Commit 9e8db6d8d15bb2b1df65f96c92c62c21107ef2b5

Authored by yanghl
1 parent bbc8907e

feat(hooks): Stop 钩子自动续跑编码流程 + 去除 A 类人工停点

为实现「coding 阶段后端+前端连跑、无需手敲 continue」:

- 新增 Stop 钩子 auto-continue.sh:回合中途结束自动续跑;命中
  [ERP-HALT] 终止标记或连续空转上限/transcript 无增长时才放行停下,
  自包含防循环(PostToolUse reset-stall-counter.sh 辅助清零)。
- 给所有真终止/硬护栏停点打 [ERP-HALT]:coding-start / test-gate /
  feature-tdd / fe-feature-tdd / module-start / module-report /
  frontend-start / interrupt-check / db-init / downstream-gen。
  审阅停(scope-lock D、db-design-gen E)不打标记 → 钩子自动跨过。
- 删 A 类确认弹窗:scope-lock 技术栈检查、skeleton-gen .env 核对 →
  自动放行。
- feature/fe-feature 的 spec/plan 覆盖确认 → 直接覆盖(CC 内部产物)。

注:钩子在会话启动时加载,已运行的会话需重启才生效。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
hooks/hooks.json
... ... @@ -6,6 +6,19 @@
6 6 "hooks": [
7 7 { "type": "command", "command": "\"${CLAUDE_PLUGIN_ROOT}\"/hooks/scripts/log-cross-module.sh" }
8 8 ]
  9 + },
  10 + {
  11 + "matcher": "",
  12 + "hooks": [
  13 + { "type": "command", "command": "\"${CLAUDE_PLUGIN_ROOT}\"/hooks/scripts/reset-stall-counter.sh" }
  14 + ]
  15 + }
  16 + ],
  17 + "Stop": [
  18 + {
  19 + "hooks": [
  20 + { "type": "command", "command": "\"${CLAUDE_PLUGIN_ROOT}\"/hooks/scripts/auto-continue.sh" }
  21 + ]
9 22 }
10 23 ]
11 24 }
... ...
hooks/scripts/auto-continue.sh 0 → 100755
  1 +#!/usr/bin/env bash
  2 +# Stop 钩子:让 ERP workflow 在回合中途结束时自动续跑,除非命中「终止标记」或「防循环上限」。
  3 +#
  4 +# 设计:
  5 +# 1. 终止标记 [ERP-HALT] —— 终止/硬护栏 skill(coding-start 全部完成、test-gate 红、
  6 +# feature-tdd 路径护栏、interrupt-check 中断)会打印它。出现即放行停下。
  7 +# 2. 防循环 —— 连续「无工具调用」的空转停止累加计数;达到上限放行停下。
  8 +# 正常推进时由 PostToolUse 的 reset-stall-counter.sh 清零,故真流程不受限。
  9 +# 3. 否则 —— block 并喂一句「继续推进」指令,用户无需手敲 continue。
  10 +set -u
  11 +
  12 +INPUT="$(cat)"
  13 +
  14 +SENTINEL='[ERP-HALT]'
  15 +MAX_STALL=8
  16 +
  17 +# —— 从 stdin JSON 取字段(不依赖 jq)——
  18 +get_str() {
  19 + printf '%s' "$INPUT" \
  20 + | sed -n "s/.*\"$1\"[[:space:]]*:[[:space:]]*\"\([^\"]*\)\".*/\1/p" \
  21 + | head -n1
  22 +}
  23 +TRANSCRIPT="$(get_str transcript_path)"
  24 +# 反转义 Windows 路径里的 \\ 与 \/
  25 +TRANSCRIPT="${TRANSCRIPT//\\\\//}"
  26 +TRANSCRIPT="${TRANSCRIPT//\\//}"
  27 +
  28 +# 计数器文件(按会话 transcript 路径派生 key,避免多会话互相干扰)
  29 +KEY="$(printf '%s' "$TRANSCRIPT" | tr -cd 'A-Za-z0-9' | tail -c 40)"
  30 +[ -z "$KEY" ] && KEY="default"
  31 +CNT_FILE="${TMPDIR:-/tmp}/erp-autocont-$KEY"
  32 +SIZE_FILE="${TMPDIR:-/tmp}/erp-autosize-$KEY"
  33 +
  34 +allow_stop() { rm -f "$CNT_FILE" "$SIZE_FILE" 2>/dev/null; exit 0; }
  35 +
  36 +# 1) 终止标记出现在最近的 transcript 尾部 → 放行停下
  37 +if [ -n "$TRANSCRIPT" ] && [ -f "$TRANSCRIPT" ]; then
  38 + if tail -c 16000 "$TRANSCRIPT" 2>/dev/null | grep -qF "$SENTINEL"; then
  39 + allow_stop
  40 + fi
  41 +fi
  42 +
  43 +# 2) 进展自复位(自包含,不依赖 PostToolUse):transcript 自上次停止以来显著增长
  44 +# → 说明这一轮做了实质工作(工具调用 + 结果),清零空转计数。
  45 +CUR_SIZE=0
  46 +[ -n "$TRANSCRIPT" ] && [ -f "$TRANSCRIPT" ] && CUR_SIZE="$(wc -c < "$TRANSCRIPT" 2>/dev/null | tr -d ' ')"
  47 +case "$CUR_SIZE" in (''|*[!0-9]*) CUR_SIZE=0 ;; esac
  48 +LAST_SIZE=0
  49 +[ -f "$SIZE_FILE" ] && LAST_SIZE="$(cat "$SIZE_FILE" 2>/dev/null || echo 0)"
  50 +case "$LAST_SIZE" in (''|*[!0-9]*) LAST_SIZE=0 ;; esac
  51 +echo "$CUR_SIZE" > "$SIZE_FILE"
  52 +if [ $((CUR_SIZE - LAST_SIZE)) -gt 4000 ]; then
  53 + rm -f "$CNT_FILE" 2>/dev/null
  54 +fi
  55 +
  56 +# 3) 防循环:连续空转停止达到上限 → 放行停下
  57 +CNT=0
  58 +[ -f "$CNT_FILE" ] && CNT="$(cat "$CNT_FILE" 2>/dev/null || echo 0)"
  59 +case "$CNT" in (''|*[!0-9]*) CNT=0 ;; esac
  60 +if [ "$CNT" -ge "$MAX_STALL" ]; then
  61 + allow_stop
  62 +fi
  63 +echo $((CNT + 1)) > "$CNT_FILE"
  64 +
  65 +# 3) 拦下停止 → 续跑
  66 +printf '%s' '{"decision":"block","reason":"继续推进 ERP workflow:直接执行流程的下一步——若当前 skill 已结束,立即用 Skill 工具调用对应派发器(A 阶段 plan-start / B 阶段 coding-start)或链中的下一个 skill;不要输出收尾叙述、不要停下等用户输入。只有打印了 [ERP-HALT] 的终止/硬护栏点才应停下。"}'
  67 +exit 0
... ...
hooks/scripts/reset-stall-counter.sh 0 → 100755
  1 +#!/usr/bin/env bash
  2 +# PostToolUse 钩子:任何工具调用都视为「有进展」,清零 auto-continue.sh 的空转计数。
  3 +# 这样真正在推进的流程可无限续跑,只有「连续多次纯文字、零工具」的空转才会触发防循环上限。
  4 +set -u
  5 +
  6 +INPUT="$(cat)"
  7 +TRANSCRIPT="$(printf '%s' "$INPUT" \
  8 + | sed -n 's/.*"transcript_path"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' \
  9 + | head -n1)"
  10 +TRANSCRIPT="${TRANSCRIPT//\\\\//}"
  11 +TRANSCRIPT="${TRANSCRIPT//\\//}"
  12 +
  13 +KEY="$(printf '%s' "$TRANSCRIPT" | tr -cd 'A-Za-z0-9' | tail -c 40)"
  14 +[ -z "$KEY" ] && KEY="default"
  15 +rm -f "${TMPDIR:-/tmp}/erp-autocont-$KEY" 2>/dev/null
  16 +exit 0
... ...
skills/coding/fe-feature-brainstorm/SKILL.md
... ... @@ -55,7 +55,7 @@ allowed-tools: Read Write Skill AskUserQuestion Glob Grep
55 55 - 消费的后端端点(与 docs/05 对齐,按本 FE 的 `associated_reqs[]` 过滤)
56 56 - 业务规则前端复刻清单(逐条,每条标注:规则描述 / 触发时机 / 报错文案 / 来源 REQ)
57 57 - Design Tokens 引用清单(本 FE 用到的 `var(--color-*)` 名称)
58   - - 文件已存在 → 征求用户确认后覆盖
  58 + - 文件已存在 → 直接覆盖(spec 是 CC 内部产物,无需确认)
59 59  
60 60 4. **Spec 自审**(inline 修,无须用户等待):
61 61 - 所有顶级节非空
... ...
skills/coding/fe-feature-plan/SKILL.md
... ... @@ -56,7 +56,7 @@ allowed-tools: Read Write Grep Skill AskUserQuestion
56 56  
57 57 5. **写 plan 到 `docs/superpowers/plans/<YYYY-MM-DD>-<fe_id>.md`**:
58 58 - 按 `${CLAUDE_SKILL_DIR}/templates/fe-feature-plan-template.md` 渲染
59   - - 文件已存在 → 征求用户确认后覆盖
  59 + - 文件已存在 → 直接覆盖(plan 是 CC 内部产物,无需确认)
60 60  
61 61 6. **Plan 自审**(inline 修,无须用户等待):
62 62 - 每个任务必须含 `test_file::test_name`、`impl_file`、完成标准
... ...
skills/coding/fe-feature-tdd/SKILL.md
... ... @@ -13,8 +13,8 @@ allowed-tools: Read Write Edit Agent Skill Bash(git add *) Bash(git commit *)
13 13  
14 14 ## 路径护栏(前端阶段)
15 15  
16   -- 任务的 `impl_file` 路径若**不以** `frontend/`(或项目实际前端根目录,从 `docs/09-项目目录结构.md § 前端目录结构` 取)开头 → 硬停并打印:`fe-feature-tdd 不允许写非前端文件:<impl_file>。前端阶段任务的 impl_file 必须落在前端目录下。`
17   -- 命中 `backend/` / `sql/` / `scripts/` → 同上硬停
  16 +- 任务的 `impl_file` 路径若**不以** `frontend/`(或项目实际前端根目录,从 `docs/09-项目目录结构.md § 前端目录结构` 取)开头 → 硬停并打印:`fe-feature-tdd 不允许写非前端文件:<impl_file>。前端阶段任务的 impl_file 必须落在前端目录下。 [ERP-HALT]`
  17 +- 命中 `backend/` / `sql/` / `scripts/` → 同上硬停 `[ERP-HALT]`
18 18 - 不允许在主会话直接 `pnpm playwright` / `pnpm test` / `pnpm e2e`,必须派发子会话
19 19  
20 20 ## 执行步骤
... ...
skills/coding/feature-brainstorm/SKILL.md
... ... @@ -43,7 +43,7 @@ allowed-tools: Read Write Skill AskUserQuestion Bash(mysql *)
43 43 3. **写 spec 到 `docs/superpowers/specs/<YYYY-MM-DD>-<REQ-id>.md`**:
44 44 - 按 `${CLAUDE_SKILL_DIR}/templates/feature-spec-template.md` 渲染
45 45 - 覆盖:goal / 输入输出 / 业务规则 / 约束 / schema / API 引用 / acceptance criteria
46   - - 文件已存在 → 征求用户确认后覆盖
  46 + - 文件已存在 → 直接覆盖(spec 是 CC 内部产物,无需确认)
47 47  
48 48 4. **Spec 自审**(inline 修,无须用户等待):
49 49 - **占位符扫描**:`TBD` / `TODO` / `【人工填写:】` / 含糊段 → 修(按"占位符规则"流程解决)
... ...
skills/coding/feature-plan/SKILL.md
... ... @@ -56,7 +56,7 @@ allowed-tools: Read Write Grep Skill AskUserQuestion
56 56  
57 57 5. **写 plan 到 `docs/superpowers/plans/<YYYY-MM-DD>-<REQ-id>.md`**:
58 58 - 按 `${CLAUDE_SKILL_DIR}/templates/feature-plan-template.md` 渲染
59   - - 文件已存在 → 征求用户确认后覆盖
  59 + - 文件已存在 → 直接覆盖(plan 是 CC 内部产物,无需确认)
60 60  
61 61 6. **Plan 自审**(inline 修,无须用户等待):
62 62 - **占位符扫描**:按"占位符规则"清单逐项 grep;命中即修
... ...
skills/coding/feature-tdd/SKILL.md
... ... @@ -35,7 +35,7 @@ allowed-tools: Read Write Edit Agent Skill Bash(git add *) Bash(git commit *)
35 35 - **绝不**在主会话直接跑 `./gradlew test` / `pnpm test` / `scripts/test.sh`,必须通过子会话
36 36 - **绝不**在主会话直接 `mysql -e "ALTER ..."`;业务 schema 改动一律走 `sql/migrations/V*.sql` 文件(只读查询 / 临时调试除外)
37 37 - 每次 commit 必须含 `REQ-XXX-NNN` 标签;不混合无关改动到同一 commit
38   -- **后端阶段路径硬护栏**:任务表里的 `impl_file` 路径以 `frontend/` 开头 → 硬停并打印 `feature-tdd 后端阶段不允许写前端代码:<impl_file>。请检查 plan 任务定义;UI 推迟到前端阶段(fe-feature-*)`,不再继续 TDD 循环
  38 +- **后端阶段路径硬护栏**:任务表里的 `impl_file` 路径以 `frontend/` 开头 → 硬停并打印 `feature-tdd 后端阶段不允许写前端代码:<impl_file>。请检查 plan 任务定义;UI 推迟到前端阶段(fe-feature-*) [ERP-HALT]`,不再继续 TDD 循环
39 39  
40 40 ## 参考
41 41  
... ...
skills/coding/frontend-start/SKILL.md
... ... @@ -19,7 +19,7 @@ allowed-tools: Read Write Edit Skill Glob Grep AskUserQuestion Bash(git branch *
19 19  
20 20 读 docs/08 § 三 "功能:" 项:
21 21  
22   -- 已有 `- [ ] FE-NN ...` 或 `- [x] FE-NN ...` 行 → **加载**:逐行解析得 `fe_list[]`,每项 `{ fe_id, name, status, associated_reqs[], associated_prototypes[] }`。行格式不符 → 硬停打印问题行
  22 +- 已有 `- [ ] FE-NN ...` 或 `- [x] FE-NN ...` 行 → **加载**:逐行解析得 `fe_list[]`,每项 `{ fe_id, name, status, associated_reqs[], associated_prototypes[] }`。行格式不符 → 硬停打印问题行 `[ERP-HALT]`
23 23 - 仅有 HTML 注释占位(无 FE bullet)→ **推导**:
24 24 1. 读 `prototype/**/*.html` + `docs/01-需求清单/**/*.md` + `docs/05-API接口契约.md`
25 25 2. 以**业务功能**为单位拆分(同流程多屏可合 1 FE;一 HTML 多功能可拆多 FE;无 UI 的 REQ 不产生 FE)。每个 FE:`{ fe_id: FE-NN, name, associated_reqs[], associated_prototypes[] }`,prototype 路径可带 anchor 区分文件内多区域
... ... @@ -35,12 +35,12 @@ allowed-tools: Read Write Edit Skill Glob Grep AskUserQuestion Bash(git branch *
35 35  
36 36 读 § 三 `整体里程碑:` 字段并 `git tag -l 'milestone/frontend-phase'` 校验:
37 37  
38   -- 字段为 `milestone/frontend-phase` 且 tag 存在 → 打印"前端阶段已完成"并停(冗余保护,正常由 coding-start 拦掉)
  38 +- 字段为 `milestone/frontend-phase` 且 tag 存在 → 打印"前端阶段已完成 `[ERP-HALT]`"并停(冗余保护,正常由 coding-start 拦掉)
39 39 - 否则(`—` 或 tag 不存在)→ 进入步骤 4
40 40  
41 41 ### 步骤 4:切到 frontend-phase 分支
42 42  
43   -目标分支 `frontend-phase`,分支管理逻辑同 module-start 步骤 3:已在 → 继续;存在 → checkout;不存在 → 切本地默认分支后 `git checkout -b frontend-phase`。任何错误硬停 + 诊断,不自动 stash / 覆盖。
  43 +目标分支 `frontend-phase`,分支管理逻辑同 module-start 步骤 3:已在 → 继续;存在 → checkout;不存在 → 切本地默认分支后 `git checkout -b frontend-phase`。任何错误硬停 + 诊断,不自动 stash / 覆盖。`[ERP-HALT]`
44 44  
45 45 ### 步骤 5:识别已完成的 FE
46 46  
... ...
skills/coding/module-report/SKILL.md
... ... @@ -15,7 +15,7 @@ allowed-tools: Read Write Glob Grep Skill Bash(git diff *) Bash(git log *) Bash(
15 15  
16 16 - `module-<id>` → `phase=backend`,`phase_id=<id>`
17 17 - `frontend-phase` → `phase=frontend`,`phase_id=frontend-phase`
18   -- 其它分支 → 硬停
  18 +- 其它分支 → 硬停 `[ERP-HALT]`
19 19  
20 20 ## 执行步骤
21 21  
... ...
skills/coding/module-start/SKILL.md
... ... @@ -26,7 +26,7 @@ allowed-tools: Read Write Skill Glob Grep Bash(git branch *) Bash(git checkout *
26 26 约束:
27 27  
28 28 - 模块完成 = `docs/08 § 二` 该模块 `里程碑:` 字段为 `milestone/<module_id>` 且 `git tag -l` 能查到该 tag;二者任一缺失即视为未完成
29   -- 任何文件读取或解析失败 → 打印错误并停止
  29 +- 任何文件读取或解析失败 → 打印错误并停止 `[ERP-HALT]`
30 30  
31 31 ### 步骤 2:找不到未完成后端模块的处理
32 32  
... ... @@ -43,7 +43,7 @@ allowed-tools: Read Write Skill Glob Grep Bash(git branch *) Bash(git checkout *
43 43 - 该分支已存在但当前不在 → checkout 过去
44 44 - 该分支不存在 → 先把工作树切到本地默认分支(main 或 master,已由 milestone-tag 的本地 merge 累积所有已完成模块),作为新分支的干净 base,再 `git checkout -b` 创建模块分支
45 45  
46   -任何错误(定位不到默认分支 / 切换前工作树脏 / checkout 失败)一律停下并打印诊断信息,不自动 stash、不强制覆盖。
  46 +任何错误(定位不到默认分支 / 切换前工作树脏 / checkout 失败)一律停下并打印诊断信息,不自动 stash、不强制覆盖。`[ERP-HALT]`
47 47  
48 48 ### 步骤 4:计算已完成 REQ 集合 `done_reqs[]`
49 49  
... ...
skills/coding/test-gate/SKILL.md
... ... @@ -24,7 +24,7 @@ allowed-tools: Read Write Skill Agent Bash(git add *) Bash(git commit *) Bash(gi
24 24  
25 25 - `module-<id>` → `phase=backend`,`phase_id=<id>`,`command=./scripts/test.sh`
26 26 - `frontend-phase` → `phase=frontend`,`phase_id=frontend-phase`;命令从 `docs/04-技术规范.md § 零 frontend.test_command` / `frontend.e2e_command` 拼接(缺失则 `pnpm test:ci && pnpm e2e:ci`)
27   -- 其它分支 → 硬停打印 `test-gate 仅在 module-* 或 frontend-phase 分支可调用,当前 <branch>`
  27 +- 其它分支 → 硬停打印 `test-gate 仅在 module-* 或 frontend-phase 分支可调用,当前 <branch> [ERP-HALT]`
28 28  
29 29 1. 派发 Agent 子会话(general-purpose)运行上述 `command`,子会话只返回结构化 JSON(不输出描述文字):
30 30 ```json
... ... @@ -47,7 +47,7 @@ allowed-tools: Read Write Skill Agent Bash(git add *) Bash(git commit *) Bash(gi
47 47  
48 48 ```
49 49 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
50   - [test-gate] ⚠️ 未通过 (phase=<phase>)
  50 + [test-gate] ⚠️ 未通过 (phase=<phase>) [ERP-HALT]
51 51 失败清单: <子会话 JSON 的 failed 摘要>
52 52 详细证据: docs/superpowers/module-reports/<phase_id>-test-gate.md
53 53  
... ...
skills/crosscut/coding-start/SKILL.md
... ... @@ -22,13 +22,13 @@ cat &quot;${CLAUDE_PLUGIN_ROOT}/skills/crosscut/coding-start/banners/flow-overview.tx
22 22 ### 步骤 1:确认 docs/08 存在
23 23  
24 24 检查 `docs/08-模块任务管理.md` 存在。
25   -- 不存在 → 打印"⚠️ 项目尚未初始化,请先运行 `/erp-workflow:plan-start`"并停下。
  25 +- 不存在 → 打印"⚠️ 项目尚未初始化,请先运行 `/erp-workflow:plan-start` `[ERP-HALT]`"并停下。
26 26  
27 27 ### 步骤 2:Plan 完成性检查
28 28  
29 29 读取 `docs/08-模块任务管理.md § 一`,判断 A0~A5 是否全部勾选(含子项)。
30 30  
31   -- 任一未勾选 → 提示用户先运行 `/erp-workflow:plan-start` 完成 A 阶段,并停下
  31 +- 任一未勾选 → 提示用户先运行 `/erp-workflow:plan-start` 完成 A 阶段并打印 `[ERP-HALT]`,停下
32 32 - 全部勾选 → 进入步骤 3
33 33  
34 34 ### 步骤 3:后端完成性检查 + 派发
... ... @@ -43,7 +43,7 @@ cat &quot;${CLAUDE_PLUGIN_ROOT}/skills/crosscut/coding-start/banners/flow-overview.tx
43 43  
44 44 读 `docs/08 § 三 整体里程碑:` 字段(并用 `git tag -l 'milestone/frontend-phase'` 校验):
45 45  
46   -- **`整体里程碑: milestone/frontend-phase` 且 tag 存在** → 前端已完成,打印 `所有阶段已完成(后端模块 + 前端阶段里程碑均已标记)`,结束本 skill。
  46 +- **`整体里程碑: milestone/frontend-phase` 且 tag 存在** → 前端已完成,打印 `所有阶段已完成(后端模块 + 前端阶段里程碑均已标记) [ERP-HALT]`,结束本 skill。
47 47  
48 48 - **`整体里程碑: —` 或 tag 不存在** → 前端未完成,打印 `[coding-start] 后端已完成、前端未完成 → 派发 frontend-start(写前端)`,立即用 Skill 工具调用 frontend-start(直接调用,**不要**先输出"已完成 / 接下来 / 请检查 / 等你确认"之类桥接叙述——会被解读为 turn 结束信号、害用户手敲 continue),本 skill 结束。
49 49  
... ...
skills/crosscut/interrupt-check/SKILL.md
... ... @@ -30,7 +30,7 @@ allowed-tools: Read Write Bash(mysql *)
30 30  
31 31 1. 逐项核对 3 个中断条件。**全部未触发** → 输出 `interrupt-check: 通过`,结束。
32 32 2. **触发任一** → 按 `${CLAUDE_SKILL_DIR}/templates/interrupt-block-template.md` 渲染 Blocker 块,追加到当前 plan 文件(典型路径 `docs/superpowers/plans/<YYYY-MM-DD>-<REQ-id>.md`;test-gate 场景下追加到本模块任一已有 plan 文件)。
33   -3. 向会话打印一句话摘要 + 指向 plan 文件路径,**停下**。
  33 +3. 向会话打印一句话摘要 + 指向 plan 文件路径 + `[ERP-HALT]`,**停下**。
34 34  
35 35 ## 参考
36 36  
... ...
skills/plan/db-init/SKILL.md
... ... @@ -66,8 +66,8 @@ bash &quot;${CLAUDE_SKILL_DIR}/scripts/validate.sh&quot; \
66 66 - `1` → **自主修正循环**(最多 3 轮,docs/03 是 SSoT 不动):
67 67 1. 解析 stderr 差异清单,修正 V1.sql
68 68 2. 重跑 validate.sh
69   - 3. 退出 0 → 进入 B;退出 1 且本轮 < 3 → 回步骤 1;本轮 ≥ 3 仍失败 → 停下,打印最终残留差异 + 已尝试的 3 轮修正摘要,让用户介入
70   -- `2` → 用法错(V1 / docs 路径找不到),打印路径并停下
  69 + 3. 退出 0 → 进入 B;退出 1 且本轮 < 3 → 回步骤 1;本轮 ≥ 3 仍失败 → 停下,打印最终残留差异 + 已尝试的 3 轮修正摘要,让用户介入 `[ERP-HALT]`
  70 +- `2` → 用法错(V1 / docs 路径找不到),打印路径并停下 `[ERP-HALT]`
71 71  
72 72 完成后(V1 写入并通过 validate.sh 校验),用 `Edit` 在 `docs/08-模块任务管理.md` 中勾选:
73 73 - ` - [ ] sql/migrations/V1__initial_schema.sql 已生成`
... ... @@ -77,7 +77,7 @@ bash &quot;${CLAUDE_SKILL_DIR}/scripts/validate.sh&quot; \
77 77  
78 78 #### B.1 检查 .env.local 凭据
79 79  
80   -用 `Glob` 检查 `.env.local` 是否存在;不存在 → 提示用户重新运行 A2 `skeleton-gen` 重建并停下。
  80 +用 `Glob` 检查 `.env.local` 是否存在;不存在 → 提示用户重新运行 A2 `skeleton-gen` 重建并停下。`[ERP-HALT]`
81 81  
82 82 用 `Bash` 加载并校验 5 个必填字段非空:
83 83  
... ... @@ -89,7 +89,7 @@ for v in DB_HOST DB_PORT DB_USER DB_PASSWORD DB_SCHEMA; do
89 89 done
90 90 ```
91 91  
92   -任一缺失 → 打印缺失字段名并停下,提示用户编辑 `.env.local` 后重跑。
  92 +任一缺失 → 打印缺失字段名并停下,提示用户编辑 `.env.local` 后重跑。`[ERP-HALT]`
93 93  
94 94 #### B.2 验证 MySQL 连接
95 95  
... ... @@ -99,7 +99,7 @@ mysql -h&quot;$DB_HOST&quot; -P&quot;$DB_PORT&quot; -u&quot;$DB_USER&quot; -p&quot;$DB_PASSWORD&quot; -e &quot;SELECT 1;&quot;
99 99 ```
100 100  
101 101 - **成功** → 进入步骤 C
102   -- **失败** → 打印具体错误(认证 / 主机不可达 / 端口拒接等),提示检查 `.env.local`,**停下**。
  102 +- **失败** → 打印具体错误(认证 / 主机不可达 / 端口拒接等),提示检查 `.env.local`,**停下**。`[ERP-HALT]`
103 103  
104 104 完成后,用 `Edit` 在 `docs/08-模块任务管理.md` 中勾选:
105 105 - ` - [ ] .env.local 凭据已验证(mysql -e "SELECT 1" OK)`
... ... @@ -120,7 +120,7 @@ mysql -h&quot;$DB_HOST&quot; -P&quot;$DB_PORT&quot; -u&quot;$DB_USER&quot; -p&quot;$DB_PASSWORD&quot; &quot;$DB_SCHEMA&quot; \
120 120 < sql/migrations/V1__initial_schema.sql
121 121 ```
122 122  
123   -非零退出 → 报错停下,打印 mysql stderr。
  123 +非零退出 → 报错停下,打印 mysql stderr。`[ERP-HALT]`
124 124  
125 125 完成后,用 `Edit` 在 `docs/08-模块任务管理.md` 中勾选:
126 126 - ` - [ ] setup-test-db.sh 防护通过 + DROP+CREATE + apply V1 已执行`
... ... @@ -135,7 +135,7 @@ EXPECTED=$(grep -c &#39;^## `&#39; docs/03-数据库设计文档.md)
135 135 [ "$ACTUAL" = "$EXPECTED" ] || { echo "MISMATCH: actual=$ACTUAL expected=$EXPECTED"; exit 1; }
136 136 ```
137 137  
138   -行数不一致 → 报错停下;一致 → 进入步骤 D。
  138 +行数不一致 → 报错停下 `[ERP-HALT]`;一致 → 进入步骤 D。
139 139  
140 140 ### D. 勾选 docs/08 进度 + 进入 A5
141 141  
... ...
skills/plan/downstream-gen/SKILL.md
... ... @@ -94,11 +94,11 @@ cp &quot;${CLAUDE_SKILL_DIR}/templates/docs-10-header-template.md&quot; docs/10-验收检æ
94 94 - **module_id 缺 docs/08 § 二** → 按步骤 D è§„åˆ™æ¸²æŸ“è¯¥æ¨¡å— bulletï¼ˆå« REQ å­é¡¹ï¼‰ï¼ŒæŒ‰ `module_id` å­—æ¯åºæ’入正确ä½ç½®
95 95 - **module_id 缺 docs/02 § 二** → é‡ç®—该模å—çš„ `req_order` 段(步骤 A å­æµç¨‹ï¼‰ï¼ŒæŒ‰æ‹“æ‰‘åºæ’å…¥ docs/02 § 二
96 96  
97   - ä¿®å¤åŽé‡è·‘检查;通过 → 进入 2ï¼›3 è½®ä»å¤±è´¥ → åœä¸‹ï¼Œæ‰“å°æœ€ç»ˆæ®‹ç•™å·®å¼‚ + å·²å°è¯•çš„ 3 è½®ä¿®å¤æ‘˜è¦è®©ç”¨æˆ·ä»‹å…¥ã€‚
  97 + ä¿®å¤åŽé‡è·‘检查;通过 → 进入 2ï¼›3 è½®ä»å¤±è´¥ → åœä¸‹ï¼Œæ‰“å°æœ€ç»ˆæ®‹ç•™å·®å¼‚ + å·²å°è¯•çš„ 3 è½®ä¿®å¤æ‘˜è¦è®©ç”¨æˆ·ä»‹å…¥ã€‚`[ERP-HALT]`
98 98  
99 99 2. **最终å ä½ç¬¦æ‰«æ**(覆盖 Plan 阶段全部产出):
100 100  
101   - a. **`TBD` → 自动补é½**:Grep æœç´¢ `TBD(A3 自动补)` å’Œ `TBD(A5 自动补)`。有命中则就地补填(A3 残留 → 查 docs/03 å¡« `ä¾èµ–表`ï¼›A5 残留 → 查 docs/05 按 REQ-ID å¡« `ä¾èµ–接å£`ï¼‰ï¼Œå† Grep 确认 0 å‘½ä¸­ï¼›ä»æ®‹ç•™æŠ¥é”™åœä¸‹ã€‚
  101 + a. **`TBD` → 自动补é½**:Grep æœç´¢ `TBD(A3 自动补)` å’Œ `TBD(A5 自动补)`。有命中则就地补填(A3 残留 → 查 docs/03 å¡« `ä¾èµ–表`ï¼›A5 残留 → 查 docs/05 按 REQ-ID å¡« `ä¾èµ–接å£`ï¼‰ï¼Œå† Grep 确认 0 å‘½ä¸­ï¼›ä»æ®‹ç•™æŠ¥é”™åœä¸‹ã€‚`[ERP-HALT]`
102 102  
103 103 b. **`ã€äººå·¥å¡«å†™ï¼š...】` → QA 循环等用户补**:
104 104  
... ...
skills/plan/scope-lock/SKILL.md
... ... @@ -47,7 +47,7 @@ cat &quot;${CLAUDE_PLUGIN_ROOT}/skills/plan/scope-lock/banners/flow.txt&quot;
47 47 0 命中后,用 `Edit` 在 `docs/08-模块任务管理.md` 中勾选:
48 48 - ` - [ ] 项目概述已填写(CLAUDE.md § 🎯 项目概述)`
49 49  
50   -### B. 提示用户检查默认技术栈并等待
  50 +### B. 默认技术栈(自动,无停顿)
51 51  
52 52 `docs/04-技术规范.md` 已由 A0 `project-init` 用模板复制(默认技术栈,见 `project-init/templates/docs-04-stack-template.md`)。本步骤让用户检查 / 调整 § 零。
53 53  
... ... @@ -64,16 +64,11 @@ cat &quot;${CLAUDE_PLUGIN_ROOT}/skills/plan/scope-lock/banners/flow.txt&quot;
64 64 - 不需要的行直接删除(如纯后端项目删前端行)
65 65 - 需要替换的技术直接改
66 66 - 需要新增的条目直接加行
67   - 改完后回来选择「继续」。
  67 + (默认栈开箱即用;如需改,直接编辑该文件即可,流程不会在此等待。)
68 68 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
69 69 ```
70 70  
71   -用 `AskUserQuestion` 询问:
72   -- **question**: `技术栈检查完毕了吗?`
73   - - 用户选择「继续」→ 进入步骤 C。
74   - - 用户选择「有疑问想先沟通」→ 回答用户问题后,再次弹出同样的 QA。
75   -
76   -完成后,用 `Edit` 在 `docs/08-模块任务管理.md` 中勾选:
  71 +**不再弹窗等待。** 默认技术栈直接采用;若用户在本轮对话中已明确要求调整某项技术,就地用 `Edit` 改 docs/04 § 零,否则保持默认。随后用 `Edit` 在 `docs/08-模块任务管理.md` 中勾选,并直接进入步骤 C:
77 72 - ` - [ ] 技术栈已确认(docs/04 § 零)`
78 73  
79 74 ### C. 提示用户填写需求清单并等待
... ...
skills/plan/skeleton-gen/SKILL.md
... ... @@ -135,23 +135,15 @@ bash &quot;${CLAUDE_SKILL_DIR}/scripts/merge-gitignore.sh&quot; &quot;${CLAUDE_SKILL_DIR}/templ
135 135  
136 136 > `.env.local` 的 DB 连接核对**不在此处停**,统一放到 E.4 最终闸门——等所有产出(docs / scripts / .env.local / .gitignore)都初始化完成后再停一次,避免「一生成就停」。
137 137  
138   -#### E.4 验证 + QA 闸门(含 .env.local 连接核对
  138 +#### E.4 验证闸门(自动,无停顿
139 139  
140   -**这是 skeleton-gen 唯一的收尾停顿——所有产出(docs / scripts / .env.local / .gitignore)全部初始化完成后才在此停一次**,**严禁**在 `.env.local` 一生成(C.1)时就提前停。
  140 +所有产出(docs / scripts / .env.local / .gitignore)初始化完成后在此自动校验放行,**不再弹窗等待**:
141 141  
142   -循环直到两条件**同时**满足:
143   -(a) `Grep` 重新扫 8 路径,0 命中
144   -(b) 用户 `AskUserQuestion` 选「继续」
145   -
146   -每次弹 QA 前重扫;有残留则打印残留位置清单(文件:行号 — 说明)+ 再弹 QA。
147   -
148   -QA 横幅涵盖:
149   -- 产出文件清单(docs/04 / 06 / 07 / 09 + scripts/*.sh + .env.local + .gitignore)
150   -- 占位状态(N=0 或待填清单)
151   -- **`.env.local` DB 连接核对**:用 `Bash`(`set -a; . .env.local; set +a`)读出后列出当前 `DB_HOST` / `DB_PORT` / `DB_USER` / `DB_SCHEMA` 的**值**;`DB_PASSWORD` / `JWT_SECRET` **只列字段名、不回显值**(凭据不进会话)。提示「默认连接开箱即用;若与本地 MySQL 不符,**现在直接编辑 `.env.local`** 再选『继续』(`cp -n` 不会覆盖你的修改,下一步 A4 db-init 会真正连库验证)」。
152   -- 两选项:「继续」/「有疑问先沟通」
153   -
154   -通过后(N=0 且用户选「继续」),用 `Edit` 在 `docs/08-模块任务管理.md` 中勾选:
  142 +1. `Grep` 重扫 8 路径的占位符:
  143 + - 0 命中 → 进入 2。
  144 + - 仍有残留 → 打印残留清单(文件:行号 — 说明)并停下 `[ERP-HALT]`(骨架产出不应残留占位符,属生成异常,修正后重跑)。
  145 +2. **`.env.local` DB 连接信息(仅供参考,无需在此确认)**:用 `Bash`(`set -a; . .env.local; set +a`)列出 `DB_HOST` / `DB_PORT` / `DB_USER` / `DB_SCHEMA` 的**值**;`DB_PASSWORD` / `JWT_SECRET` **只列字段名、不回显**(凭据不进会话)。默认连接开箱即用;如与本地 MySQL 不符,可直接编辑 `.env.local`,下一步 A4 db-init 会真正连库验证(连不上会在 A4 报错停下)。
  146 +3. 用 `Edit` 在 `docs/08-模块任务管理.md` 中勾选,并直接进入 F:
155 147 - `- [ ] A2 骨架生成 — skeleton-gen`
156 148  
157 149 ### F. 进入 A3
... ...