#!/usr/bin/env bash # Compile the QA V1.1.73 runtime surface into stripped Cython extensions. set -euo pipefail umask 027 SOURCE_ROOT="${1:?Usage: $0 [python]}" OUTPUT_DIR="${2:?Usage: $0 [python]}" PYTHON="${3:-python3}" SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" VISIBILITY_TOOL="${ELF_VISIBILITY_TOOL:-$SCRIPT_DIR/tools/elf_visibility.py}" ENTRY_SCRIPT="scripts/qa_v1_1_73_server.py" SOURCE_ROOT="$(realpath "$SOURCE_ROOT")" OUTPUT_DIR="$(realpath -m "$OUTPUT_DIR")" [[ -d "$SOURCE_ROOT" ]] || { echo "QA source directory missing: $SOURCE_ROOT" >&2; exit 2; } [[ -x "$PYTHON" ]] || { echo "Python is not executable: $PYTHON" >&2; exit 2; } [[ -f "$VISIBILITY_TOOL" ]] || { echo "ELF visibility tool missing: $VISIBILITY_TOOL" >&2; exit 2; } for command_name in gcc strip rsync; do command -v "$command_name" >/dev/null; done case "$OUTPUT_DIR" in "/"|"$(realpath -m "$HOME")"|"$SOURCE_ROOT") echo "Unsafe output directory: $OUTPUT_DIR" >&2 exit 2 ;; esac [[ ! -e "$OUTPUT_DIR" ]] || { echo "Output already exists; refusing to overwrite: $OUTPUT_DIR" >&2 exit 2 } mkdir -p \ "$OUTPUT_DIR/scripts" \ "$OUTPUT_DIR/src/rag/qa_v1_1_73" \ "$OUTPUT_DIR/src/rag/retrieval" \ "$OUTPUT_DIR/src/rag/dual_kb_taxonomy_rag" \ "$OUTPUT_DIR/configs/rag" echo "[QA 1/6] Copying the audited runtime surface" install -m 0750 "$SOURCE_ROOT/$ENTRY_SCRIPT" "$OUTPUT_DIR/$ENTRY_SCRIPT" rsync -a --include='*/' --include='*.py' --exclude='*' \ "$SOURCE_ROOT/src/rag/qa_v1_1_73/" "$OUTPUT_DIR/src/rag/qa_v1_1_73/" rsync -a --include='*/' --include='*.py' --exclude='*' \ "$SOURCE_ROOT/src/rag/retrieval/" "$OUTPUT_DIR/src/rag/retrieval/" install -m 0640 \ "$SOURCE_ROOT/src/rag/dual_kb_taxonomy_rag/entity_alias.py" \ "$OUTPUT_DIR/src/rag/dual_kb_taxonomy_rag/entity_alias.py" # 2026-08-31 主项目新增:normalized_release.py(backend_guard 校验 + 图适配器) [[ -f "$SOURCE_ROOT/src/rag/normalized_release.py" ]] && install -m 0640 \ "$SOURCE_ROOT/src/rag/normalized_release.py" \ "$OUTPUT_DIR/src/rag/normalized_release.py" for relative in \ configs/rag/entity_alias.yaml \ configs/rag/relation_taxonomy.yaml \ configs/capabilities.yaml \ pyproject.toml \ requirements.txt \ requirements-rag.txt do if [[ -f "$SOURCE_ROOT/$relative" ]]; then install -D -m 0640 "$SOURCE_ROOT/$relative" "$OUTPUT_DIR/$relative" fi done # S6:prompts/ 目录(Superpowers SKILL.md 明文注入包) if [[ -d "$SOURCE_ROOT/prompts" ]]; then install -d -m 0750 "$OUTPUT_DIR/prompts" install -m 0640 "$SOURCE_ROOT"/prompts/*.md "$OUTPUT_DIR/prompts/" 2>/dev/null || true fi # Namespace/package markers are intentionally left as minimal Python files. touch \ "$OUTPUT_DIR/scripts/__init__.py" \ "$OUTPUT_DIR/src/__init__.py" \ "$OUTPUT_DIR/src/rag/__init__.py" \ "$OUTPUT_DIR/src/rag/dual_kb_taxonomy_rag/__init__.py" echo "[QA 2/6] Discovering Python modules" PY_FILES=() while IFS= read -r -d '' path; do PY_FILES+=("$path"); done \ < <(find "$OUTPUT_DIR" -type f -name '*.py' \ -not -path "*/$ENTRY_SCRIPT" \ -not -name '__init__.py' -print0) TOTAL="${#PY_FILES[@]}" (( TOTAL > 0 )) || { echo "No QA modules selected for compilation" >&2; exit 3; } INCLUDE_PY="$("$PYTHON" -c 'import sysconfig; print(sysconfig.get_config_var("INCLUDEPY") or "")')" EXT_SUFFIX="$("$PYTHON" -c 'import sysconfig; print(sysconfig.get_config_var("EXT_SUFFIX") or ".so")')" [[ -n "$INCLUDE_PY" ]] || { echo "Python INCLUDEPY is empty" >&2; exit 3; } echo "[QA 3/6] Cython preflight ($TOTAL modules)" COUNT=0 CYTHON_FAILURES=0 for py_file in "${PY_FILES[@]}"; do COUNT=$((COUNT + 1)) directory="$(dirname "$py_file")" module="$(basename "$py_file" .py)" c_file="$directory/$module.c" echo " [$COUNT/$TOTAL] ${py_file#"$OUTPUT_DIR"/}" if ! "$PYTHON" -m cython -3 \ --directive always_allow_keywords=true,annotation_typing=False \ --no-docstrings "$py_file" -o "$c_file"; then CYTHON_FAILURES=$((CYTHON_FAILURES + 1)) fi done (( CYTHON_FAILURES == 0 )) || { echo "QA Cython preflight failed: modules=$CYTHON_FAILURES" >&2 exit 3 } echo "[QA 4/6] GCC hidden visibility + strip ($TOTAL modules)" COUNT=0 for py_file in "${PY_FILES[@]}"; do COUNT=$((COUNT + 1)) directory="$(dirname "$py_file")" module="$(basename "$py_file" .py)" c_file="$directory/$module.c" so_file="$directory/$module$EXT_SUFFIX" echo " [$COUNT/$TOTAL] ${py_file#"$OUTPUT_DIR"/}" gcc -shared -pthread -fPIC -O2 -fvisibility=hidden \ -I"$INCLUDE_PY" -o "$so_file" "$c_file" strip --strip-unneeded "$so_file" "$PYTHON" -B "$VISIBILITY_TOOL" \ --hide-non-pyinit --check "$so_file" >/dev/null rm -f -- "$c_file" "$py_file" done echo "[QA 5/6] Restoring package markers" while IFS= read -r -d '' directory; do if find "$directory" -maxdepth 1 -type f \( -name '*.so' -o -name '*.py' \) -print -quit | grep -q .; then [[ -f "$directory/__init__.py" ]] || touch "$directory/__init__.py" fi done < <(find "$OUTPUT_DIR" -type d -print0) echo "[QA 6/6] Final checks" SO_COUNT="$(find "$OUTPUT_DIR" -type f -name '*.so' | wc -l)" [[ "$SO_COUNT" -eq "$TOTAL" ]] || { echo "QA count mismatch: selected=$TOTAL produced=$SO_COUNT" >&2 exit 4 } if find "$OUTPUT_DIR" -type f -name '*.c' -print -quit | grep -q .; then echo "Generated C source remains in output" >&2 exit 4 fi echo "QA compile+harden complete: modules=$SO_COUNT output=$OUTPUT_DIR"