#!/usr/bin/env bash set -euo pipefail ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" CLIENT_DIR="$ROOT_DIR/client" SERVER_DIR="$ROOT_DIR/server" ISSUE_CSV="$ROOT_DIR/issues/2026-05-07_12-34-21-r105-pretrial-readiness-automation.csv" ISSUE_VALIDATOR="/home/shunli/.codex/skills/plan/scripts/validate_issues_csv.py" PUBLIC_BASE_URL="${LIVE_SMOKE_BASE_URL:-https://oa.hyinda.com}" MODE="static" usage() { cat </dev/null 2>&1 || { echo "[pretrial][FAIL] 缺少命令: $1" >&2 exit 1 } } has_live_smoke_credentials() { [[ -n "${LIVE_SMOKE_ADMIN_IDENTIFIER:-}" ]] && [[ -n "${LIVE_SMOKE_ADMIN_PASSWORD:-}" ]] && [[ -n "${LIVE_SMOKE_EMPLOYEE_IDENTIFIER:-}" ]] && [[ -n "${LIVE_SMOKE_EMPLOYEE_PASSWORD:-}" ]] } has_live_ocr_credentials() { if [[ -n "${PLAYWRIGHT_OCR_LIVE_IDENTIFIER:-}" && -n "${PLAYWRIGHT_OCR_LIVE_PASSWORD:-}" ]]; then return 0 fi [[ -n "${LIVE_SMOKE_EMPLOYEE_IDENTIFIER:-}" ]] && [[ -n "${LIVE_SMOKE_EMPLOYEE_PASSWORD:-}" ]] } run_static() { require_cmd python3 require_cmd node require_cmd npm echo ">>> [pretrial] CSV 校验" python3 "$ISSUE_VALIDATOR" "$ISSUE_CSV" echo ">>> [pretrial] 部署契约校验" node "$ROOT_DIR/deploy/trialrun/validate-env-contract.js" echo ">>> [pretrial] Prisma schema 校验" ( cd "$SERVER_DIR" npm run prisma:validate ) echo ">>> [pretrial] smoke 数据审计脚本语法" ( cd "$SERVER_DIR" node --check src/scripts/audit-smoke-data.js node src/scripts/audit-smoke-data.js --help >/dev/null ) if [[ -n "${DATABASE_URL:-}" ]]; then echo ">>> [pretrial] smoke 数据足迹只读审计" ( cd "$SERVER_DIR" npm run audit:smoke-data -- --format=text ) else echo ">>> [pretrial] 跳过 smoke 数据足迹审计:当前 shell 未设置 DATABASE_URL" fi echo ">>> [pretrial] UI 设计规则" node "$ROOT_DIR/scripts/qa/check-ui-design-rules.mjs" echo ">>> [pretrial] client typecheck" ( cd "$CLIENT_DIR" npm run typecheck ) } run_live_smoke() { require_cmd curl require_cmd node require_cmd npm if ! has_live_smoke_credentials; then echo ">>> [pretrial] 跳过 live smoke:缺少完整 LIVE_SMOKE_* 凭据" return 0 fi echo ">>> [pretrial] live smoke: ${PUBLIC_BASE_URL}" LIVE_SMOKE_BASE_URL="$PUBLIC_BASE_URL" bash "$ROOT_DIR/scripts/qa/run-web-gates.sh" smoke-live } run_visual() { require_cmd node require_cmd npm if ! has_live_smoke_credentials; then echo ">>> [pretrial] 跳过 R105 视觉自动化:缺少完整 LIVE_SMOKE_* 凭据" return 0 fi echo ">>> [pretrial] R105 公网视觉自动化: ${PUBLIC_BASE_URL}" ( cd "$CLIENT_DIR" LIVE_SMOKE_BASE_URL="$PUBLIC_BASE_URL" \ E2E_MODE=live \ npx playwright test tests/e2e/r105-pretrial-visual.spec.ts --reporter=list ) } run_ocr() { require_cmd node require_cmd npm if [[ -z "${PLAYWRIGHT_OCR_LIVE_FILE:-}" ]]; then echo ">>> [pretrial] 跳过真实 OCR:未设置 PLAYWRIGHT_OCR_LIVE_FILE" return 0 fi if [[ ! -f "$PLAYWRIGHT_OCR_LIVE_FILE" ]]; then echo ">>> [pretrial] 跳过真实 OCR:文件不存在 ${PLAYWRIGHT_OCR_LIVE_FILE}" return 0 fi if ! has_live_ocr_credentials; then echo ">>> [pretrial] 跳过真实 OCR:缺少 smoke 员工凭据" return 0 fi echo ">>> [pretrial] 真实 OCR 辅助复核: ${PUBLIC_BASE_URL}" ( cd "$CLIENT_DIR" PLAYWRIGHT_MANUAL=1 \ PLAYWRIGHT_OCR_LIVE=1 \ PLAYWRIGHT_OCR_ALLOW_DUPLICATE=1 \ E2E_BASE_URL="$PUBLIC_BASE_URL" \ npx playwright test tests/e2e/manual/live-invoice-ocr.spec.ts --workers=1 --reporter=list ) } if [[ "$#" -eq 0 ]]; then MODE="static" elif [[ "$#" -eq 1 ]]; then case "$1" in --help|-h) usage exit 0 ;; --static) MODE="static" ;; --live-smoke) MODE="live-smoke" ;; --visual) MODE="visual" ;; --ocr) MODE="ocr" ;; --all) MODE="all" ;; *) usage >&2 exit 1 ;; esac else usage >&2 exit 1 fi case "$MODE" in static) run_static ;; live-smoke) run_live_smoke ;; visual) run_visual ;; ocr) run_ocr ;; all) run_static run_live_smoke run_visual run_ocr ;; esac echo "[pretrial][PASS] mode=${MODE}"