chore(config): 参考 novavis 完善 Agent 配置体系
- AGENTS.md: 新增 §20 工具脚本复用 / §21 分析结论复用 / §22 Flaky 门禁,更新文档配置表
- .pi/: 新增 settings.json、rules/guardrails.md、prompts/{debug,review,ship}-gym-manage.md
- .agents/: 新增 Hook 配置与 4 个 Hook 脚本(session-start/pre-agent-check/check-completeness/stop-check)
及 protocols/systematic-debugging.md(check-completeness 含接口链缺口检测)
- scripts/flaky-scan.sh: vitest shuffle 稳定性扫描(gym-manage-web)
- .gitignore: 追踪 AGENTS.md 与 .pi 配置,忽略运行时缓存(todos/taskflows-runs/tokenomy/sessions)
This commit was merged in pull request #57.
This commit is contained in:
@@ -0,0 +1,132 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# PostToolUse hook: checks a single edited file for:
|
||||||
|
# 1. Unfinished markers (TODO/FIXME/skeleton/empty fn)
|
||||||
|
# 2. Integration chain gaps (based on file type)
|
||||||
|
# Runs after Write/Edit operations only on the modified file.
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
PROJECT_DIR="${AGENT_PROJECT_DIR:-$(pwd)}"
|
||||||
|
|
||||||
|
# Suppress during brainstorming / exploratory sessions
|
||||||
|
if [ -f "${PROJECT_DIR}/.agents/.suppress-hooks" ]; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
f="${AGENT_EDITED_FILE:-$AGENT_FILE}"
|
||||||
|
if [ ! -f "$f" ]; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
issues=()
|
||||||
|
ext="${f##*.}"
|
||||||
|
basename=$(basename "$f")
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# PART 1: Unfinished markers scan
|
||||||
|
# ============================================================
|
||||||
|
|
||||||
|
if [[ "$ext" =~ ^(ts|tsx|js|jsx|vue)$ ]]; then
|
||||||
|
while IFS=: read -r line_no content; do
|
||||||
|
[ -z "$line_no" ] && continue
|
||||||
|
trimmed=$(echo "$content" | sed 's/^[[:space:]]*//')
|
||||||
|
if echo "$trimmed" | grep -qE '^(TODO|FIXME|HACK|XXX):'; then
|
||||||
|
issues+=(" L${line_no}: TODO/FIXME ${trimmed:0:100}")
|
||||||
|
elif echo "$trimmed" | grep -qi 'not implemented' && echo "$trimmed" | grep -qi 'throw'; then
|
||||||
|
issues+=(" L${line_no}: [SKELETON] ${trimmed:0:100}")
|
||||||
|
elif echo "$trimmed" | grep -qE 'function [a-zA-Z_][a-zA-Z0-9_]*\s*\(\s*\)\s*\{\s*\}'; then
|
||||||
|
if ! echo "$trimmed" | grep -q 'return'; then
|
||||||
|
issues+=(" L${line_no}: [EMPTY FN] ${trimmed:0:100}")
|
||||||
|
fi
|
||||||
|
elif echo "$trimmed" | grep -qE 'const [a-zA-Z_][a-zA-Z0-9_]*\s*=\s*\(\)\s*=>\s*\{\s*\}'; then
|
||||||
|
issues+=(" L${line_no}: [EMPTY ARROW FN] ${trimmed:0:100}")
|
||||||
|
fi
|
||||||
|
done < <(grep -nE 'TODO:|FIXME:|HACK:|XXX:|not implemented|function [a-zA-Z_][a-zA-Z0-9_]*\s*\(\s*\)\s*\{\s*\}|const [a-zA-Z_][a-zA-Z0-9_]*\s*=\s*\(\)\s*=>\s*\{\s*\}' "$f" 2>/dev/null || true)
|
||||||
|
elif [[ "$ext" == "java" ]]; then
|
||||||
|
while IFS=: read -r line_no content; do
|
||||||
|
[ -z "$line_no" ] && continue
|
||||||
|
trimmed=$(echo "$content" | sed 's/^[[:space:]]*//')
|
||||||
|
if echo "$trimmed" | grep -qE '^(TODO|FIXME|HACK|XXX):'; then
|
||||||
|
issues+=(" L${line_no}: TODO/FIXME ${trimmed:0:100}")
|
||||||
|
elif echo "$trimmed" | grep -qE 'UnsupportedOperationException'; then
|
||||||
|
issues+=(" L${line_no}: [SKELETON] UnsupportedOperationException")
|
||||||
|
fi
|
||||||
|
done < <(grep -nE 'TODO:|FIXME:|HACK:|XXX:|UnsupportedOperationException' "$f" 2>/dev/null || true)
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# PART 2: Integration chain gap detection
|
||||||
|
# ============================================================
|
||||||
|
|
||||||
|
# Check 1: Java Controller 变更 → 提取映射路径,检查 Web/UniApp 请求层是否有引用
|
||||||
|
if [[ "$f" == *"gym-manage-api/"*.java ]] && grep -q '@RestController\|@Controller' "$f" 2>/dev/null; then
|
||||||
|
# 提取 @RequestMapping/@GetMapping/@PostMapping/@PutMapping/@DeleteMapping 的路径
|
||||||
|
paths=$(grep -oE '@(Request|Get|Post|Put|Delete)Mapping\([^)]*' "$f" 2>/dev/null \
|
||||||
|
| grep -oE '"/[^"]+"' | tr -d '"' | sort -u || true)
|
||||||
|
if [ -n "$paths" ]; then
|
||||||
|
# 与类级 @RequestMapping 前缀合并
|
||||||
|
prefix=$(grep -oE '@RequestMapping\([^)]*' "$f" 2>/dev/null | grep -oE '"/[^"]+"' | tr -d '"' | head -1 || true)
|
||||||
|
while IFS= read -r p; do
|
||||||
|
[ -z "$p" ] && continue
|
||||||
|
# 已含 /api 绝对路径的不再加类级前缀,避免双写
|
||||||
|
case "$p" in
|
||||||
|
/api/*) full="$p" ;;
|
||||||
|
*) full="${prefix}${p}" ;;
|
||||||
|
esac
|
||||||
|
# 去掉 Spring 模板变量({id} 等)用于模糊匹配
|
||||||
|
key=$(echo "$full" | sed 's/{[^}]*}//g')
|
||||||
|
[ -z "$key" ] && continue
|
||||||
|
hits=$(grep -rl -- "$key" "${PROJECT_DIR}/gym-manage-web/src/api" "${PROJECT_DIR}/gym-manage-uniapp/api" "${PROJECT_DIR}/gym-manage-coach-uniapp/api" 2>/dev/null | wc -l | tr -d ' ' || true)
|
||||||
|
if [ "$hits" -eq 0 ]; then
|
||||||
|
issues+=(" [GAP] 接口 '${full}' 在 Web/UniApp 请求层无引用(gym-manage-web/src/api、uniapp/api、coach-uniapp/api)")
|
||||||
|
fi
|
||||||
|
done <<< "$paths"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check 2: Web API 请求层变更 → 检查页面/store 有引用
|
||||||
|
if [[ "$f" == *"gym-manage-web/src/api/"*".api.ts" ]]; then
|
||||||
|
new_fns=$(grep -oE '^export (async )?function [a-zA-Z_][a-zA-Z0-9_]*|^export const [a-zA-Z_][a-zA-Z0-9_]*\s*=' "$f" 2>/dev/null \
|
||||||
|
| sed -E 's/^export (async )?function //; s/^export const //; s/[[:space:]]*=.*//' | sort -u || true)
|
||||||
|
if [ -n "$new_fns" ]; then
|
||||||
|
while IFS= read -r fn; do
|
||||||
|
[ -z "$fn" ] && continue
|
||||||
|
hits=$(grep -rl -- "\b${fn}\b" "${PROJECT_DIR}/gym-manage-web/src/views" "${PROJECT_DIR}/gym-manage-web/src/stores" "${PROJECT_DIR}/gym-manage-web/src/components" 2>/dev/null | wc -l | tr -d ' ' || true)
|
||||||
|
if [ "$hits" -eq 0 ]; then
|
||||||
|
issues+=(" [GAP] Web API '${fn}' 在 src/views|stores|components 无调用方")
|
||||||
|
fi
|
||||||
|
done <<< "$new_fns"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check 3: UniApp 请求层变更 → 检查 pages 有引用
|
||||||
|
if [[ "$f" == *"gym-manage-uniapp/api/"*.js ]] || [[ "$f" == *"gym-manage-coach-uniapp/api/"*.js ]]; then
|
||||||
|
uniapp_root="gym-manage-uniapp"
|
||||||
|
[[ "$f" == *"coach-uniapp"* ]] && uniapp_root="gym-manage-coach-uniapp"
|
||||||
|
new_fns=$(grep -oE '^export (async )?function [a-zA-Z_][a-zA-Z0-9_]*|^export const [a-zA-Z_][a-zA-Z0-9_]*\s*=' "$f" 2>/dev/null \
|
||||||
|
| sed -E 's/^export (async )?function //; s/^export const //; s/[[:space:]]*=.*//' | sort -u || true)
|
||||||
|
if [ -n "$new_fns" ]; then
|
||||||
|
while IFS= read -r fn; do
|
||||||
|
[ -z "$fn" ] && continue
|
||||||
|
hits=$(grep -rl -- "${fn}" "${PROJECT_DIR}/${uniapp_root}/pages" 2>/dev/null | wc -l | tr -d ' ' || true)
|
||||||
|
if [ "$hits" -eq 0 ]; then
|
||||||
|
issues+=(" [GAP] ${uniapp_root} API '${fn}' 在 pages/ 无调用方")
|
||||||
|
fi
|
||||||
|
done <<< "$new_fns"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# REPORT
|
||||||
|
# ============================================================
|
||||||
|
|
||||||
|
if [ ${#issues[@]} -gt 0 ]; then
|
||||||
|
echo ""
|
||||||
|
echo "[COMPLETENESS] $(basename "$f") 检查发现 ${#issues[@]} 个问题:"
|
||||||
|
for issue in "${issues[@]:0:20}"; do
|
||||||
|
echo "$issue"
|
||||||
|
done
|
||||||
|
if [ ${#issues[@]} -gt 20 ]; then
|
||||||
|
echo " ... 及其他 $((${#issues[@]} - 20)) 处"
|
||||||
|
fi
|
||||||
|
echo ""
|
||||||
|
fi
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# PreToolUse hook: 写操作前根据文件路径输出集成提醒
|
||||||
|
# 不阻止操作,仅输出提示信息
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
f="${AGENT_EDITED_FILE:-$AGENT_FILE}"
|
||||||
|
[ -z "$f" ] && exit 0
|
||||||
|
[ ! -e "$f" ] && exit 0
|
||||||
|
|
||||||
|
basename=$(basename "$f")
|
||||||
|
|
||||||
|
# 检查 1: 新建/修改 Java Controller → 提醒全链路(API → Service → Web/UniApp)
|
||||||
|
if [[ "$f" == *"gym-manage-api/"*.java ]]; then
|
||||||
|
if grep -q '@RestController\|@Controller' "$f" 2>/dev/null; then
|
||||||
|
echo ""
|
||||||
|
echo "[PRE-CHECK] 修改 Java Controller: $basename"
|
||||||
|
echo " → 全链路要求(AGENTS.md §13/§14):"
|
||||||
|
echo " 1) Service 层实现业务逻辑(Controller 不直连 Repository)"
|
||||||
|
echo " 2) 同步 gym-manage-web/src/api/*.api.ts(请求路径/参数/类型)"
|
||||||
|
echo " 3) 同步 gym-manage-uniapp/api/*.js 与 coach-uniapp/api/*.js"
|
||||||
|
echo " 4) Swagger 注解齐全(@ApiOperation/@ApiModelProperty)"
|
||||||
|
echo ""
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
# 仅 Service/其它 Java 文件:提醒写单测
|
||||||
|
echo ""
|
||||||
|
echo "[PRE-CHECK] 修改后端 Java: $basename"
|
||||||
|
echo " → 业务逻辑改动需配套 JUnit 测试(cd gym-manage-api && mvn test -pl <模块> -am)"
|
||||||
|
echo ""
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 检查 2: 修改 Web 请求层 → 提醒同步类型与页面
|
||||||
|
if [[ "$f" == *"gym-manage-web/src/api/"*".api.ts" ]]; then
|
||||||
|
echo ""
|
||||||
|
echo "[PRE-CHECK] Web API 接口变更: $basename"
|
||||||
|
echo " → 同步更新:"
|
||||||
|
echo " 1) 接口路径/参数与后端 Controller 注解一致"
|
||||||
|
echo " 2) 类型定义与后端 DTO/VO 字段对齐(camelCase)"
|
||||||
|
echo " 3) 页面调用方(src/views、src/stores)使用新签名"
|
||||||
|
echo ""
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 检查 3: 修改 UniApp 请求层 → 提醒同步
|
||||||
|
if [[ "$f" == *"gym-manage-uniapp/api/"*.js ]] || [[ "$f" == *"gym-manage-coach-uniapp/api/"*.js ]]; then
|
||||||
|
echo ""
|
||||||
|
echo "[PRE-CHECK] UniApp API 变更: $basename"
|
||||||
|
echo " → 同步更新: 页面调用方(pages/*)+ 后端接口契约 + Web 端同名接口"
|
||||||
|
echo ""
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 检查 4: 新建/修改测试文件 → 提醒 flaky 门禁
|
||||||
|
if [[ "$f" == *".test."* ]] || [[ "$f" == *".spec."* ]] || [[ "$f" == *"Test.java" ]]; then
|
||||||
|
echo ""
|
||||||
|
echo "[PRE-CHECK] 测试文件: $basename"
|
||||||
|
echo " → Web 测试(vitest)需通过 bash scripts/flaky-scan.sh --spec <文件> --runs 3(AGENTS.md §22)"
|
||||||
|
echo ""
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# SessionStart hook: 启动时输出项目关键上下文和集成提醒
|
||||||
|
# 不阻止会话启动,仅输出提示信息
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
PROJECT_DIR="${AGENT_PROJECT_DIR:-$(pwd)}"
|
||||||
|
cd "$PROJECT_DIR"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||||
|
echo " Gym Manage — 项目上下文"
|
||||||
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||||
|
|
||||||
|
# 当前分支
|
||||||
|
BRANCH=$(git branch --show-current 2>/dev/null || echo "未知")
|
||||||
|
echo " 分支: $BRANCH"
|
||||||
|
|
||||||
|
# 变更文件统计
|
||||||
|
STAGED=$(git diff --cached --name-only 2>/dev/null | wc -l | tr -d ' ')
|
||||||
|
UNSTAGED=$(git diff --name-only 2>/dev/null | wc -l | tr -d ' ')
|
||||||
|
echo " 变更: ${STAGED} 个暂存, ${UNSTAGED} 个未暂存"
|
||||||
|
|
||||||
|
# 检测关键文件变更
|
||||||
|
CHANGED_FILES=$(git diff --name-only HEAD 2>/dev/null; git diff --cached --name-only 2>/dev/null; git ls-files --others --exclude-standard 2>/dev/null | sort -u)
|
||||||
|
HAS_API_CHANGE=""
|
||||||
|
HAS_WEB_API_CHANGE=""
|
||||||
|
HAS_UNIAPP_CHANGE=""
|
||||||
|
|
||||||
|
while IFS= read -r f; do
|
||||||
|
[ -z "$f" ] && continue
|
||||||
|
case "$f" in
|
||||||
|
gym-manage-api/*.java) HAS_API_CHANGE="yes" ;;
|
||||||
|
gym-manage-web/src/api/*.api.ts) HAS_WEB_API_CHANGE="yes" ;;
|
||||||
|
gym-manage-uniapp/api/*.js|gym-manage-coach-uniapp/api/*.js) HAS_UNIAPP_CHANGE="yes" ;;
|
||||||
|
esac
|
||||||
|
done <<< "$CHANGED_FILES"
|
||||||
|
|
||||||
|
# 集成提醒
|
||||||
|
if [ -n "$HAS_API_CHANGE" ] || [ -n "$HAS_WEB_API_CHANGE" ] || [ -n "$HAS_UNIAPP_CHANGE" ]; then
|
||||||
|
echo ""
|
||||||
|
echo " ⚠️ 检测到接口相关文件变更,请确保全链路完整性:"
|
||||||
|
echo ""
|
||||||
|
echo " ┌─ Layer 1: Java Controller(gym-manage-api)─────────────┐"
|
||||||
|
echo " │ @RestController / @RequestMapping / Service 层 │"
|
||||||
|
echo " ├─ Layer 2: Web 请求层 ──────────────────────────────────┤"
|
||||||
|
echo " │ gym-manage-web/src/api/*.api.ts(请求路径/参数/类型) │"
|
||||||
|
echo " ├─ Layer 3: UniApp 请求层 ───────────────────────────────┤"
|
||||||
|
echo " │ gym-manage-uniapp/api/*.js + coach-uniapp/api/*.js │"
|
||||||
|
echo " ├─ Layer 4: 页面/组件 ───────────────────────────────────┤"
|
||||||
|
echo " │ gym-manage-web/src/views/* + uniapp pages/* │"
|
||||||
|
echo " └─ Layer 5: 测试验证 ────────────────────────────────────┘"
|
||||||
|
echo " mvn test(后端)+ pnpm test(Web)+ flaky-scan(§22)"
|
||||||
|
echo ""
|
||||||
|
echo " 详细清单: AGENT.md(架构/命令/端口)+ AGENTS.md §13/§17"
|
||||||
|
echo ""
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||||
|
echo ""
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Stop hook: runs quick quality checks and outputs JSON result.
|
||||||
|
# 轻量检查(<15s),不编译后端 — 重型检查留给 pre-push 和 CI。
|
||||||
|
# 残留扫描由 check-completeness.sh(PostToolUse)按文件处理,此处不重复。
|
||||||
|
# Outputs diagnostic info to stderr, final JSON status to stdout.
|
||||||
|
set -euo pipefail
|
||||||
|
cd "${AGENT_PROJECT_DIR:-$(pwd)}"
|
||||||
|
|
||||||
|
# Suppress during brainstorming / exploratory sessions
|
||||||
|
if [ -f ".agents/.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/2: 变更文件残留扫描(未完成标记 + 调试遗留)----
|
||||||
|
echo '[1/2] 变更文件残留扫描...'
|
||||||
|
CHANGED=$( { git diff --name-only HEAD 2>/dev/null; git diff --cached --name-only 2>/dev/null; } | sort -u )
|
||||||
|
LEFTOVERS=""
|
||||||
|
while IFS= read -r f; do
|
||||||
|
[ -z "$f" ] && continue
|
||||||
|
[ -f "$f" ] || continue
|
||||||
|
case "$f" in
|
||||||
|
gym-manage-web/src/*|gym-manage-uniapp/**|gym-manage-coach-uniapp/**|*.java|*.ts|*.tsx|*.js|*.vue)
|
||||||
|
if grep -nE '\.only\(|\.skip\(' "$f" 2>/dev/null | grep -qE '\.(only|skip)\('; then
|
||||||
|
LEFTOVERS="${LEFTOVERS} [LEFTOVER] ${f}: .only()/.skip() 残留\n"
|
||||||
|
fi
|
||||||
|
if grep -nE 'console\.log' "$f" 2>/dev/null | grep -qv 'console\.log(`' 2>/dev/null; then
|
||||||
|
LEFTOVERS="${LEFTOVERS} [LEFTOVER] ${f}: console.log 残留\n"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done <<< "$CHANGED"
|
||||||
|
|
||||||
|
if [ -n "$LEFTOVERS" ]; then
|
||||||
|
printf '%b' "$LEFTOVERS"
|
||||||
|
echo " ⚠️ 存在调试/测试残留(未阻断,提交前请清理)"
|
||||||
|
else
|
||||||
|
echo ' 残留扫描: PASS'
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ---- 2/2: 未提交任务状态检查 ----
|
||||||
|
echo '[2/2] 任务状态检查...'
|
||||||
|
if [ -d ".pi/todos" ]; then
|
||||||
|
OPEN=$(ls .pi/todos/*.md 2>/dev/null | wc -l | tr -d ' ')
|
||||||
|
echo " 打开的任务: ${OPEN}(如需关闭请使用 todo 工具或手动更新)"
|
||||||
|
else
|
||||||
|
echo ' 任务目录: 不存在'
|
||||||
|
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
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
# 系统化调试协议(Systematic Debugging)
|
||||||
|
|
||||||
|
> 通用规则见 `AGENTS.md` §15(系统调试优先:先定位根因再修复,禁止"试试看")。
|
||||||
|
|
||||||
|
## 适用范围
|
||||||
|
本项目任何层级的 Bug:后端 Java(gym-manage-api)、Gateway 路由、Web 前端(gym-manage-web)、
|
||||||
|
UniApp 小程序(gym-manage-uniapp / gym-manage-coach-uniapp)、数据库(PostgreSQL:55432)。
|
||||||
|
|
||||||
|
## 协议步骤
|
||||||
|
|
||||||
|
### Step 1 — 复现确认
|
||||||
|
- 拿到最小复现步骤:单测试 / 单操作 / 单输入
|
||||||
|
- 区分环境:本地 Dev(Web:3002)、Docker(`docker-compose logs -f backend/frontend/postgres`)、
|
||||||
|
微信开发者工具(小程序,`urlCheck: false` 已关闭 URL 校验)
|
||||||
|
|
||||||
|
### Step 2 — 分层隔离
|
||||||
|
| 层级 | 排查入口 | 快速验证 |
|
||||||
|
|------|----------|---------|
|
||||||
|
| 后端 Java | Gateway/App 控制台日志(DEBUG 输出 stdout) | `cd gym-manage-api && mvn compile` |
|
||||||
|
| Gateway 路由 | `/api/**` → 8084 转发日志 | `docker-compose logs -f gateway` |
|
||||||
|
| 数据库 | SQL / 数据不一致 | `psql -U novalon -d manage_system -p 55432` |
|
||||||
|
| Web 前端 | DevTools Console + Network | `cd gym-manage-web && pnpm test` |
|
||||||
|
| UniApp | 微信开发者工具控制台 | jest(`gym-manage-uniapp`) |
|
||||||
|
|
||||||
|
按上表顺序定位,**一次只换一个变量**。
|
||||||
|
|
||||||
|
### Step 3 — 假设驱动
|
||||||
|
- 对每个假设写下一行验证方法,先验证最可能/最便宜的假设
|
||||||
|
- Java 逻辑:加 SLF4J DEBUG 日志或补单测缩小范围
|
||||||
|
- 接口联调:用 Swagger(`:8084/swagger-ui.html`)直调接口确认后端,再查前端参数
|
||||||
|
- UI:Vue DevTools 组件树 + Network 请求/响应比对
|
||||||
|
|
||||||
|
### Step 4 — 检查最近变更
|
||||||
|
```bash
|
||||||
|
git diff --name-only HEAD~5 # 最近 5 次提交变更
|
||||||
|
git log --oneline -10 # 最近 10 条提交
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 5 — 运行受影响测试
|
||||||
|
```bash
|
||||||
|
cd gym-manage-api && mvn test -pl <受影响模块> -am # 后端
|
||||||
|
cd gym-manage-web && pnpm test # Web 前端
|
||||||
|
cd gym-manage-web && pnpm test:e2e # Web E2E
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 6 — 确认根因后才提修复方案
|
||||||
|
- 记录完整复现路径与根因证据
|
||||||
|
- 修复后走完整验证:受影响单测 + 类型检查(`vue-tsc`)+ 真实后端联调
|
||||||
|
- **Mock 通过 ≠ 功能可用**(AGENTS.md §13)——需真实后端验证
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
{
|
||||||
|
"_comment": "Generic agent hook configuration. Environment variable AGENT_PROJECT_DIR should be set by the host agent to the project root. If unavailable, hooks fall back to pwd.",
|
||||||
|
"hooks": {
|
||||||
|
"SessionStart": [
|
||||||
|
{
|
||||||
|
"hooks": [
|
||||||
|
{
|
||||||
|
"type": "command",
|
||||||
|
"command": "bash \"${AGENT_PROJECT_DIR}/.agents/hooks/session-start.sh\"",
|
||||||
|
"timeout": 10000
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"PreToolUse": [
|
||||||
|
{
|
||||||
|
"matcher": "Write|Edit",
|
||||||
|
"hooks": [
|
||||||
|
{
|
||||||
|
"type": "command",
|
||||||
|
"command": "bash \"${AGENT_PROJECT_DIR}/.agents/hooks/pre-agent-check.sh\"",
|
||||||
|
"timeout": 3000
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"PostToolUse": [
|
||||||
|
{
|
||||||
|
"matcher": "Write|Edit",
|
||||||
|
"hooks": [
|
||||||
|
{
|
||||||
|
"type": "command",
|
||||||
|
"command": "bash \"${AGENT_PROJECT_DIR}/.agents/hooks/check-completeness.sh\"",
|
||||||
|
"timeout": 5000
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Stop": [
|
||||||
|
{
|
||||||
|
"hooks": [
|
||||||
|
{
|
||||||
|
"type": "command",
|
||||||
|
"command": "bash \"${AGENT_PROJECT_DIR}/.agents/hooks/stop-check.sh\"",
|
||||||
|
"timeout": 30000
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
+9
-2
@@ -154,8 +154,15 @@ docs/superpowers/*
|
|||||||
# .trae
|
# .trae
|
||||||
.trae/
|
.trae/
|
||||||
|
|
||||||
# agent
|
# Agent 行为规则与配置(参考 novavis 模式:AGENTS.md / .agents 入库)
|
||||||
AGENTS.md
|
# .pi 配置文件(settings.json / rules / prompts)入库,运行时缓存忽略
|
||||||
|
.pi/todos/
|
||||||
|
.pi/taskflows/runs/
|
||||||
|
.pi/tokenomy-cache/
|
||||||
|
.pi/tokenomy-stats.json
|
||||||
|
sessions/
|
||||||
|
.agents/.suppress-hooks
|
||||||
|
.agents/skills/
|
||||||
|
|
||||||
# dogfood
|
# dogfood
|
||||||
dogfood-output/
|
dogfood-output/
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
---
|
||||||
|
description: 健身房管理系统专用系统调试 — 跨 Java API + Vue3 Web + UniApp 小程序排查
|
||||||
|
---
|
||||||
|
Gym Manage(SpringBoot 多模块后端 + Vue3 管理后台 + UniApp 双小程序)系统化调试协议:
|
||||||
|
|
||||||
|
## 1. 复现确认
|
||||||
|
- 确认最小复现步骤(单测试 / 单操作 / 单输入)
|
||||||
|
- 区分环境:本地 Dev(`pnpm dev`,端口 3002)vs Docker(`docker-compose logs -f backend/frontend/postgres`)vs 微信开发者工具(小程序)
|
||||||
|
|
||||||
|
## 2. 分层隔离
|
||||||
|
按以下顺序定位故障层:
|
||||||
|
|
||||||
|
| 层级 | 检查点 | 快速验证 |
|
||||||
|
|------|--------|---------|
|
||||||
|
| 后端 Java | Controller / Service / Mapper、参数校验、异常处理 | `cd gym-manage-api && mvn compile` / `mvn test` |
|
||||||
|
| Gateway 路由 | `/api/**` → 8084 转发、CORS、鉴权过滤器 | Gateway 控制台日志 |
|
||||||
|
| Web 前端 | `gym-manage-web/src/api/*.api.ts` 请求层、views 组件、store | `cd gym-manage-web && pnpm test` / 浏览器 DevTools Network |
|
||||||
|
| UniApp 小程序 | `gym-manage-uniapp/api/*.js`、pages 页面 | 微信开发者工具控制台(`urlCheck: false` 已关闭) |
|
||||||
|
| 数据库 | SQL 错误、数据不一致 | `psql -U novalon -d manage_system -p 55432` |
|
||||||
|
|
||||||
|
## 3. 二分排查
|
||||||
|
- 对 Java 逻辑:加日志(SLF4J DEBUG)或单测缩小范围
|
||||||
|
- 对接口联调:用 Swagger(`:8084/swagger-ui.html`)直接调接口,确认后端返回 → 再查前端请求参数
|
||||||
|
- 对 UI:Vue DevTools 组件树 + Network 标签比对请求/响应
|
||||||
|
|
||||||
|
## 4. 检查最近变更
|
||||||
|
```bash
|
||||||
|
git diff --name-only HEAD~5 # 最近 5 次提交变更
|
||||||
|
git log --oneline -10 # 最近 10 条提交
|
||||||
|
```
|
||||||
|
|
||||||
|
## 5. 运行受影响测试
|
||||||
|
```bash
|
||||||
|
cd gym-manage-api && mvn test -pl <受影响模块> -am # 后端
|
||||||
|
cd gym-manage-web && pnpm test # Web 前端
|
||||||
|
cd gym-manage-web && pnpm test:e2e # Web E2E(Playwright)
|
||||||
|
```
|
||||||
|
|
||||||
|
## 6. 确认根因后才提修复方案
|
||||||
|
- 记录完整的复现路径与根因证据
|
||||||
|
- 修复后走完整验证:受影响单测 + 类型检查(`vue-tsc`)+ 真实后端联调(Mock 通过 ≠ 功能可用,见 AGENTS.md §13)
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
---
|
||||||
|
description: 健身房管理系统全链路集成审查 — API → Service → Web 组件 / UniApp 页面 → 测试 → CI
|
||||||
|
---
|
||||||
|
Gym Manage 项目专用集成审查,覆盖全链路:
|
||||||
|
|
||||||
|
## 全链路检查清单
|
||||||
|
|
||||||
|
### 1. 后端 Java
|
||||||
|
- `cd gym-manage-api && mvn compile` — 编译检查
|
||||||
|
- `cd gym-manage-api && mvn test` — 单元+集成测试(JUnit 5)
|
||||||
|
- Controller → Service → Mapper 分层清晰,无 Controller 直连 Repository
|
||||||
|
- DTO/VO 与实体分离,响应结构统一(code/message/data)
|
||||||
|
|
||||||
|
### 2. 接口契约
|
||||||
|
- Web 端 `gym-manage-web/src/api/*.api.ts` 请求路径/方法/参数与 Java Controller 注解一致
|
||||||
|
- UniApp 端 `gym-manage-uniapp/api/*.js`、`gym-manage-coach-uniapp/api/*.js` 同步一致
|
||||||
|
- 新增接口已登记(Swagger 注解齐全:`@ApiOperation`/`@ApiModelProperty`)
|
||||||
|
|
||||||
|
### 3. Web 前端
|
||||||
|
- `cd gym-manage-web && pnpm exec vue-tsc --noEmit` — 类型检查
|
||||||
|
- `cd gym-manage-web && pnpm lint` — lint
|
||||||
|
- 组件通过 `src/api/*.api.ts` 取数,无直接裸 `fetch`/`axios` 绕过
|
||||||
|
- store(pinia)状态变更向后兼容;类型与后端 DTO 无漂移
|
||||||
|
|
||||||
|
### 4. UniApp 小程序
|
||||||
|
- 会员端 / 教练端页面通过 `api/*.js` 取数,请求封装(`utils/request.js`)一致
|
||||||
|
- 页面展示字段与接口返回字段对齐(camelCase ↔ 后端命名)
|
||||||
|
|
||||||
|
### 5. 测试覆盖
|
||||||
|
- 后端:`mvn test` 覆盖新增 Service 核心分支 + 边界
|
||||||
|
- Web:`pnpm test`(vitest)覆盖组件关键行为;新增测试通过 `bash scripts/flaky-scan.sh --spec <文件> --runs 3`
|
||||||
|
- 检查 `.only()` / `.skip()` / `console.log` 等调试遗留
|
||||||
|
|
||||||
|
### 6. CI 门禁
|
||||||
|
- `cd gym-manage-web && pnpm build` — 生产构建通过
|
||||||
|
- Jenkins pipeline(Jenkinsfile)兼容性;根目录 `run-all-tests.ps1` 可本地全量回归
|
||||||
|
|
||||||
|
## 报告格式
|
||||||
|
输出简洁表格:层、状态(✅/❌/⚠️)、发现的问题
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
---
|
||||||
|
description: 健身房管理系统专属质量门禁与发布流程 — 构建→测试→提交→推送
|
||||||
|
---
|
||||||
|
Gym Manage 项目质量门禁和提交发布流程:
|
||||||
|
|
||||||
|
## 质量门禁(按顺序执行)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Step 1: 后端编译 + 测试(受影响模块)
|
||||||
|
cd gym-manage-api && mvn test -pl <受影响模块> -am
|
||||||
|
|
||||||
|
# Step 2: Web 前端类型检查 + 单元测试
|
||||||
|
cd gym-manage-web && pnpm exec vue-tsc --noEmit
|
||||||
|
cd gym-manage-web && pnpm test
|
||||||
|
|
||||||
|
# Step 3: Web E2E(涉及页面交互时)
|
||||||
|
cd gym-manage-web && pnpm test:e2e
|
||||||
|
|
||||||
|
# Step 4: 新增/修改测试的 flaky 门禁(P1,AGENTS.md §22)
|
||||||
|
bash scripts/flaky-scan.sh --spec <新文件> --runs 3
|
||||||
|
|
||||||
|
# Step 5: 构建验证
|
||||||
|
cd gym-manage-web && pnpm build
|
||||||
|
```
|
||||||
|
|
||||||
|
## Git 操作规范
|
||||||
|
|
||||||
|
### 提交信息格式
|
||||||
|
```
|
||||||
|
类型(范围): 中文描述
|
||||||
|
|
||||||
|
- 类型: feat / fix / refactor / test / docs / chore / perf / style
|
||||||
|
- 范围: api / web / uniapp / coach / config / ci / deps
|
||||||
|
```
|
||||||
|
|
||||||
|
### 提交前检查
|
||||||
|
- 无 `// TODO` / `// FIXME` / `console.log` 残留
|
||||||
|
- 无空函数体或 `throw new UnsupportedOperationException()` 等骨架占位
|
||||||
|
- 无 `.only()` / `.skip()` 在测试中
|
||||||
|
- 已从两个独立信源交叉验证(AGENTS.md §7)
|
||||||
|
|
||||||
|
### 推送前检查
|
||||||
|
- Jenkins CI pipeline 兼容性(`Jenkinsfile` 在 root)
|
||||||
|
- 全链路打通(API → Service → Web/UniApp,AGENTS.md §13)——Mock 通过 ≠ 功能可用,需真实后端验证
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
# Gym Manage Pi Agent Guardrails
|
||||||
|
|
||||||
|
AGENTS.md 通用规则的 Pi Agent 专项补充,由 pi-agent-suite/project-rules 扩展加载。
|
||||||
|
|
||||||
|
## 文件操作边界
|
||||||
|
- 禁止修改或删除 `.pi/`、`.agents/` 目录下任何配置文件和脚本,除非用户明确要求
|
||||||
|
- 禁止修改 `gym-manage-api/**/application*.yml` / `application*.properties` 中的数据库口令等敏感配置,除非用户明确要求
|
||||||
|
- 数据库 `manage_system`(PostgreSQL:55432)结构变更(DDL)前,须先确认影响范围并同步更新文档
|
||||||
|
- 禁止修改或删除 `dogfood-output/`、`test-results/`、`playwright-report/` 等测试产出目录内容(只读)
|
||||||
|
|
||||||
|
## 依赖管理
|
||||||
|
- 禁止在未获用户明确批准的情况下添加/升级/删除任何 Maven 依赖(`gym-manage-api/pom.xml` 及各模块 `pom.xml`)或 npm/pnpm 依赖
|
||||||
|
- `pom.xml`、`package.json`、`pnpm-lock.yaml`、`package-lock.json` 的修改须经用户确认
|
||||||
|
|
||||||
|
## 构建安全
|
||||||
|
- 禁止运行 `mvn clean` / `rm -rf target/` / `rm -rf node_modules/` 等清理构建缓存的命令,除非用户明确要求
|
||||||
|
- 构建失败时,先诊断根因,禁止"试试看"式的反复修改
|
||||||
|
|
||||||
|
## 环境变量
|
||||||
|
- 禁止修改、覆盖、或取消设置 HOME 环境变量
|
||||||
|
- `.env*` 文件为只读,禁止修改
|
||||||
|
|
||||||
|
## Git 操作
|
||||||
|
- 禁止运行 `git push`、`git reset --hard`、`git clean -fd`、`git branch -D` 等破坏性命令
|
||||||
|
- `git commit` 须经用户确认
|
||||||
|
|
||||||
|
## 测试命令退出码保留
|
||||||
|
- 测试命令必须是整条 bash 命令的**最后一个命令**,禁止在后面追加任何后处理(`grep`、`head`、`wc -l`、`echo`、`tee` 等,无论是否有用)
|
||||||
|
- 唯一例外是以下模式,且必须严格按模板书写:
|
||||||
|
```bash
|
||||||
|
test_cmd > /tmp/output.txt 2>&1; EXIT=$?
|
||||||
|
# 后处理(只读,不修改 EXIT)
|
||||||
|
wc -l /tmp/output.txt
|
||||||
|
grep ... /tmp/output.txt | head -30
|
||||||
|
exit $EXIT
|
||||||
|
```
|
||||||
|
- 管道场景使用 `set -o pipefail` 确保任一命令失败时整体退出码非零
|
||||||
|
- 重定向顺序必须是 `> file 2>&1`,不能是 `2>&1 > file`
|
||||||
|
|
||||||
|
## 端口与服务
|
||||||
|
- Gateway: 8080(路由 `/api/**` → 8084);App: 8084(Swagger: `http://localhost:8084/swagger-ui.html`);Web Dev: 3002;PostgreSQL: 55432;Redis: 6379
|
||||||
|
- 数据库直连查询用 `psql -U novalon -d manage_system -p 55432`
|
||||||
|
- 启动/停止本地环境优先使用 `scripts/start-all.sh` / `scripts/stop-test-env.sh`,不手工起停容器
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"prompts": ["prompts"],
|
||||||
|
"compaction": {
|
||||||
|
"enabled": true,
|
||||||
|
"reserveTokens": 16384,
|
||||||
|
"keepRecentTokens": 40000
|
||||||
|
},
|
||||||
|
"sessionDir": "sessions",
|
||||||
|
"quietStartup": false,
|
||||||
|
"defaultThinkingLevel": "high",
|
||||||
|
"sourceCodeFilteringEnabled": true,
|
||||||
|
"sourceCodeFilteringLevel": "minimal",
|
||||||
|
"smartTruncationEnabled": true,
|
||||||
|
"smartTruncationMaxLines": 150,
|
||||||
|
"terminal": {
|
||||||
|
"showTerminalProgress": true
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,178 @@
|
|||||||
|
# 全局 Agent 规则
|
||||||
|
|
||||||
|
本文件用于约束自动化代理在本机工作区中的默认工作方式,并将 Superpowers 作为主工作流体系按需激活。
|
||||||
|
|
||||||
|
## 指令优先级
|
||||||
|
|
||||||
|
- 默认以 **Superpowers** 作为主工作流体系,但不默认启用 full Superpowers。
|
||||||
|
- 只读分析任务可不进入完整实现流程,但结论必须清晰、可追溯。
|
||||||
|
- 若用户明确要求 `continue nonstop`,默认持续推进,直到满足验收标准或出现真实阻塞。
|
||||||
|
- `AGENT.md` — 项目架构、命令、测试策略的主要参考
|
||||||
|
- `CONTEXT.md` — 领域术语表与业务上下文
|
||||||
|
- 本文件约束通用 Agent 行为模式。当 AGENTS.md 与 AGENT.md 冲突时,AGENTS.md 优先
|
||||||
|
|
||||||
|
## 核心原则
|
||||||
|
|
||||||
|
### §1 任务分解优先
|
||||||
|
- 任何需 3 步以上的工作,先创建任务列表再实施
|
||||||
|
- 开始任务标记 `in_progress`,完成标记 `completed`
|
||||||
|
- 停止前检查所有任务状态,无遗留 `pending`/`in_progress`
|
||||||
|
|
||||||
|
### §2 最短路径与流程升降级
|
||||||
|
- **默认以 Superpowers 作为主工作流体系**,但不默认启用 full Superpowers
|
||||||
|
- **默认实现方法**:TDD(RED→GREEN→REFACTOR)。能通过 TDD 完成的,不升级为更重流程
|
||||||
|
- 默认采用"满足质量要求的最短路径"
|
||||||
|
- 能直接完成并验证的,不升级为更重流程
|
||||||
|
- 能用轻量 planning 解决的小任务,不升级为重文档流程
|
||||||
|
- 能用单一专项 skill 解决的问题,不扩展为 full Superpowers
|
||||||
|
- **升级条件**:边界超出判断、涉及公共 API/schema/持久化/并发/共享逻辑、需求不清晰
|
||||||
|
- **降级条件**:仅限用户批准的极简单变更(文档、配置、拼写错误)
|
||||||
|
|
||||||
|
### §3 技能优先使用
|
||||||
|
- 执行任务前先检查可用 skills;若存在匹配 skill,通过 Skill 工具调用
|
||||||
|
- 禁止绕过已有 skill 手工实现
|
||||||
|
- 能用单一 skill 完成的事项,不使用 Agent 或 Workflow 重实现
|
||||||
|
|
||||||
|
### §4 编码质量(Karpathy Guidelines)
|
||||||
|
在编写、审查或重构代码时,遵循以下原则:
|
||||||
|
1. **编码前先思考** — 明确假设,不隐藏困惑,展示权衡
|
||||||
|
2. **简单优先** — 只写解决问题的最小代码,拒绝过度抽象
|
||||||
|
3. **精准修改** — 只触碰必须修改的部分,不"改进"相邻代码
|
||||||
|
4. **目标驱动执行** — 定义可验证的成功标准,循环直到验证通过
|
||||||
|
|
||||||
|
### §5 逐步推理
|
||||||
|
1. 先澄清再实现,先缩小边界再扩展范围
|
||||||
|
2. 涉及第三方库/框架时,优先用 `context7` 查询官方文档
|
||||||
|
3. 优先局部修改与最小充分实现
|
||||||
|
4. 复杂度上升时升级流程,收敛时降级
|
||||||
|
|
||||||
|
### §6 零缺陷交付
|
||||||
|
- **严守三不**:绝不延期、绝不出错、绝不超计划
|
||||||
|
- **禁止凭空制造**:代码/API/数据结构必须有可信来源支撑
|
||||||
|
- 所有产出物(代码/文档)必须逻辑严谨、可验证、无歧义错误
|
||||||
|
|
||||||
|
### §7 多源交叉验证
|
||||||
|
- 实现前从至少**两个独立可信源**比对求证,消除理解偏差
|
||||||
|
- 两个信源矛盾时以官方/权威文档为准
|
||||||
|
- 变更影响评估:修改前评估对关联模块的影响,并同步更新相关文档
|
||||||
|
|
||||||
|
### §8 双轨验证
|
||||||
|
任务完成后:
|
||||||
|
1. **功能验证**(测试/边界条件/异常路径)
|
||||||
|
2. **溯源验证**(对照可信信源)
|
||||||
|
|
||||||
|
### §9 循环控制
|
||||||
|
连续两步实质性重复、引用同一信源无新信息、结论已在上一轮已知结论集中 → **立即终止**并输出已确认的稳定结论
|
||||||
|
|
||||||
|
### §10 变更影响评估
|
||||||
|
修改前评估关联模块:数据模型→适配器/测试;API→调用方;配置→各环境
|
||||||
|
|
||||||
|
### §11 无骨架占位
|
||||||
|
- 禁止:`throw 'not implemented'`、空函数体、`// TODO`/`// FIXME`、无返回值函数
|
||||||
|
- 完成前验证:TDD 合规检查 → 类型检查 → 自我审查 → 集成验证
|
||||||
|
|
||||||
|
### §12 诚实地报告不完整性
|
||||||
|
不能完成时明确告知:已完成部分、未完成部分及原因、后续步骤
|
||||||
|
|
||||||
|
### §13 全链路集成验证(P0 强制)
|
||||||
|
**每个新功能必须打通完整链路**:API 接口 → Service 层 → Web 前端组件 / UniApp 页面
|
||||||
|
|
||||||
|
- ❌ 后端实现但前端无调用链 / 前端组件无后端数据源 / 类型漂移
|
||||||
|
- ❌ Mock 通过 ≠ 功能可用(需要通过真实后端验证)
|
||||||
|
- 详见 `AGENT.md` 工作流说明
|
||||||
|
|
||||||
|
### §14 任务拆分即包含集成
|
||||||
|
"后端 API → 前端页面/组件 → 小程序页面"是同一个 Task,禁止拆成后端/前端两个独立 Task(轻量修复除外)
|
||||||
|
|
||||||
|
### §15 系统调试优先
|
||||||
|
遇到 bug 先定位根因再修复,禁止"试试看"。完成根源调查前不得提修复方案。
|
||||||
|
|
||||||
|
### §16 中文文档与注释规范
|
||||||
|
业务逻辑/领域知识注释优先用中文。变量名/函数名/类名始终用英文。技术术语保留英文不翻译。
|
||||||
|
|
||||||
|
### §17 完整性命门(Completeness Gate)
|
||||||
|
功能完成前必须通过完整性验证,确保无遗漏接口、无未连接的调用链、无类型漂移。
|
||||||
|
|
||||||
|
### §18 测试编写流程
|
||||||
|
1. 阅读/Code Review 业务代码 → 理解组件实际行为
|
||||||
|
2. 识别测试需要覆盖的关键行为点
|
||||||
|
3. 编写精确断言,匹配业务代码的实际渲染输出
|
||||||
|
4. 运行测试验证
|
||||||
|
|
||||||
|
### §19 测试命令退出码保留(P0 强制)
|
||||||
|
- 测试命令必须是整条 bash 命令的**最后一个命令**,禁止在后面追加任何后处理(`grep`、`head`、`wc -l`、`echo`、`tee` 等,无论是否有用)
|
||||||
|
- 唯一例外是以下模式,且必须严格按模板书写:
|
||||||
|
```bash
|
||||||
|
test_cmd > /tmp/output.txt 2>&1; EXIT=$?
|
||||||
|
# 后处理(只读,不修改 EXIT)
|
||||||
|
wc -l /tmp/output.txt
|
||||||
|
grep ... /tmp/output.txt | head -30
|
||||||
|
exit $EXIT
|
||||||
|
```
|
||||||
|
- 管道场景使用 `set -o pipefail` 确保任一命令失败时整体退出码非零
|
||||||
|
- 重定向顺序必须是 `> file 2>&1`,不能是 `2>&1 > file`
|
||||||
|
|
||||||
|
### §20 工具脚本可复用优先(P0 强制)
|
||||||
|
**禁止生成一次性(one-off)内联脚本。任何需要重复执行的命令、分析、转换逻辑,必须固化为 `scripts/` 下的持久化工具脚本。**
|
||||||
|
|
||||||
|
- ❌ 禁止:每次在 bash 中内联 Python/Node/awk 脚本做一次性分析(接口扫描、测试报告解析、JSON 提取等),用完即丢
|
||||||
|
- ✅ 允许:将逻辑写入 `scripts/*.py` / `scripts/*.sh` / `scripts/*.mjs`(带参数、帮助信息、可重复执行),后续通过 `bash scripts/xxx.sh --args` 复用
|
||||||
|
- ✅ 已有工具先查 `scripts/` 是否已存在:`scripts/run-tests.sh`、`scripts/start-all.sh`、`scripts/collect-test-metrics.py`、`scripts/flaky-scan.sh` 等
|
||||||
|
- 内联 `python3 -c "..."` 仅允许用于不超过 3 行的极简调试输出
|
||||||
|
- 新工具脚本必须:① 放到 `scripts/` ② 支持 `--help` 或头部注释说明用法 ③ 可带参数运行 ④ 不硬编码具体文件路径(接受参数或从项目根推导)
|
||||||
|
|
||||||
|
### §21 分析结论复用,避免重复调查(P0 强制)
|
||||||
|
- 同一类分析(覆盖率、接口映射、测试报告)优先复用已有脚本与文档,不重新编写一次性脚本
|
||||||
|
- 已在 `docs/reports/`、`docs/plans/`、`docs/framework/` 中记录的任务状态/结论,先读取再继续,不重复调查
|
||||||
|
- 测试命令与服务端口以 `AGENT.md` 为准;领域术语以 `CONTEXT.md` 为准;已有结论以 `docs/reports/` 为准
|
||||||
|
|
||||||
|
### §22 Flaky 测试门禁(P1 强制)
|
||||||
|
- 新增/修改前端测试(`gym-manage-web`,vitest)后,必须通过 `bash scripts/flaky-scan.sh --spec <文件> --runs 3` 验证**顺序无关性**
|
||||||
|
- **存在 flaky 时禁止合并**:全量 `bash scripts/flaky-scan.sh --runs 1` 失败(shuffle 下任何测试失败)即阻断合并,须先定位根因修复
|
||||||
|
- 常见 flaky 根因(Vitest 环境):
|
||||||
|
① `vi.clearAllMocks()` 不清除 `mockResolvedValue/mockRejectedValue` 实现 → beforeEach 须显式恢复默认实现
|
||||||
|
② store/pinia 单例跨测试残留 → beforeEach 须重置全部字段
|
||||||
|
③ 模块级可变 `let` mock 变量被测试修改未还原
|
||||||
|
④ `vi.stubGlobal` 全局替换(URL/Notification/FileReader 等)未在 afterEach 恢复
|
||||||
|
⑤ 异步测试缺少 `await flushPromises()`/`waitFor`(被空渲染掩盖的隐藏缺陷)
|
||||||
|
- 新增测试文件必须通过 `bash scripts/flaky-scan.sh --spec <新文件> --runs 3`
|
||||||
|
|
||||||
|
## 默认原则
|
||||||
|
|
||||||
|
### 轻量任务默认策略(Codex / Superpowers)
|
||||||
|
- 轻量任务:单文件或小范围修改、明确 bug 修复、配置 / 文案调整、小测试补充、局部文档修改。
|
||||||
|
- 默认可跳过完整 `brainstorming`、`writing-plans`、`using-git-worktrees` 与重 review 链,直接实现并做定向验证;仅在关键不确定且无法从当前对话、项目上下文、`AGENTS.md`、现有代码回答时才提问。
|
||||||
|
- 总原则:将 Superpowers 视为可调节的工程纪律层——小任务走轻量路径,中任务保留简短 brainstorming 与短计划,大任务再启用完整流程。
|
||||||
|
|
||||||
|
### 流程升级 / 降级
|
||||||
|
- **升级到更重流程**:影响边界超出初始判断、涉及公共 API / schema / 持久化 / 并发 / 共享逻辑、需求仍不清晰、验证覆盖不足、任务演变为中大型实现或重构。
|
||||||
|
- **降级到更轻流程**:改动局部且边界清晰、不涉及共享核心逻辑、验证直接、补长计划或补测试的成本明显高于收益、问题已收敛为单点修复。
|
||||||
|
|
||||||
|
## 文档与配置
|
||||||
|
|
||||||
|
| 文件 | 内容 |
|
||||||
|
|------|------|
|
||||||
|
| `AGENTS.md` | 通用行为规则(本文件) |
|
||||||
|
| `AGENT.md` | 项目架构、命令、测试策略、服务工作端口 |
|
||||||
|
| `CONTEXT.md` | 领域术语表 / 业务上下文 |
|
||||||
|
| `.pi/settings.json` | 项目级 Pi 配置 |
|
||||||
|
| `.pi/rules/guardrails.md` | Pi Agent 安全边界(文件/依赖/构建/Git) |
|
||||||
|
| `.pi/prompts/` | 项目专用调试 / 审查 / 发布提示词 |
|
||||||
|
| `.agents/settings.json` | 项目级 Hook 配置 |
|
||||||
|
| `.agents/hooks/` | Hook 脚本(session-start / pre-agent-check / check-completeness / stop-check) |
|
||||||
|
| `.agents/protocols/` | 调试与测试分析协议 |
|
||||||
|
| `.agents/skills/` | 自定义 Skills(feature-completeness-gate / systematic-debugging 等) |
|
||||||
|
| `docs/superpowers/specs/` | 需求共识 spec 与 PRD 文档 |
|
||||||
|
| `docs/superpowers/plans/` | 可执行任务计划 |
|
||||||
|
| `docs/superpowers/guides/` | 最佳实践指南 |
|
||||||
|
| `docs/adr/` | 架构决策记录 |
|
||||||
|
| `docs/architecture/` | 架构文档 |
|
||||||
|
| `README.md` | 项目概览、快速开始 |
|
||||||
|
|
||||||
|
## 问题升级路径
|
||||||
|
|
||||||
|
1. **自查比对**:检查代码逻辑与测试用例,定位明显错误
|
||||||
|
2. **第一信源查证**:使用 `context7` 获取官方/权威文档说明
|
||||||
|
3. **第二信源佐证**:搜索额外独立来源进行比对印证
|
||||||
|
4. **实证测试**:编写最小化验证代码,用实际运行结果终结争议
|
||||||
|
5. **仍无法解决**:明确告知用户已完成部分、卡点及所需支持
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# ============================================================
|
||||||
|
# flaky-scan.sh — Vitest 全量 shuffle 稳定性扫描(AGENTS.md §22)
|
||||||
|
#
|
||||||
|
# 用 --sequence.shuffle 打乱文件与测试执行顺序,暴露顺序依赖型
|
||||||
|
# flaky(共享 store 状态 / mock 实现污染 / 全局 stub 残留等)。
|
||||||
|
# 目标项目: gym-manage-web(vitest)。通过 --project 可切换。
|
||||||
|
#
|
||||||
|
# 用法:
|
||||||
|
# bash scripts/flaky-scan.sh # gym-manage-web 全量 shuffle 1 次
|
||||||
|
# bash scripts/flaky-scan.sh --runs 3 # 全量 shuffle 3 次
|
||||||
|
# bash scripts/flaky-scan.sh --spec <file> # 单文件多次 shuffle
|
||||||
|
# bash scripts/flaky-scan.sh --project uniapp # gym-manage-uniapp(jest,无 shuffle)
|
||||||
|
# bash scripts/flaky-scan.sh --help
|
||||||
|
#
|
||||||
|
# 退出码: 0 = 全部通过;1 = 存在失败(flaky 或顺序依赖 bug)
|
||||||
|
# 失败详情保留在 /tmp/flaky-scan-*.log 供根因定位
|
||||||
|
# ============================================================
|
||||||
|
|
||||||
|
set -uo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||||
|
PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
|
||||||
|
RUNS=1
|
||||||
|
SPEC=""
|
||||||
|
PROJECT="web"
|
||||||
|
SHUFFLE="--sequence.shuffle"
|
||||||
|
|
||||||
|
NEXT=""
|
||||||
|
for arg in "$@"; do
|
||||||
|
case "$arg" in
|
||||||
|
--runs=*) RUNS="${arg#--runs=}" ;;
|
||||||
|
--spec=*) SPEC="${arg#--spec=}" ;;
|
||||||
|
--project=*) PROJECT="${arg#--project=}" ;;
|
||||||
|
--runs|--spec|--project) NEXT="$arg" ;;
|
||||||
|
--no-shuffle) SHUFFLE="" ;;
|
||||||
|
--help|-h)
|
||||||
|
sed -n '2,16p' "$0" | sed 's/^# \{0,1\}//'
|
||||||
|
exit 0 ;;
|
||||||
|
*)
|
||||||
|
if [ -n "$NEXT" ]; then
|
||||||
|
case "$NEXT" in
|
||||||
|
--runs) RUNS="$arg" ;;
|
||||||
|
--spec) SPEC="$arg" ;;
|
||||||
|
--project) PROJECT="$arg" ;;
|
||||||
|
esac
|
||||||
|
NEXT=""
|
||||||
|
else
|
||||||
|
echo "未知参数: ${arg}(--help 查看用法)" >&2
|
||||||
|
exit 2
|
||||||
|
fi ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
case "$PROJECT" in
|
||||||
|
web) SUB_PROJ="gym-manage-web" ;;
|
||||||
|
uniapp|coach) SUB_PROJ="gym-manage-${PROJECT}" ;;
|
||||||
|
*) echo "未知项目: ${PROJECT}(web | uniapp | coach)" >&2; exit 2 ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
[ -d "${PROJECT_DIR}/${SUB_PROJ}" ] || { echo "子项目不存在: ${SUB_PROJ}" >&2; exit 2; }
|
||||||
|
|
||||||
|
echo "============================================"
|
||||||
|
echo " Gym Manage Flaky 稳定性扫描"
|
||||||
|
echo " 项目: ${SUB_PROJ}"
|
||||||
|
echo " 模式: ${SHUFFLE:-无 shuffle} × $RUNS 次${SPEC:+ (${SPEC})}"
|
||||||
|
echo "============================================"
|
||||||
|
|
||||||
|
FAILED=0
|
||||||
|
for i in $(seq 1 "$RUNS"); do
|
||||||
|
LOG="/tmp/flaky-scan-$i.log"
|
||||||
|
if [ -n "$SPEC" ]; then
|
||||||
|
(cd "${PROJECT_DIR}/${SUB_PROJ}" && NODE_ENV=test npx vitest run $SHUFFLE "$SPEC" > "$LOG" 2>&1)
|
||||||
|
else
|
||||||
|
(cd "${PROJECT_DIR}/${SUB_PROJ}" && NODE_ENV=test npx vitest run $SHUFFLE > "$LOG" 2>&1)
|
||||||
|
fi
|
||||||
|
EXIT=$?
|
||||||
|
SUMMARY=$(grep -E "Tests " "$LOG" | tail -1)
|
||||||
|
if [ "$EXIT" -eq 0 ]; then
|
||||||
|
echo "run $i/$RUNS: ✅ $SUMMARY"
|
||||||
|
else
|
||||||
|
echo "run $i/$RUNS: ❌ exit=$EXIT $SUMMARY"
|
||||||
|
grep -E "^ FAIL" "$LOG" | head -10
|
||||||
|
FAILED=1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "--------------------------------------------"
|
||||||
|
if [ "$FAILED" -eq 0 ]; then
|
||||||
|
echo " 扫描通过:${RUNS} 次运行 0 flaky ✅"
|
||||||
|
exit 0
|
||||||
|
else
|
||||||
|
echo " 发现 flaky/顺序依赖(详见 /tmp/flaky-scan-*.log) ❌"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
Reference in New Issue
Block a user