新增 AGENTS.md 规则(§1-§22)、Hook 脚本和可复用工具脚本: - 重构 AGENTS.md:新增 16 条规则(任务分解、双轨验证、骨架占位禁止、 测试命令退出码保留、工具脚本可复用、完成前验证门禁、Flaky 测试门禁等) - 新增 .trae/hooks/:session-start / pre-agent-check / check-completeness / stop-check - 新增 .trae/settings.json:关联 4 个 Hook 到 SessionStart/PreToolUse/PostToolUse/Stop - 新增 scripts/:flaky-scan.sh / check-task-checklist.sh / check-issue-checklist.sh - 调整 .gitignore:保留 hooks/settings 纳入版本控制,忽略运行时状态文件
87 lines
2.6 KiB
Bash
87 lines
2.6 KiB
Bash
#!/usr/bin/env bash
|
||
# Stop hook: runs quick quality checks and outputs JSON result.
|
||
# 轻量检查(<10s)
|
||
# 残留扫描由 check-completeness.sh(PostToolUse)按文件处理,此处不重复。
|
||
set -euo pipefail
|
||
|
||
cd "${AGENT_PROJECT_DIR:-$(pwd)}"
|
||
|
||
# Suppress during brainstorming / exploratory sessions
|
||
if [ -f ".trae/.suppress-hooks" ]; then
|
||
echo '{"status":"ok","mode":"suppressed"}'
|
||
exit 0
|
||
fi
|
||
|
||
HAS_ERRORS=0
|
||
|
||
# All diagnostics go to stderr
|
||
{
|
||
echo '=== [STOP HOOK QUALITY GATE] ==='
|
||
|
||
# ---- 1/3: TypeScript type check ----
|
||
echo '[1/3] TypeScript 类型检查...'
|
||
APP_DIR="everything-is-suitable-uniapp"
|
||
if [ -f "${APP_DIR}/node_modules/.bin/tsc" ]; then
|
||
if (cd "${APP_DIR}" && npx tsc --noEmit --pretty false 2>&1); then
|
||
echo ' tsc: PASS'
|
||
else
|
||
echo ' tsc: FAIL'
|
||
HAS_ERRORS=1
|
||
fi
|
||
else
|
||
echo ' tsc: SKIP(未安装依赖,运行 npm install)'
|
||
fi
|
||
|
||
# ---- 2/3: TODO/FIXME 残留扫描 ----
|
||
echo '[2/3] 代码残留扫描(TODO/FIXME/skeleton)...'
|
||
FOUND=$(grep -rn 'TODO:\|FIXME:\|not implemented.*throw' "${APP_DIR}/src" --include='*.ts' --include='*.vue' --include='*.js' 2>/dev/null | grep -v 'node_modules' | grep -v '.test.' | head -10 || true)
|
||
if [ -z "$FOUND" ]; then
|
||
echo ' 残留扫描: PASS'
|
||
else
|
||
echo ' 残留扫描: 发现以下残留标记:'
|
||
echo "$FOUND"
|
||
HAS_ERRORS=1
|
||
fi
|
||
|
||
# ---- 3/3: 测试文件完整性检查 ----
|
||
echo '[3/3] 测试文件一致性检查...'
|
||
# 检查 src 中每个 .ts/.vue 文件是否有关联测试文件
|
||
ORPHANED=0
|
||
while IFS= read -r src_file; do
|
||
[ -z "$src_file" ] && continue
|
||
base=$(basename "$src_file" .ts)
|
||
base=$(basename "$base" .vue)
|
||
dir=$(dirname "$src_file")
|
||
test_file="${dir}/__tests__/${base}.test.ts"
|
||
if [ ! -f "$test_file" ]; then
|
||
# 跳过 index.vue 等特殊文件
|
||
case "$base" in
|
||
index|main|App) continue ;;
|
||
esac
|
||
# 跳过类型定义文件
|
||
case "$src_file" in
|
||
*/types/*) continue ;;
|
||
esac
|
||
ORPHANED=$((ORPHANED + 1))
|
||
fi
|
||
done < <(find "${APP_DIR}/src" -name '*.ts' -o -name '*.vue' 2>/dev/null | head -100)
|
||
if [ "$ORPHANED" -eq 0 ]; then
|
||
echo ' 测试文件一致性: PASS'
|
||
else
|
||
echo " 测试文件一致性: ${ORPHANED} 个源文件缺少关联测试(仅供参考,非强制)"
|
||
fi
|
||
|
||
# ---- Summary ----
|
||
if [ "$HAS_ERRORS" -eq 0 ]; then
|
||
echo '=== [STOP HOOK: ALL PASS] ==='
|
||
else
|
||
echo '=== [STOP HOOK: ERRORS FOUND] ==='
|
||
fi
|
||
} >&2
|
||
|
||
# Output final status as JSON
|
||
if [ "$HAS_ERRORS" -eq 0 ]; then
|
||
echo '{"status":"ok"}'
|
||
else
|
||
echo '{"status":"error"}'
|
||
fi |