Files
wenzi/scripts/prd_review_cycle.sh

157 lines
5.2 KiB
Bash
Raw Permalink Normal View History

#!/usr/bin/env bash
set -euo pipefail
PROJECT_DIR="/home/long/project/蚊子"
REPORT_DIR="$PROJECT_DIR/logs/prd-review"
RUN_LOG="$PROJECT_DIR/logs/prd_review_cycle.log"
LOCK_FILE="/tmp/mosquito_prd_review_cycle.lock"
PID_FILE="$PROJECT_DIR/logs/prd-review/cycle.pid"
FORCE_RERUN="${FORCE_RERUN:-0}"
STALE_SECONDS="${STALE_SECONDS:-10800}"
CLAUDE_BIN="$HOME/.cursor/extensions/anthropic.claude-code-2.1.15-linux-x64/resources/native-binary/claude"
EVIDENCE_CHECK_SCRIPT="$PROJECT_DIR/scripts/verify_review_evidence.sh"
# cron环境下PATH通常不完整显式补齐nvm/codex
export HOME="${HOME:-/home/long}"
export NVM_DIR="${NVM_DIR:-$HOME/.nvm}"
export PATH="$HOME/.local/bin:$HOME/bin:/usr/local/bin:/usr/bin:/bin:$PATH"
if ! command -v codex >/dev/null 2>&1; then
if [ -s "$NVM_DIR/nvm.sh" ]; then
# shellcheck disable=SC1090
. "$NVM_DIR/nvm.sh" >/dev/null 2>&1 || true
nvm use --silent 20 >/dev/null 2>&1 || true
nvm use --silent default >/dev/null 2>&1 || true
fi
fi
CODEX_BIN="$(command -v codex || true)"
if [ -z "$CODEX_BIN" ] && [ -x "$HOME/.nvm/versions/node/v20.19.0/bin/codex" ]; then
CODEX_BIN="$HOME/.nvm/versions/node/v20.19.0/bin/codex"
fi
mkdir -p "$REPORT_DIR" "$PROJECT_DIR/logs"
if [ -f "$PID_FILE" ]; then
prev_pid="$(cat "$PID_FILE" 2>/dev/null || true)"
if [ -n "${prev_pid:-}" ] && kill -0 "$prev_pid" 2>/dev/null; then
now_ts=$(date +%s)
pid_age=$((now_ts - $(stat -c %Y "$PID_FILE" 2>/dev/null || echo "$now_ts")))
if [ "$FORCE_RERUN" = "1" ] || [ "$pid_age" -gt "$STALE_SECONDS" ]; then
echo "[$(date '+%F %T')] force/stale rerun: killing previous pid=$prev_pid age=${pid_age}s" >> "$RUN_LOG"
kill "$prev_pid" 2>/dev/null || true
sleep 2
fi
fi
fi
exec 9>"$LOCK_FILE"
if ! flock -n 9; then
echo "[$(date '+%F %T')] skip: previous cycle still running" >> "$RUN_LOG"
exit 0
fi
echo $$ > "$PID_FILE"
trap 'rm -f "$PID_FILE"' EXIT
cd "$PROJECT_DIR"
TIMESTAMP="$(date '+%Y%m%d_%H%M%S')"
REPORT_FILE="$REPORT_DIR/review_${TIMESTAMP}.md"
LATEST_REPORT="$REPORT_DIR/latest_review.md"
CLAUDE_SUMMARY="$REPORT_DIR/claude_apply_${TIMESTAMP}.md"
PRD_FILES=()
for f in "$PROJECT_DIR/docs/PRD.md" "$PROJECT_DIR/docs/prd"/*.md; do
if [ -f "$f" ]; then
PRD_FILES+=("$f")
fi
done
if [ ${#PRD_FILES[@]} -eq 0 ]; then
echo "[$(date '+%F %T')] error: no PRD files found" >> "$RUN_LOG"
exit 1
fi
PRD_LIST=$(printf '%s\n' "${PRD_FILES[@]}")
CODEX_PROMPT=$(cat <<EOF
你是严格的项目评审官。请在仓库 $PROJECT_DIR 执行全面review并以 PRD 为基准进行差距分析。
PRD文件如下
$PRD_LIST
输出要求中文Markdown
1. 总体结论是否满足最新PRD
2. PRD事项对照矩阵事项/当前状态/证据文件路径/优先级)
3. 未完成清单P0/P1/P2
4. 给Claude可直接执行的优化任务清单按顺序包含具体文件与验收标准
5. 建议执行命令构建、测试、e2e
请务必面向“可执行落地”,不要空泛建议。
EOF
)
if [ -z "$CODEX_BIN" ]; then
echo "[$(date '+%F %T')] error: codex binary not found (PATH=$PATH)" >> "$RUN_LOG"
exit 1
fi
echo "[$(date '+%F %T')] cycle start: generating codex report with $CODEX_BIN" >> "$RUN_LOG"
"$CODEX_BIN" exec \
--cd "$PROJECT_DIR" \
--dangerously-bypass-approvals-and-sandbox \
--output-last-message "$REPORT_FILE" \
"$CODEX_PROMPT" >> "$RUN_LOG" 2>&1
if [ ! -s "$REPORT_FILE" ]; then
echo "[$(date '+%F %T')] error: codex report is empty: $REPORT_FILE" >> "$RUN_LOG"
exit 1
fi
cp -f "$REPORT_FILE" "$LATEST_REPORT"
echo "[$(date '+%F %T')] codex report ready: $REPORT_FILE" >> "$RUN_LOG"
CLAUDE_PROMPT=$(cat <<EOF
请读取并执行该评审报告中的优化任务:
$REPORT_FILE
要求:
1) 按优先级执行修复优先完成P0/P1
2) 可以直接修改代码并运行必要命令(含后端测试、前端测试、端到端测试)
3) 若修复后仍有失败,继续迭代直到通过或给出明确阻塞原因
4) 输出最终摘要执行命令、修改文件、测试结果、剩余未完成PRD项
5) 必须输出“证据矩阵”,每条包含:命令 | 退出码 | 原始日志路径 | 结果结论
6) 所有结论都要附可追溯日志路径(如 logs/*.log、target/surefire-reports/*.xml
若无法提供可追溯证据,必须明确写“证据不足-本轮无效”。
请直接开始执行,不要只给计划。
EOF
)
echo "[$(date '+%F %T')] cycle continue: running claude apply" >> "$RUN_LOG"
"$CLAUDE_BIN" -p \
--permission-mode dontAsk \
--dangerously-skip-permissions \
"$CLAUDE_PROMPT" > "$CLAUDE_SUMMARY" 2>> "$RUN_LOG"
if [ ! -s "$CLAUDE_SUMMARY" ]; then
echo "[$(date '+%F %T')] error: claude summary is empty: $CLAUDE_SUMMARY" >> "$RUN_LOG"
exit 1
fi
if [ -x "$EVIDENCE_CHECK_SCRIPT" ]; then
if "$EVIDENCE_CHECK_SCRIPT" "$CLAUDE_SUMMARY" "$PROJECT_DIR" >> "$RUN_LOG" 2>&1; then
echo "[$(date '+%F %T')] evidence gate pass" >> "$RUN_LOG"
else
echo "[$(date '+%F %T')] error: evidence gate failed, mark cycle invalid" >> "$RUN_LOG"
exit 1
fi
else
echo "[$(date '+%F %T')] warn: evidence checker missing: $EVIDENCE_CHECK_SCRIPT" >> "$RUN_LOG"
exit 1
fi
echo "[$(date '+%F %T')] cycle done: $CLAUDE_SUMMARY" >> "$RUN_LOG"