Commit 981f6aceb41952b9b41ee6f4624b88ef50d52515

Authored by zichun
1 parent e559870b

refactor: B 阶段改用本地里程碑 tag,移除 git 远程/MR

- mr-create → milestone-tag:本地 merge 进默认分支 + 打 milestone/<id> tag,完成后自动回调 coding-start(无人工闸门)
- 移除 push/GitLab MR/API:删 deny-no-verify hook、derive-gitlab 脚本、pre-push 模板,env-local 去 GITLAB_*
- 完成判定改为 docs/08「里程碑」字段 + git tag -l;README/CLAUDE-template/状态语义同步
- 删除空 skills/internal 目录,skill 计数 27→25
- docs-04 § 一 新增 1.1 规则(后端通用约定)占位,由 skeleton-gen E 填写
Showing 36 changed files with 248 additions and 822 deletions
.claude-plugin/plugin.json
1 1 {
2 2 "name": "erp-workflow",
3   - "description": "ERP 项目全流程框架:阶段 A 计划(一次性) + 阶段 B 编码(模块循环 + 功能循环),含完整 skill 流水线 + 守门 hook + 软规则留痕。专为后端 Spring Boot + 前端 React + MySQL 8 的 ERP/管理类系统设计。",
  3 + "description": "ERP 项目全流程框架:阶段 A 计划(一次性) + 阶段 B 编码(模块循环 + 功能循环),含完整 skill 流水线 + 守门 hook + 软规则留痕。",
4 4 "version": "0.1.0",
5   - "skills": ["./skills/plan", "./skills/coding", "./skills/crosscut", "./skills/internal"]
  5 + "skills": ["./skills/plan", "./skills/coding", "./skills/crosscut"]
6 6 }
... ...
README.md
... ... @@ -2,7 +2,7 @@
2 2  
3 3 Claude Code 插件:ERP / 后端管理系统全流程开发框架。
4 4  
5   -把"从零到 N 个模块上线 + 前端整体阶段"的整个流程固化成 **27 个 skill + 2 个 agent + 2 个 hook + 44 份模板**,让 CC 在 schema 演化用 Flyway migration、需求可追溯、人工审核可控的前提下推进编码。后端按模块循环依次提交 MR,所有后端 merged 后进入前端整体阶段(以项目根 `prototype/` 静态 HTML mockup 为页面权威)。
  5 +把"从零到 N 个模块上线 + 前端整体阶段"的整个流程固化成 **25 个 skill + 2 个 agent + 1 个 hook + 41 份模板**,让 CC 在 schema 演化用 Flyway migration、需求可追溯、纯本地 git 的前提下推进编码。后端按模块循环依次打里程碑 tag,所有后端模块打里程碑后进入前端整体阶段(以项目根 `prototype/` 静态 HTML mockup 为页面权威)。
6 6  
7 7 ## 这个插件做什么
8 8  
... ... @@ -27,15 +27,15 @@ Claude Code 插件:ERP / 后端管理系统全流程开发框架。
27 27  
28 28 B-后端(按模块循环)
29 29 功能循环:Brainstorm → Plan → TDD → Verify → Review
30   - 模块循环:本地测试闸门 → 写模块报告 → 创建 GitLab MR → ⏸ 用户 Approve+Merge → 下次 coding-start 自动扫描 MR 状态为 merged → 下一模块
  30 + 模块循环:本地测试闸门 → 写模块报告 → 本地 merge 进默认分支 + 打 milestone/<id> tag → 自动回 coding-start → 下一模块
31 31  
32   - ↓ 后端全部 merged
  32 + ↓ 后端全部打里程碑
33 33  
34   - B-前端(整体阶段,1 个 MR
  34 + B-前端(整体阶段,1 个里程碑 tag
35 35 入口门禁:检查项目根 prototype/ 至少含 1 个 *.html mockup(缺失则 AskUserQuestion 提示用户补齐)
36   - FE 拆分:AI 自主推导功能清单(业务功能粒度,与 HTML 文件数无关)写入 docs/08 § 三;已有则加载——无人工审阅断点(人工只在 MR Approve+Merge 处介入)
  36 + FE 拆分:AI 自主推导功能清单(业务功能粒度,与 HTML 文件数无关)写入 docs/08 § 三;已有则加载——无人工审阅断点(全程无人工介入)
37 37 FE 循环(每个 FE-NN):fe-feature-brainstorm → -plan → -tdd → -verify → -review
38   - 收尾:test-gate(phase=frontend) → module-report(phase=frontend) → mr-create(分支 frontend-phase)→ ⏸ 用户 Approve+Merge → 全部完成
  38 + 收尾:test-gate(phase=frontend) → module-report(phase=frontend) → milestone-tag(分支 frontend-phase)→ 全部完成
39 39  
40 40 ⚙️ 后台守门:占位符未填 / 中断触发 / 跨模块改动未记录
41 41 ```
... ... @@ -66,7 +66,7 @@ Claude Code 插件:ERP / 后端管理系统全流程开发框架。
66 66 ```
67 67 /erp-workflow:coding-start
68 68 ```
69   - Plan 全部完成后由你显式触发。`coding-start` 是阶段分发权威——每次入口都重新扫描 docs/08 § 二/§ 三 + GitLab API state,按当前进度决定派发:
  69 + Plan 全部完成后由你显式触发。`coding-start` 是阶段分发权威——每次入口都重新扫描 docs/08 § 二/§ 三 里程碑字段 + 本地 git tag,按当前进度决定派发:
70 70  
71 71 **路由规则(coding-start 真值表,只做分发)**:
72 72  
... ... @@ -76,19 +76,19 @@ Claude Code 插件:ERP / 后端管理系统全流程开发框架。
76 76 | `true` | `false` | `frontend-start`(写前端) |
77 77 | `true` | `true` | 打印"所有阶段已完成",停下 |
78 78  
79   - GitLab API HTTP 非 200 / 查不到 / state 非法 → 停下报错(绝不静默假设未 merged)。
  79 + docs/08 里程碑字段与 `git tag -l` 不一致(字段填了但 tag 不存在,或反之)→ 停下报错(绝不静默假设完成状态)。
80 80  
81 81 **后端阶段(module-start 内,单一职责)**:
82   - - 切到 `module-<id>` 分支,跑功能循环(feature-brainstorm → ... → feature-review)→ 全 approve → test-gate → module-report → mr-create → ⏸ 人工 Approve+Merge → 用户重跑 coding-start,coding-start 再次路由
  82 + - 切到 `module-<id>` 分支,跑功能循环(feature-brainstorm → ... → feature-review)→ 全 approve → test-gate → module-report → milestone-tag(本地 merge + 打 tag)→ 自动回 coding-start 再次路由
83 83  
84 84 **前端阶段(frontend-start 内,自带前置门禁)**:
85 85 - 步骤 1:prototype/ 门禁(≥ 1 个 *.html,缺失则 AskUserQuestion 提示用户补齐 → 停下)
86 86 - 步骤 2:准备 FE 清单(无审阅断点)。§ 三 占位则 AI 扫 prototype + docs/01 + docs/05 自主推导 FE 业务功能清单写入 § 三(每个 FE 标注关联 REQ + 关联原型;FE 数与 HTML 文件数无关);§ 三 已有则直接加载
87   - - 步骤 4-8:MR state 判定 → 切 `frontend-phase` 分支 → 跑 fe-feature 循环(fe-feature-brainstorm → ... → fe-feature-review,专用 `fe-code-reviewer` agent 做 7 维 review)→ 全 approve → test-gate(frontend) → module-report(frontend) → mr-create(docs/08 § 三 整体 MR)→ ⏸ 人工 Approve+Merge
  87 + - 步骤 3-7:里程碑 tag 判定 → 切 `frontend-phase` 分支 → 跑 fe-feature 循环(fe-feature-brainstorm → ... → fe-feature-review,专用 `fe-code-reviewer` agent 做 7 维 review)→ 全 approve → test-gate(frontend) → module-report(frontend) → milestone-tag(docs/08 § 三 整体里程碑)→ 自动回 coding-start → 全部完成
88 88  
89   - `docs/08 § 二` 每后端模块占一行 bullet,`§ 三` 是前端阶段整体段,完成信号统一由 MR merged state 判定。
  89 + `docs/08 § 二` 每后端模块占一行 bullet,`§ 三` 是前端阶段整体段,完成信号统一由本地 `git tag -l 'milestone/<id>'` 判定。
90 90  
91   -4. **中途恢复**:任何时候运行对应入口命令——根据 Plan § 一 checkbox、§ 二 各后端模块 MR state、§ 三 前端整体 MR state 跳到当前该做的事。
  91 +4. **中途恢复**:任何时候运行对应入口命令——根据 Plan § 一 checkbox、§ 二 各后端模块里程碑 tag、§ 三 前端整体里程碑 tag 跳到当前该做的事。
92 92  
93 93 ## 目录结构
94 94  
... ... @@ -98,26 +98,24 @@ erp-workflow-plugin/
98 98 │ └── plugin.json # 插件清单,声明 skills 四个子目录
99 99 ├── README.md # 本文档
100 100 ├── hooks/
101   -│ ├── hooks.json # hook 注册表(2 个 hook)
102   -│ └── scripts/*.sh # 2 个 hook 脚本
  101 +│ ├── hooks.json # hook 注册表(1 个 hook)
  102 +│ └── scripts/*.sh # 1 个 hook 脚本
103 103 ├── agents/
104 104 │ ├── superpower-code-reviewer.md # 后端 code-reviewer agent(feature-review 调用)
105 105 │ └── fe-code-reviewer.md # 前端专用 reviewer(fe-feature-review 调用,硬编码 7 维 review)
106 106 └── skills/
107 107 ├── plan/ # 阶段 A:6 个一次性规划 skill
108 108 ├── coding/ # 阶段 B:15 个 skill = 9 个后端模块/功能循环 + frontend-start + 5 个 fe-feature-*
109   - ├── crosscut/ # 横切:2 个入口 + 1 中断守门 + 1 留痕 skill
110   - └── internal/ # superpowers 本地 fork:2 个无门 brainstorming / writing-plans
  109 + └── crosscut/ # 横切:2 个入口 + 1 中断守门 + 1 留痕 skill
111 110 ```
112 111  
113   -## Hook 清单(2 个,全部在 hooks/hooks.json 注册)
  112 +## Hook 清单(1 个,在 hooks/hooks.json 注册)
114 113  
115 114 | Hook | 脚本 | 事件 | 触发条件 | 作用 |
116 115 |---|---|---|---|---|
117   -| 拒绝 no-verify | `deny-no-verify.sh` | PreToolUse / Bash | CC 尝试 `git push --no-verify` | 硬拦截,强制 `.githooks/pre-push` 生效 |
118   -| 跨模块改动留痕 | `log-cross-module.sh` | PostToolUse / Edit \| Write | 当前处于 `module-*` 分支 且 编辑目标路径落在 `docs/08 § 二` 中**非当前模块**的 path 范围内(无论目标模块 MR 是否已 merged) | 把改动追加为 `TBD(CC 补)` 存根到 `<current_module>-cross-module.md`;通过 `additionalContext` 软提示 CC 调 `cross-module-log` skill **自主推断**补「原因 / 影响评估」两列。即时性由 CC 自己决定;**最迟在 `module-report` § ⑦ 硬闸门处**(TBD 未清空会阻断模块完成报告),保证模块完成前所有 TBD 必被 CC 填实 |
  116 +| 跨模块改动留痕 | `log-cross-module.sh` | PostToolUse / Edit \| Write | 当前处于 `module-*` 分支 且 编辑目标路径落在 `docs/08 § 二` 中**非当前模块**的 path 范围内(无论目标模块是否已打里程碑) | 把改动追加为 `TBD(CC 补)` 存根到 `<current_module>-cross-module.md`;通过 `additionalContext` 软提示 CC 调 `cross-module-log` skill **自主推断**补「原因 / 影响评估」两列。即时性由 CC 自己决定;**最迟在 `module-report` § ⑦ 硬闸门处**(TBD 未清空会阻断模块完成报告),保证模块完成前所有 TBD 必被 CC 填实 |
119 117  
120   -## Skill 清单(27 个)
  118 +## Skill 清单(25 个)
121 119  
122 120 ### Plan 阶段(6 个,`skills/plan/`)
123 121  
... ... @@ -125,7 +123,7 @@ erp-workflow-plugin/
125 123 |---|---|---|---|
126 124 | A0 | `project-init` | • 依赖检查(`mysql` 在 PATH,缺失则尝试自动安装)<br>• 空目录初始化:`cp` 模板创建 CLAUDE.md / docs/01/index.md / docs/08<br>• `git init` | `plan-start` |
127 125 | A1 | `scope-lock` | • 引导填项目概述 / 技术栈 / 需求索引<br>• 按 `docs/01-需求清单/<module>/{_module.md, REQ-*.md}` 子目录结构生成 REQ 卡片骨架(CC 起草 req_id / title / goal / rules / constraints / acceptance;输入 / 输出 各含一句简述 + N 张示例字段表(输入 8 列 / 输出 3 列),全部原样复制自模板,由人工按业务编辑;`依赖表 / 依赖接口` 留 `TBD(A3/A5 自动补)`)<br>• **停下**等人工审阅 + 改输入 / 输出,审阅完毕用 `/plan-start` 恢复续进 A2 | A0 |
128   -| A2 | `skeleton-gen` | • 生成架构文档:docs/04 § 一+ / docs/06 / docs/07 / docs/09<br>• 生成工具脚本:scripts/*.sh、.githooks/pre-push、.env.local<br>• 创建 `sql/migrations/` 空目录(Flyway 准备)<br>• 合并 .gitignore(逐行判重) | `plan-start` |
  126 +| A2 | `skeleton-gen` | • 生成架构文档:docs/04 § 一+ / docs/06 / docs/07 / docs/09<br>• 生成工具脚本:scripts/*.sh、.env.local<br>• 创建 `sql/migrations/` 空目录(Flyway 准备)<br>• 合并 .gitignore(逐行判重) | `plan-start` |
129 127 | A3 | `db-design-gen` | • 从 docs/01 REQ 卡片正向设计 `docs/03-数据库设计文档.md`(schema SSoT)<br>• 回填 REQ 卡片依赖表(`TBD(A3 自动补)` → 实际表名)<br>• **停下**等人工审阅 docs/03,审阅完毕用 `/plan-start` 恢复续进 A4 | A2 |
130 128 | A4 | `db-init` | • LLM 解析 docs/03 → `sql/migrations/V1__initial_schema.sql`(DDL only)<br>• **5 维度全量校验** DDL ↔ docs/03(表名 / 列名+列序 / 类型+nullable+默认值 / 索引名 / FK 名),fail-closed<br>• 验证 MySQL 连接<br>• 调 `scripts/setup-test-db.sh` 复用三层防护(与 B 阶段 test.sh 共用)→ DROP+CREATE 空库<br>• apply V1 + `SHOW TABLES` 行数自检 | A3 |
131 129 | A5 | `downstream-gen` | • 一次性生成 docs/02 / docs/05 / docs/06 § 三 / docs/10<br>• 回填 REQ 卡片依赖接口(`TBD(A5 自动补)` → 实际 endpoint)<br>• 追加模块清单到 docs/08 § 二<br>• 最终占位符扫描(TBD 自动补 + `【人工填写:】` QA 循环)<br>• 打印 Plan 完成横幅并**停下**(不自动进 B) | A4 |
... ... @@ -138,10 +136,10 @@ erp-workflow-plugin/
138 136 /erp-workflow:coding-start ← 用户每次手动触发;阶段分发器(只做分发)
139 137
140 138 │ ① Plan 完成校验(docs/08 § 一 A0~A5)
141   - │ ② 后端完成性检查(§ 二 + GitLab state
  139 + │ ② 后端完成性检查(§ 二 + git tag
142 140 │ ├ 未完成 → 立即派发 module-start,结束
143 141 │ └ 已完成 → 继续 ③
144   - │ ③ 前端完成性检查(§ 三 整体 MR + state
  142 + │ ③ 前端完成性检查(§ 三 整体里程碑 + tag
145 143 │ ├ 已完成 → 打印"所有阶段已完成",结束
146 144 │ └ 未完成 → 派发 frontend-start,结束
147 145
... ... @@ -155,11 +153,10 @@ erp-workflow-plugin/
155 153 │ │ request-changes (=5) → 停下(升级给人)
156 154 │ │
157 155 │ │ 本模块所有 REQ approve:
158   - │ │ test-gate(phase=backend) → module-report → mr-create
159   - │ │ (docs/08 § 二 写 MR iid)
  156 + │ │ test-gate(phase=backend) → module-report → milestone-tag
  157 + │ │ (本地 merge 进默认分支 + 打 milestone/<id>,写 docs/08 § 二)
160 158 │ │
161   - │ └─ ⏸ 停下等人工 Approve + Merge
162   - │ (合并后用户重跑 coding-start → coding-start 再次路由)
  159 + │ └─ 自动回 coding-start → 再次路由(无人工介入)
163 160
164 161 ├─ 后端完成 & 前端完成 → 打印"所有阶段已完成",停下
165 162
... ... @@ -194,23 +191,22 @@ erp-workflow-plugin/
194 191 │ 全部 FE approve:
195 192 │ test-gate(phase=frontend)(vitest + playwright,子会话跑)
196 193 │ → module-report(phase=frontend)
197   - │ → mr-create(docs/08 § 三 整体 MR
  194 + │ → milestone-tag(docs/08 § 三 整体里程碑
198 195
199   - └─ ⏸ 停下等人工 Approve + Merge
200   - (合并后再跑 coding-start → "所有阶段已完成")
  196 + └─ 自动回 coding-start → "所有阶段已完成"(无人工介入)
201 197 ```
202 198  
203 199 | Skill | 做什么 | 谁触发它 |
204 200 |---|---|---|
205   -| `module-start` | **后端模块循环单一职责**(不感知前端阶段)。切 `module-<id>` 分支,扫 `docs/superpowers/reviews/*.md` 的 `verdict=approve` 计算已完成 REQ,推进第一个未完成 REQ;本模块全 approve → `test-gate`。**幂等可重入** | `coding-start` 派发(仅当后端有未 merged 模块时);`feature-review` approve 后回调 |
  201 +| `module-start` | **后端模块循环单一职责**(不感知前端阶段)。切 `module-<id>` 分支,扫 `docs/superpowers/reviews/*.md` 的 `verdict=approve` 计算已完成 REQ,推进第一个未完成 REQ;本模块全 approve → `test-gate`。**幂等可重入** | `coding-start` 派发(仅当后端有未打里程碑模块时);`feature-review` approve 后回调 |
206 202 | `feature-brainstorm` | 功能循环步骤 1:交互 brainstorm → 生成 `docs/superpowers/specs/*.md` | `module-start` 推进 REQ 时调用 |
207 203 | `feature-plan` | 功能循环步骤 2:spec → 任务级 plan(文件路径 + API 签名 + 测试意图 + 完成判据,代码由 TDD 阶段产出),输出 `docs/superpowers/plans/*.md` | `feature-brainstorm` 链式调用 |
208 204 | `feature-tdd` | 功能循环步骤 3:红绿循环(写失败测试 → 实现 → 子会话验证通过 → commit 到 `module-<id>` 分支);路径硬护栏:`impl_file` 落 `frontend/` 前缀 → 硬停(UI 推迟到前端阶段) | `feature-plan` 链式调用 |
209 205 | `feature-verify` | 功能循环步骤 4:将全量测试派发到子会话执行一次,用模板渲染 evidence | `feature-tdd` 链式调用;`feature-review` 在 request-changes 修复后重新调用 |
210 206 | `feature-review` | 功能循环步骤 5:AI 自审,写 `docs/superpowers/reviews/*.md`。approve → 回 `module-start`;request-changes → 逐项 Edit + fix commit → 回 `feature-verify` 重新执行(最多 5 轮,第 5 轮仍 request-changes 则停下) | `feature-verify` 链式调用 |
211   -| `test-gate` | MR 前硬闸门。按当前分支推 phase:`module-*` → 跑 `scripts/test.sh`(drop+create 空库、Flyway apply、测试);`frontend-phase` → 跑 vitest + playwright(命令取自 docs/04 § 零)。通过 → 写 `<phase_id>-test-gate.md` 并 commit 到当前分支;失败停下 | `module-start`(后端 REQ 全 approve 后)/ `frontend-start`(FE 全 approve 后) |
  207 +| `test-gate` | 里程碑 tag 前硬闸门。按当前分支推 phase:`module-*` → 跑 `scripts/test.sh`(drop+create 空库、Flyway apply、测试);`frontend-phase` → 跑 vitest + playwright(命令取自 docs/04 § 零)。通过 → 写 `<phase_id>-test-gate.md` 并 commit 到当前分支;失败停下 | `module-start`(后端 REQ 全 approve 后)/ `frontend-start`(FE 全 approve 后) |
212 208 | `module-report` | 中断检查 → 生成 12 节完成报告 `docs/superpowers/module-reports/<date>-<phase_id>.md`(前端阶段 § ④/§ ⑥ 写 N/A)→ commit 到当前分支(后端:module-* 分支;前端:frontend-phase 分支) | `test-gate` 链式调用 |
213   -| `mr-create` | 中断检查 → 验证当前分支 = `module-<id>` 或 `frontend-phase` 且 `git status --porcelain` worktree 干净 → `git push` 推代码与全部 evidence → 用 curl 调 GitLab REST API 创建 MR(完成报告嵌入 MR 描述)→ 追加 MR URL 到报告并 commit → 把 docs/08 § 二 该模块的 `MR: —`(后端) / § 三 `整体 MR: —`(前端) 回写为 `!<iid>` 并 commit → 再次 push;**停下等人工 Approve+Merge**。完成由 MR state 判定 | `module-report` 链式调用 |
  209 +| `milestone-tag` | 验证当前分支 = `module-<id>` 或 `frontend-phase` 且 `git status --porcelain` worktree 干净 → 探测本地默认分支 → `git merge --no-ff` 本地集成进默认分支 → 把 docs/08 § 二 该模块的 `里程碑: —`(后端) / § 三 `整体里程碑: —`(前端) 回写为 `milestone/<id>` 并 commit → `git tag -a milestone/<id>` 打里程碑 → 追加 tag 名到报告并 commit → **自动回调 coding-start 推进下一阶段(无人工介入)**。完成由本地 `git tag -l` 判定 | `module-report` 链式调用 |
214 210 | `frontend-start` | 写前端阶段单一职责。步骤 1 自带 prototype/ 门禁(≥ 1 个 *.html,缺失则 AskUserQuestion)。步骤 2 准备 FE 清单(无审阅断点):§ 三 占位则 AI 自主推导写入;§ 三 已有则加载。后续切 `frontend-phase` 分支 + 计算未完成 FE + 推进第一个 FE 的 fe-feature 循环;全 approve → `test-gate(phase=frontend)` | `coding-start` 派发(仅当 `backend_done=true && frontend_done=false`);`fe-feature-review` approve 后回调 |
215 211 | `fe-feature-brainstorm` | 前端功能循环步骤 1:基于 FE 关联的 `associated_prototypes[]` + `associated_reqs[]` + docs/05 + docs/06 § 二 + docs/04 § 零前端 → spec | `frontend-start` 推进 FE 时调用,传 `{ fe_id, name, associated_reqs[], associated_prototypes[] }` |
216 212 | `fe-feature-plan` | 前端功能循环步骤 2:spec → 任务级计划(组件/路由/hook/API client,`impl_file` 必须 `frontend/` 前缀) | `fe-feature-brainstorm` 链式调用 |
... ... @@ -223,7 +219,7 @@ erp-workflow-plugin/
223 219 | Skill | 作用 | 流程中谁调用 |
224 220 |---|---|---|
225 221 | `plan-start` | **A 阶段入口**。读取 docs/08 § 一 找第一个未勾 A 子项 → 派发对应 A skill;A 全部完成时提示运行 coding-start | **用户手动**运行 `/erp-workflow:plan-start` |
226   -| `coding-start` | **B 阶段入口 + 阶段分发器(只做分发)**。① 验证 Plan 已完成(docs/08 § 一 A0~A5 全勾选)② 后端完成性检查(§ 二 + GitLab state)③ 前端完成性检查(§ 三 整体 MR)④ 真值表派发:`backend=false` → `module-start`;`backend=true & frontend=false` → `frontend-start`;都 done → "全部完成"。前端阶段的 prototype/ 门禁由 `frontend-start` 自带,不在此处 | **用户手动**运行 `/erp-workflow:coding-start` |
  222 +| `coding-start` | **B 阶段入口 + 阶段分发器(只做分发)**。① 验证 Plan 已完成(docs/08 § 一 A0~A5 全勾选)② 后端完成性检查(§ 二 + git tag)③ 前端完成性检查(§ 三 整体里程碑 + tag)④ 真值表派发:`backend=false` → `module-start`;`backend=true & frontend=false` → `frontend-start`;都 done → "全部完成"。前端阶段的 prototype/ 门禁由 `frontend-start` 自带,不在此处 | **用户手动**运行 `/erp-workflow:coding-start`;`milestone-tag` 每模块完成后自动回调 |
227 223 | `interrupt-check` | 检查 CLAUDE.md 的 3 项中断清单;触发则追加 Blocker 到计划文件并停下 | 功能循环各步骤和生成重要制品前自动调用 |
228 224 | `cross-module-log` | 给 `log-cross-module.sh` 追加的跨模块改动存根批量补「原因 / 影响评估」 | `module-report` § ⑦ 硬验收时一次性调用(CC 编辑中途不主动调);`module-start` 初始化日志文件时也会用其模板 |
229 225  
... ... @@ -250,7 +246,7 @@ step 0 流程图被抽到独立 `.txt` 文件,SKILL.md 步骤 0 改为 `bash cat
250 246  
251 247 **字节对齐保证**:每个文件 17 行,每行 visible width = 58 cell(内宽 56 + 2 个 `│` 边框)。改动需重新校准。
252 248  
253   -## Templates 清单(44 份)
  249 +## Templates 清单(41 份)
254 250  
255 251 | 所属 Skill | 模板文件 | 用途 |
256 252 |---|---|---|
... ... @@ -266,7 +262,6 @@ step 0 流程图被抽到独立 `.txt` 文件,SKILL.md 步骤 0 改为 `bash cat
266 262 | skeleton-gen | `docs-09-structure-template.md` | docs/09 目录结构大纲 |
267 263 | skeleton-gen | `scripts-setup-test-db-template.sh` | 运行时 drop + create 空库脚本(0 槽位);schema apply 交给 Flyway |
268 264 | skeleton-gen | `scripts-test-template.sh` | test.sh 骨架(4 个命令槽位:{{build_cmd}} / {{lint_cmd}} / {{test_cmd}} / {{e2e_cmd}},由 skeleton-gen 按技术栈推断填充) |
269   -| skeleton-gen | `githooks-pre-push-template.sh` | pre-push → 调 scripts/test.sh(0 槽位) |
270 265 | skeleton-gen | `env-local-template` | 6 字段凭据模板(DB_* + JWT_SECRET) |
271 266 | skeleton-gen | `gitignore-append-template` | 插件推荐忽略项(`.env.local`、`.tmp/`、构建产物等) |
272 267 | db-design-gen | `docs-03-header-template.md` | docs/03 数据库设计头部 |
... ... @@ -285,8 +280,6 @@ step 0 流程图被抽到独立 `.txt` 文件,SKILL.md 步骤 0 改为 `bash cat
285 280 | feature-review | `feature-review-template.md` | 自审报告结构 |
286 281 | test-gate | `test-gate-result-template.md` | 闸门结果渲染 |
287 282 | module-report | `module-report-template.md` | 12 节模块报告 |
288   -| mr-create | `mr-title-template.md` | MR 标题模板 |
289   -| mr-create | `mr-description-template.md` | MR 描述模板(嵌入模块报告) |
290 283 | interrupt-check | `interrupt-block-template.md` | Blocker 节追加模板 |
291 284 | cross-module-log | `cross-module-log-template.md` | cross-module 日志头(由 hook log-cross-module.sh 在首次跨模块改动时渲染创建;skill 自身不再读取) |
292 285 | cross-module-log | `cross-module-log-row-template.md` | 单条改动行模板 |
... ... @@ -305,7 +298,7 @@ step 0 流程图被抽到独立 `.txt` 文件,SKILL.md 步骤 0 改为 `bash cat
305 298 - **MySQL 8.x** 实例已就绪(推荐本地 / `*.local` host;A4 `db-init` 的安全守护要求 host 在白名单且 schema 名含 `test`/`dev`/`local`,避免误删生产库)
306 299 - **`mysql` 命令行**:A4 `db-init` 验证连接 + 自动 `DROP+CREATE` schema 后 apply V1;`scripts/setup-test-db.sh` 在测试闸门前后 drop+create 空库
307 300 - **Spring Boot + Flyway**(**必需**):pom.xml 声明 `flyway-core` + `flyway-mysql`;Spring 启动时自动 apply `sql/migrations/V*.sql`。本插件生成的 `setup-test-db.sh` 只清库,schema 必须由 Flyway 应用
308   -- **GitLab v3 API + Private Token**:`mr-create` 用 `curl` POST `/projects/:id/merge_requests` 建 MR;`coding-start` / `module-start` 用 `curl` GET `/projects/:id/merge_requests?iid=<iid>` 判定 state(v3 路径参数 `:merge_request_id` 要内部数字 id,所以统一用 iid 过滤列表)。HTTP 头用 `PRIVATE-TOKEN`;凭据(`GITLAB_API_URL=.../api/v3` / `GITLAB_TOKEN` / `GITLAB_PROJECT_ID`)放 `.env.local`
  301 +- **本地 git 仓库**(纯本地,无需远程):A0 `project-init` 执行 `git init`;B 阶段每模块由 `milestone-tag` 本地 `git merge --no-ff` 进默认分支并 `git tag -a milestone/<id>`,完成信号由 `git tag -l` 判定。**不依赖任何远程仓库 / push / GitLab**
309 302 - **本地可运行 `mvn test` / `pnpm test`**:测试闸门 `scripts/test.sh` 由 `skeleton-gen` 生成
310 303  
311 304 ## 设计原则
... ...
hooks/hooks.json
1 1 {
2 2 "hooks": {
3   - "PreToolUse": [
4   - {
5   - "matcher": "Bash",
6   - "hooks": [
7   - { "type": "command", "command": "\"${CLAUDE_PLUGIN_ROOT}\"/hooks/scripts/deny-no-verify.sh" }
8   - ]
9   - }
10   - ],
11 3 "PostToolUse": [
12 4 {
13 5 "matcher": "Edit|Write",
... ...
hooks/scripts/deny-no-verify.sh deleted
1   -#!/usr/bin/env bash
2   -# PreToolUse hook: block any `git push --no-verify` — the local test.sh gate is the only hard gate.
3   -
4   -set -euo pipefail
5   -
6   -input="$(cat)"
7   -tool_name="$(printf '%s' "$input" | jq -r '.tool_name // empty')"
8   -[ "$tool_name" = "Bash" ] || exit 0
9   -
10   -cmd="$(printf '%s' "$input" | jq -r '.tool_input.command // empty')"
11   -[ -n "$cmd" ] || exit 0
12   -
13   -if printf '%s' "$cmd" | grep -qE '\bgit[[:space:]]+push\b.*--no-verify\b'; then
14   - echo "BLOCKED: --no-verify bypasses the local test.sh gate (唯一硬闸门). If test.sh is failing, fix the root cause; do not skip the gate. Use /test-gate to run the gate properly." >&2
15   - exit 2
16   -fi
17   -
18   -exit 0
hooks/scripts/log-cross-module.sh
1 1 #!/usr/bin/env bash
2 2 # PostToolUse hook: 检测 Edit/Write 是否触及"当前模块以外"的模块路径,若是则在当前模块的跨模块日志中留痕(软规则 S2)。
3   -# CC 在当前模块开发期间改动其他模块(无论目标模块是否已 merged)都会在此处留痕。
  3 +# CC 在当前模块开发期间改动其他模块(无论目标模块是否已打里程碑)都会在此处留痕。
4 4  
5 5 set -euo pipefail
6 6  
... ... @@ -33,7 +33,7 @@ esac
33 33 # - module_0 <name>
34 34 # - 依赖: ...
35 35 # - 路径: backend/module/xxx/, frontend/pages/xxx/
36   -# - MR: !N 或 —
  36 +# - 里程碑: milestone/<id> 或 —
37 37 hit_module=""
38 38 # 用 awk 逐模块解析:每碰到 `- module_` 记录 module_id($2),然后在其下找第一个 `- 路径:` 行
39 39 # current_module 已在上文计算,在外层循环被排除 → 只会命中"非当前模块"的路径
... ...
skills/coding/fe-feature-review/SKILL.md
... ... @@ -20,7 +20,7 @@ allowed-tools: Read Write Edit Skill Agent Bash(git add *) Bash(git commit *)
20 20 3. 按 `verdict` 分派:
21 21  
22 22 **approve**
23   - - `Edit docs/08-模块任务管理.md § 三`,把本 FE 下 `- [ ] <fe_id> ...` 改为 `- [x] <fe_id> ...`(仅 FE 级可视化;前端阶段完成仍以 `整体 MR:` + GitLab API state 为准)
  23 + - `Edit docs/08-模块任务管理.md § 三`,把本 FE 下 `- [ ] <fe_id> ...` 改为 `- [x] <fe_id> ...`(仅 FE 级可视化;前端阶段完成仍以 `整体里程碑:` 字段 + 本地 `git tag -l` 为准)
24 24 - 输出 `fe-feature-review: <fe_id> round <N> 通过`,调用 `Skill(frontend-start)` 推进下一 FE 或进入 test-gate(phase=frontend)
25 25  
26 26 **request-changes(round < 5)**
... ...
skills/coding/feature-review/SKILL.md
... ... @@ -18,7 +18,7 @@ allowed-tools: Read Write Edit Skill Agent Bash(git add *) Bash(git commit *)
18 18 3. 按 `verdict` 分派:
19 19  
20 20 **approve**
21   - - `Edit docs/08-模块任务管理.md § 二`,把本模块下 `- [ ] <REQ-id> ...` 改为 `- [x] <REQ-id> ...`(仅功能级可视化;模块完成仍以 `MR:` + GitLab API state 为准,不依赖此勾选)
  21 + - `Edit docs/08-模块任务管理.md § 二`,把本模块下 `- [ ] <REQ-id> ...` 改为 `- [x] <REQ-id> ...`(仅功能级可视化;模块完成仍以 `里程碑:` 字段 + 本地 `git tag -l` 为准,不依赖此勾选)
22 22 - 输出 `feature-review: <REQ> round <N> 通过`,调用 `Skill(module-start)`
23 23  
24 24 **request-changes(round < 5)**
... ...
skills/coding/frontend-start/SKILL.md
... ... @@ -2,7 +2,7 @@
2 2 name: frontend-start
3 3 description: 前端阶段循环入口。AI 自主推导 FE 业务功能清单写入 docs/08 § 三(已有则加载),定位未完成 FE 派发 fe-feature-brainstorm 或 test-gate(前端阶段)。幂等可重入。
4 4 user-invocable: false
5   -allowed-tools: Read Write Edit Skill Glob Grep AskUserQuestion Bash(git branch *) Bash(git checkout *) Bash(git rev-parse *) Bash(git pull *) Bash(git status *) Bash(git symbolic-ref *) Bash(curl *) Bash(jq *) Bash(find *) Bash(ls *)
  5 +allowed-tools: Read Write Edit Skill Glob Grep AskUserQuestion Bash(git branch *) Bash(git checkout *) Bash(git rev-parse *) Bash(git status *) Bash(git symbolic-ref *) Bash(git tag *) Bash(find *) Bash(ls *)
6 6 ---
7 7  
8 8 **所有输出必须使用中文。**
... ... @@ -29,19 +29,18 @@ allowed-tools: Read Write Edit Skill Glob Grep AskUserQuestion Bash(git branch *
29 29 - [ ] FE-NN 功能名 | 关联 REQ:REQ-A, REQ-B | 关联原型:prototype/<file>.html
30 30 ```
31 31  
32   - 保留 `- 整体 MR: —` 不动;写入后解析得 `fe_list[]`,继续步骤 3
  32 + 保留 `- 整体里程碑: —` 不动;写入后解析得 `fe_list[]`,继续步骤 3
33 33  
34   -### 步骤 3:检查前端 MR 状态
  34 +### 步骤 3:检查前端里程碑状态
35 35  
36   -读 § 三 `整体 MR:` 调 GitLab API
  36 +读 § 三 `整体里程碑:` 字段并 `git tag -l 'milestone/frontend-phase'` 校验
37 37  
38   -- `merged` → 打印"前端阶段已完成"并停(冗余保护,正常由 coding-start 拦掉)
39   -- 其它(`—` / opened / closed)→ 进入步骤 4
40   -- API 异常 → 硬停 + 诊断
  38 +- 字段为 `milestone/frontend-phase` 且 tag 存在 → 打印"前端阶段已完成"并停(冗余保护,正常由 coding-start 拦掉)
  39 +- 否则(`—` 或 tag 不存在)→ 进入步骤 4
41 40  
42 41 ### 步骤 4:切到 frontend-phase 分支
43 42  
44   -目标分支 `frontend-phase`,分支管理逻辑同 module-start 步骤 3:已在 → 继续;存在 → checkout;不存在 → 切默认分支 fast-forward 后 `git checkout -b frontend-phase`。任何错误硬停 + 诊断,不自动 stash / 覆盖。
  43 +目标分支 `frontend-phase`,分支管理逻辑同 module-start 步骤 3:已在 → 继续;存在 → checkout;不存在 → 切本地默认分支后 `git checkout -b frontend-phase`。任何错误硬停 + 诊断,不自动 stash / 覆盖。
45 44  
46 45 ### 步骤 5:识别已完成的 FE
47 46  
... ... @@ -59,7 +58,7 @@ allowed-tools: Read Write Edit Skill Glob Grep AskUserQuestion Bash(git branch *
59 58 ## 参考
60 59  
61 60 - `${CLAUDE_SKILL_DIR}/templates/frontend-start-banner-template.md`
62   -- `docs/08-模块任务管理.md § 三`(前端阶段元数据:整体 MR + FE 清单)
  61 +- `docs/08-模块任务管理.md § 三`(前端阶段元数据:整体里程碑 + FE 清单)
63 62 - `prototype/`(HTML mockup,FE 拆分粒度与文件数无关)
64 63 - `docs/superpowers/reviews/*-FE-*.md`(verdict=approve 即完成)
65 64 - 上游:`coding-start`(步骤 4 派发,仅当后端完成 + 前端未完成);`fe-feature-review` approve 后回调
... ...
skills/coding/frontend-start/templates/frontend-start-banner-template.md
1 1 ## 前端阶段(frontend-phase)
2 2  
3 3 - 分支:frontend-phase
4   -- 整体 MR:{{overall_mr}}
  4 +- 整体里程碑:{{overall_milestone}}
5 5 - FE 进度(`x` = 已完成 review approve;FE 是业务功能粒度,与 prototype/ HTML 文件数无关):
6 6 {{#each fes}}
7 7 - [{{status}}] {{fe_id}} {{name}} | 关联 REQ:{{reqs}} | 关联原型:{{prototypes}}
... ...
skills/coding/milestone-tag/SKILL.md 0 → 100644
  1 +---
  2 +name: milestone-tag
  3 +description: 完成报告生成后,把当前分支(module-* 后端 / frontend-phase 前端)本地合并进默认分支并打里程碑 tag(milestone/<id>),把 tag 名回写 docs/08(§ 二 模块行 / § 三 整体里程碑)+ 报告 § ⑫,然后自动回调 coding-start 推进下一阶段。全程无人工介入。
  4 +user-invocable: false
  5 +allowed-tools: Read Edit Skill Bash(git *)
  6 +---
  7 +
  8 +**所有输出必须使用中文。**
  9 +
  10 +# milestone-tag
  11 +
  12 +## 前置条件
  13 +
  14 +- `module-report` 已生成报告并 commit 到当前分支
  15 +- `test-gate` 绿色,test-gate.md 已 commit 到当前分支
  16 +- 当前分支 = `module-<module_id>` 或 `frontend-phase`(由 `module-start` 步骤 3 / `frontend-start` 步骤 4 切入)
  17 +
  18 +## 执行步骤
  19 +
  20 +### 步骤 1:验证当前分支并推断 phase
  21 +
  22 +`git branch --show-current`:
  23 +
  24 +- 匹配 `module-*` → `phase=backend`,`phase_id=` 去掉 `module-` 前缀,`tag=milestone/<phase_id>`
  25 +- 等于 `frontend-phase` → `phase=frontend`,`phase_id=frontend-phase`,`tag=milestone/frontend-phase`
  26 +- 其它 → 停下报错(不自动建分支——分支职责在上游 `module-start` / `frontend-start`)
  27 +
  28 +### 步骤 2:验证 worktree 干净
  29 +
  30 +`git status --porcelain` 输出非空 → 停下打印 dirty 文件清单:
  31 +
  32 +```
  33 +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
  34 + [milestone-tag] ⚠️ worktree 不干净,无法集成 + 打里程碑
  35 +
  36 + <git status 输出>
  37 +
  38 + 集成前所有 evidence 必须已 commit。检查点:
  39 + - test-gate 步骤 3 是否已 commit test-gate.md?
  40 + - module-report 步骤 5 是否已 commit 报告 + cross-module log?
  41 +
  42 + 修复:git add <files> && git commit -m "...",然后重跑 /erp-workflow:coding-start。
  43 +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
  44 +```
  45 +
  46 +### 步骤 3:探测本地默认分支
  47 +
  48 +无远程,用 `git rev-parse --verify` 依次探测本地 `main` / `master`,取第一个存在的作为 `default_branch`。两者都不存在 → 停下报错。
  49 +
  50 +### 步骤 4:本地集成(合并模块分支进默认分支)
  51 +
  52 +替代原来的"远程 push + 人工 MR merge"——本地完成集成:
  53 +
  54 +```bash
  55 +git checkout <default_branch>
  56 +git merge --no-ff <current_branch> -m "merge(<phase_id>): integrate <current_branch>"
  57 +```
  58 +
  59 +合并冲突 → 停下打印冲突文件清单,引导人工解决后重跑 `/erp-workflow:coding-start`(不自动 `--abort`、不强制覆盖)。
  60 +
  61 +### 步骤 5:回写 docs/08 里程碑字段并 commit
  62 +
  63 +在 `default_branch` 上 `Edit docs/08-模块任务管理.md`:
  64 +
  65 +- **phase=backend**:在 § 二 中找到当前模块的 ` - 里程碑: —` 改为 ` - 里程碑: milestone/<phase_id>`
  66 +- **phase=frontend**:在 § 三 中找到 `- 整体里程碑: —` 改为 `- 整体里程碑: milestone/frontend-phase`
  67 +
  68 +```bash
  69 +git add docs/08-模块任务管理.md
  70 +git commit -m "chore(<phase_id>): record milestone/<phase_id> in docs/08"
  71 +```
  72 +
  73 +### 步骤 6:在默认分支 HEAD 打 annotated 里程碑 tag
  74 +
  75 +```bash
  76 +git tag -a milestone/<phase_id> -m "milestone(<phase_id>): <phase> 阶段完成"
  77 +```
  78 +
  79 +tag 已存在(重跑场景)→ 跳过,不重复打。
  80 +
  81 +### 步骤 7:追加里程碑 tag 到完成报告 § ⑫ 并 commit
  82 +
  83 +`Edit docs/superpowers/module-reports/<date>-<phase_id>.md` 的 § ⑫,把 `{{milestone_tag}}` 替换为 `milestone/<phase_id>`(已替换则跳过)。
  84 +
  85 +```bash
  86 +git add docs/superpowers/module-reports/<date>-<phase_id>.md
  87 +git commit -m "docs(<phase_id>): record milestone/<phase_id> in completion report"
  88 +```
  89 +
  90 +### 步骤 8:自动回调 coding-start 推进下一阶段
  91 +
  92 +本阶段已集成 + 打 tag,**不停下等人工**。立即用 Skill 工具调用 `coding-start`:
  93 +
  94 +- coding-start 重新做后端 / 前端完成性检查(按 `里程碑:` 字段 + `git tag -l`),未完则推进下一模块 / 前端阶段,全部完成则打印"所有阶段已完成"。
  95 +
  96 +## 参考
  97 +
  98 +- 上游:`module-report`
  99 +- 下游:`coding-start`(自治回调,由其路由下一阶段)
... ...
skills/coding/module-report/SKILL.md
1 1 ---
2 2 name: module-report
3   -description: 本地测试闸门通过后,生成标准化 12 节完成报告(后端模块 OR 前端阶段)并 commit 到当前分支供 MR 嵌入
  3 +description: 本地测试闸门通过后,生成标准化 12 节完成报告(后端模块 OR 前端阶段)并 commit 到当前分支(供里程碑标记)
4 4 user-invocable: false
5 5 allowed-tools: Read Write Glob Grep Skill Bash(git diff *) Bash(git log *) Bash(git add *) Bash(git commit *) Bash(git branch *)
6 6 ---
... ... @@ -9,7 +9,7 @@ allowed-tools: Read Write Glob Grep Skill Bash(git diff *) Bash(git log *) Bash(
9 9  
10 10 # module-report
11 11  
12   -`test-gate` 绿色后渲染 12 节完成报告,commit 到当前分支供 MR 嵌入。**只读摘要,不读 diff 正文进上下文**。
  12 +`test-gate` 绿色后渲染 12 节完成报告,commit 到当前分支供里程碑标记。**只读摘要,不读 diff 正文进上下文**。
13 13  
14 14 按当前分支自动推断 `phase`:
15 15  
... ... @@ -59,12 +59,12 @@ allowed-tools: Read Write Glob Grep Skill Bash(git diff *) Bash(git log *) Bash(
59 59 git add docs/superpowers/module-reports/<phase_id>-cross-module.md
60 60 git commit -m "docs(<phase_id>): add completion report + cross-module log"
61 61 ```
62   - commit 是必需的——`mr-create` 的 worktree-clean 前置条件依赖此步。
  62 + commit 是必需的——`milestone-tag` 的 worktree-clean 前置条件依赖此步。
63 63  
64   -6. 调用 `Skill(mr-create)` 推送并创建 MR
  64 +6. 调用 `Skill(milestone-tag)` 本地集成并打里程碑 tag
65 65  
66 66 ## 参考
67 67  
68 68 - `${CLAUDE_SKILL_DIR}/templates/module-report-template.md`(12 节,后端 + 前端共用)
69 69 - 上游:`test-gate`(绿色时派发)
70   -- 下游:`mr-create`(phase 由当前分支推断)
  70 +- 下游:`milestone-tag`(phase 由当前分支推断)
... ...
skills/coding/module-report/templates/module-report-template.md
... ... @@ -64,5 +64,5 @@ git_range: {{git_range}}
64 64 ## ⑪ 下一模块预览
65 65 {{next_module}}
66 66  
67   -## ⑫ MR 链接
68   -{{mr_url}}
  67 +## ⑫ 里程碑 tag
  68 +{{milestone_tag}}
... ...
skills/coding/module-start/SKILL.md
1 1 ---
2 2 name: module-start
3   -description: 后端模块循环入口。定位当前未 merged 模块与未完成 REQ,派发 feature-brainstorm 或 test-gate;幂等可重入。阶段路由由 coding-start 负责,本 skill 不感知前端阶段。
  3 +description: 后端模块循环入口。定位当前未完成(未打里程碑 tag)模块与未完成 REQ,派发 feature-brainstorm 或 test-gate;幂等可重入。阶段路由由 coding-start 负责,本 skill 不感知前端阶段。
4 4 user-invocable: false
5   -allowed-tools: Read Write Skill Glob Grep Bash(git branch *) Bash(git checkout *) Bash(git rev-parse *) Bash(git pull *) Bash(git status *) Bash(git symbolic-ref *) Bash(curl *) Bash(jq *)
  5 +allowed-tools: Read Write Skill Glob Grep Bash(git branch *) Bash(git checkout *) Bash(git rev-parse *) Bash(git status *) Bash(git symbolic-ref *) Bash(git tag *)
6 6 ---
7 7  
8 8 **所有输出必须使用中文。**
... ... @@ -11,29 +11,28 @@ allowed-tools: Read Write Skill Glob Grep Bash(git branch *) Bash(git checkout *
11 11  
12 12 ## 职责说明
13 13  
14   -本 skill 单一职责:推进**后端模块循环**。`coding-start` 已在派发前确认存在未 merged 后端模块;本 skill 不再做"后端是否全完"的判定,也不感知前端阶段。
  14 +本 skill 单一职责:推进**后端模块循环**。`coding-start` 已在派发前确认存在未完成后端模块;本 skill 不再做"后端是否全完"的判定,也不感知前端阶段。
15 15  
16 16 ## 执行步骤
17 17  
18 18 ### 步骤 1:定位当前模块与本模块 REQ 列表
19 19  
20   -按 `docs/02 § 二 开发顺序清单` 的 REQ 顺序扫描,找到第一个所属模块尚未 merged 的模块作为 `current_module`,并抽取本模块 REQ 序列。
  20 +按 `docs/02 § 二 开发顺序清单` 的 REQ 顺序扫描,找到第一个所属模块尚未打里程碑 tag 的模块作为 `current_module`,并抽取本模块 REQ 序列。
21 21  
22   -模块状态判定(`MR:` 字段 × GitLab API state 三种组合的语义和应对动作)参见 `CLAUDE.md § ✅ 阶段完成判定规则 § 状态语义`。
  22 +模块状态判定(`里程碑:` 字段 + `git tag -l 'milestone/<module_id>'` 存在性)参见 `CLAUDE.md § ✅ 阶段完成判定规则 § 状态语义`。
23 23  
24 24 找到 `current_module` 后,从 docs/02 § 二 的 REQ 列表里取出所有 `module_id == current_module` 的项,按原序得 `req_list[]`(A5 约束保证同模块 REQ 连续)。模块名、需求卡目录等其它字段由后续步骤按需从 `docs/08 § 二` 或 `docs/01-需求清单/` 取,不在本步骤预读。
25 25  
26 26 约束:
27 27  
28   -- GitLab 凭据从 `.env.local` 读取(`GITLAB_API_URL` / `GITLAB_TOKEN` / `GITLAB_PROJECT_ID`)
29   -- API 异常(HTTP 非 2xx / 找不到 MR / state 非合法值)一律硬停,**禁止静默假设未 merged**,向用户打印诊断信息,引导核查上述凭据与 docs/08 的 iid
  28 +- 模块完成 = `docs/08 § 二` 该模块 `里程碑:` 字段为 `milestone/<module_id>` 且 `git tag -l` 能查到该 tag;二者任一缺失即视为未完成
30 29 - 任何文件读取或解析失败 → 打印错误并停止
31 30  
32   -### 步骤 2:找不到未 merged 后端模块的处理
  31 +### 步骤 2:找不到未完成后端模块的处理
33 32  
34   -如果步骤 1 没找到任何未 merged 的后端模块——理论上不应触达此分支(`coding-start` 步骤 3 已确认存在未 merged 模块才会派发到本 skill),属于异常调用:
  33 +如果步骤 1 没找到任何未完成的后端模块——理论上不应触达此分支(`coding-start` 步骤 3 已确认存在未完成模块才会派发到本 skill),属于异常调用:
35 34  
36   -- 打印诊断:"`module-start` 未发现未 merged 后端模块。请通过 `/erp-workflow:coding-start` 入口重新驱动——coding-start 会按 docs/08 § 二/§ 三 自动路由到正确阶段(后端 / 前端 / 全部完成)。"
  35 +- 打印诊断:"`module-start` 未发现未完成后端模块。请通过 `/erp-workflow:coding-start` 入口重新驱动——coding-start 会按 docs/08 § 二/§ 三 自动路由到正确阶段(后端 / 前端 / 全部完成)。"
37 36 - 结束本 skill,不派发下游
38 37  
39 38 ### 步骤 3:确保处于模块分支
... ... @@ -42,9 +41,9 @@ allowed-tools: Read Write Skill Glob Grep Bash(git branch *) Bash(git checkout *
42 41  
43 42 - 已在该分支 → 继续步骤 4
44 43 - 该分支已存在但当前不在 → checkout 过去
45   -- 该分支不存在 → 先把工作树切到远程默认分支(main 或 master)并 fast-forward 同步,作为新分支的干净 base,再 `git checkout -b` 创建模块分支
  44 +- 该分支不存在 → 先把工作树切到本地默认分支(main 或 master,已由 milestone-tag 的本地 merge 累积所有已完成模块),作为新分支的干净 base,再 `git checkout -b` 创建模块分支
46 45  
47   -任何错误(定位不到默认分支 / 切换前工作树脏 / 不能 fast-forward / checkout 失败)一律停下并打印诊断信息,不自动 stash、不强制覆盖。
  46 +任何错误(定位不到默认分支 / 切换前工作树脏 / checkout 失败)一律停下并打印诊断信息,不自动 stash、不强制覆盖。
48 47  
49 48 ### 步骤 4:计算已完成 REQ 集合 `done_reqs[]`
50 49  
... ... @@ -64,10 +63,10 @@ allowed-tools: Read Write Skill Glob Grep Bash(git branch *) Bash(git checkout *
64 63 ## 参考
65 64  
66 65 - `docs/02-开发计划.md § 二 开发顺序清单`(分发权威)
67   -- `docs/08-模块任务管理.md § 二`(后端模块元数据,含 `MR:` 字段;完成判定以 MR state 为准)
  66 +- `docs/08-模块任务管理.md § 二`(后端模块元数据,含 `里程碑:` 字段;完成判定以 tag 存在为准)
68 67 - `docs/superpowers/reviews/*.md`(REQ 级进度事实——verdict=approve 即完成)
69 68 - `${CLAUDE_SKILL_DIR}/templates/module-start-banner-template.md`
70 69 - 下游:
71 70 - `feature-brainstorm`(每个未完成 REQ)
72 71 - `test-gate`(本模块全部 REQ approve 后;phase=backend 由分支推断)
73   -- 上游:`coding-start`(步骤 3 派发到此;后端模块全 merged 时不会派发到此)
  72 +- 上游:`coding-start`(步骤 3 派发到此;后端模块全部打里程碑时不会派发到此)
... ...
skills/coding/mr-create/SKILL.md deleted
1   ----
2   -name: mr-create
3   -description: 完成报告生成后,把当前分支(module-* 后端 / frontend-phase 前端)推到远程并创建 GitLab MR,把 MR iid 回写 docs/08(§ 二 模块行 / § 三 整体 MR)+ URL 回写报告 § ⑫,停下等人工 Approve + Merge。
4   -user-invocable: false
5   -allowed-tools: Read Edit Bash(git *) Bash(bash *)
6   ----
7   -
8   -**所有输出必须使用中文。**
9   -
10   -# mr-create
11   -
12   -## 前置条件
13   -
14   -- `module-report` 已生成报告并 commit 到当前分支
15   -- `test-gate` 绿色,test-gate.md 已 commit 到当前分支
16   -- 当前分支 = `module-<module_id>` 或 `frontend-phase`(由 `module-start` 步骤 3 / `frontend-start` 步骤 4 切入)
17   -
18   -## 执行步骤
19   -
20   -### 步骤 1:验证当前分支并推断 phase
21   -
22   -`git branch --show-current`:
23   -
24   -- 匹配 `module-*` → `phase=backend`,`phase_id=` 去掉 `module-` 前缀
25   -- 等于 `frontend-phase` → `phase=frontend`,`phase_id=frontend-phase`
26   -- 其它 → 停下报错(不自动建分支——分支职责在上游 `module-start` / `frontend-start`)
27   -
28   -### 步骤 2:验证 worktree 干净
29   -
30   -`git status --porcelain` 输出非空 → 停下打印 dirty 文件清单:
31   -
32   -```
33   -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
34   - [mr-create] ⚠️ worktree 不干净,无法 push
35   -
36   - <git status 输出>
37   -
38   - push 前所有 evidence 必须已 commit。检查点:
39   - - test-gate 步骤 3 是否已 commit test-gate.md?
40   - - module-report 步骤 5 是否已 commit 报告 + cross-module log?
41   -
42   - 修复:git add <files> && git commit -m "...",然后重跑 /erp-workflow:coding-start。
43   -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
44   -```
45   -
46   -### 步骤 3:初次 push
47   -
48   -`git push -u origin <current_branch>`——**禁用 `--no-verify`**。
49   -
50   -### 步骤 4:调脚本创建(或复用)MR
51   -
52   -```bash
53   -bash "${CLAUDE_SKILL_DIR}/scripts/create-mr.sh" <phase_id> <current_branch> <YYYY-MM-DD>
54   -```
55   -
56   -`<phase_id>` = 后端模块 id(如 `module_sys`)或前端常量 `frontend-phase`。脚本内部完成:加载 `.env.local` → 探测目标分支 → 取 `module_name`(后端从 docs/08 § 二,前端使用常量"前端阶段(整体)")→ test-gate.md 取结论 → 渲染 description → 查已有 opened MR → 否则创建新 MR。
57   -
58   -输出(stdout):单行 `<MR_IID> <MR_URL>`,由本步骤捕获供后续步骤使用。失败时脚本写诊断到 stderr 并 exit 1,本 skill 停下。
59   -
60   -### 步骤 5:回写 docs/08 MR 字段并 commit
61   -
62   -**先于步骤 6 执行**——若步骤 6 失败,重跑时步骤 4 脚本能识别已有 MR + docs/08 已含 IID,状态一致。
63   -
64   -`Edit docs/08-模块任务管理.md`:
65   -
66   -- **phase=backend**:在 § 二 中找到当前模块的 ` - MR: —` 改为 ` - MR: !<MR_IID>`
67   -- **phase=frontend**:在 § 三 中找到 `- 整体 MR: —` 改为 `- 整体 MR: !<MR_IID>`
68   -
69   -```bash
70   -git add docs/08-模块任务管理.md
71   -git commit -m "chore(<phase_id>): record MR !<MR_IID> in docs/08"
72   -```
73   -
74   -### 步骤 6:追加 MR URL 到完成报告 § ⑫ 并 commit
75   -
76   -`Edit docs/superpowers/module-reports/<date>-<phase_id>.md` 的 § ⑫,把 `{{mr_url}}` 替换为 `<MR_URL>`(已替换则追加一行)。
77   -
78   -```bash
79   -git add docs/superpowers/module-reports/<date>-<phase_id>.md
80   -git commit -m "docs(<phase_id>): record MR !<MR_IID> link in completion report"
81   -```
82   -
83   -### 步骤 7:再次 push 同步新 commits
84   -
85   -步骤 5、6 产生了两个新 commit,必须再 push 让 MR 自动更新 commit 列表 + diff:
86   -
87   -`git push origin <current_branch>`
88   -
89   -### 步骤 8:打印 MR URL,停下等 Approve + Merge
90   -
91   -向会话打印 `<MR_URL>`,结束本 skill。
92   -
93   -- **phase=backend**:用户在 GitLab merge 后再运行 `/erp-workflow:coding-start`;coding-start 重新做后端完成性检查,未完则推进下一模块,全 merged 则路由到 `frontend-start`(frontend-start 自带 prototype/ 门禁)
94   -- **phase=frontend**:用户在 GitLab merge 后再运行 `/erp-workflow:coding-start`,扫描到 § 三 整体 MR `state=merged` → 打印"所有阶段已完成"
95   -
96   -## 参考
97   -
98   -- `${CLAUDE_SKILL_DIR}/scripts/create-mr.sh`(步骤 4 主流程脚本,按 phase_id 自动选 backend / frontend 行为)
99   -- `${CLAUDE_SKILL_DIR}/templates/mr-title-template.md`
100   -- `${CLAUDE_SKILL_DIR}/templates/mr-description-template.md`
101   -- 上游:`module-report`
102   -- 下游闸门:用户手工 MR Approve + Merge
skills/coding/mr-create/scripts/create-mr.sh deleted
1   -#!/usr/bin/env bash
2   -# create-mr.sh — mr-create 主流程:渲染 description、查已有 MR / 创建新 MR
3   -#
4   -# 用法:
5   -# bash create-mr.sh <phase_id> <current_branch> <date>
6   -#
7   -# <phase_id> = 后端模块 id(如 module_sys)或前端常量 "frontend-phase"
8   -#
9   -# 输出(stdout,单行,由调用方读取):
10   -# <MR_IID> <MR_URL>
11   -#
12   -# 失败:诊断写 stderr,exit 1。
13   -#
14   -# 设计要点:
15   -# - 报告整文只经 sed + awk 管道流入 description 与 GitLab API(curl --rawfile),
16   -# 全程不进 LLM 上下文。
17   -# - 幂等:同一 source_branch 已有 opened MR 时,复用其 iid/url,不再创建。
18   -# - phase 自动:phase_id == "frontend-phase" 时跳过 docs/08 § 二 lookup,使用常量名。
19   -
20   -set -euo pipefail
21   -
22   -MODULE_ID="${1:?usage: create-mr.sh <phase_id> <current_branch> <date>}"
23   -CURRENT_BRANCH="${2:?missing current_branch}"
24   -DATE="${3:?missing date (YYYY-MM-DD)}"
25   -
26   -SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
27   -TPL_DIR="$SCRIPT_DIR/../templates"
28   -DESC_TPL="$TPL_DIR/mr-description-template.md"
29   -TITLE_TPL="$TPL_DIR/mr-title-template.md"
30   -
31   -REPORT="docs/superpowers/module-reports/${DATE}-${MODULE_ID}.md"
32   -TEST_GATE="docs/superpowers/module-reports/${MODULE_ID}-test-gate.md"
33   -
34   -[ -f "$REPORT" ] || { echo "[create-mr] ⚠️ 完成报告不存在: $REPORT" >&2; exit 1; }
35   -[ -f "$TEST_GATE" ] || { echo "[create-mr] ⚠️ test-gate evidence 不存在: $TEST_GATE" >&2; exit 1; }
36   -
37   -# 1. 加载凭据
38   -[ -f .env.local ] || { echo "[create-mr] ⚠️ .env.local 不存在" >&2; exit 1; }
39   -set -a; . ./.env.local; set +a
40   -for v in GITLAB_API_URL GITLAB_TOKEN GITLAB_PROJECT_ID; do
41   - eval "val=\${$v:-}"
42   - [ -n "$val" ] || { echo "[create-mr] ⚠️ .env.local 缺少 $v" >&2; exit 1; }
43   -done
44   -
45   -# 2. 探测目标分支(origin/HEAD → main → master)
46   -TARGET_BRANCH=$(git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null | sed 's|refs/remotes/origin/||' || true)
47   -[ -n "$TARGET_BRANCH" ] || TARGET_BRANCH=$(git branch -r --format='%(refname:short)' | grep -E '^origin/(main|master)$' | head -1 | sed 's|^origin/||' || true)
48   -[ -n "$TARGET_BRANCH" ] || { echo "[create-mr] ⚠️ 无法探测默认分支(origin/main 或 origin/master)" >&2; exit 1; }
49   -
50   -# 3. 取 module_name
51   -if [ "$MODULE_ID" = "frontend-phase" ]; then
52   - MODULE_NAME="前端阶段(整体)"
53   -else
54   - # 从 docs/08 § 二 提取后端模块 module_name
55   - MODULE_NAME=$(awk -v mid="$MODULE_ID" '
56   - $0 ~ "^- "mid" " { sub("^- "mid" ", ""); print; exit }
57   - ' docs/08-模块任务管理.md)
58   - [ -n "$MODULE_NAME" ] || { echo "[create-mr] ⚠️ docs/08 § 二 找不到模块 $MODULE_ID" >&2; exit 1; }
59   -fi
60   -
61   -# 4. 从 test-gate evidence 提取 conclusion + subagent_id
62   -TEST_SUBAGENT_ID=$(awk '/^- 子会话: / { sub("^- 子会话: ", ""); print; exit }' "$TEST_GATE")
63   -TEST_GATE_CONCLUSION=$(awk '/^结论: / { sub("^结论: ", ""); print; exit }' "$TEST_GATE" | awk '{print $1}')
64   -
65   -# 5. 渲染 MR 标题(单行,可进 LLM 上下文)
66   -TITLE=$(cat "$TITLE_TPL")
67   -TITLE="${TITLE//\{\{module_id\}\}/$MODULE_ID}"
68   -TITLE="${TITLE//\{\{module_name\}\}/$MODULE_NAME}"
69   -
70   -# 6. 渲染 description(整篇模块报告,全程不进 LLM 上下文)
71   -mkdir -p .tmp
72   -DESC_FILE=.tmp/mr-desc.md
73   -
74   -sed -e "s|{{test_gate_conclusion}}|$TEST_GATE_CONCLUSION|g" \
75   - -e "s|{{test_subagent_id}}|$TEST_SUBAGENT_ID|g" \
76   - -e "s|{{module_id}}|$MODULE_ID|g" \
77   - -e "s|{{date}}|$DATE|g" \
78   - "$DESC_TPL" > "$DESC_FILE"
79   -
80   -awk -v report="$REPORT" '
81   - /\{\{module_report_contents\}\}/ { while ((getline line < report) > 0) print line; close(report); next }
82   - { print }
83   -' "$DESC_FILE" > .tmp/mr-desc.final
84   -mv .tmp/mr-desc.final "$DESC_FILE"
85   -
86   -# 7. 幂等守门:查已有 opened MR
87   -CURL_META=$(curl -sS -o .tmp/existing.json -w '%{http_code}|%{url_effective}' \
88   - --header "PRIVATE-TOKEN: ${GITLAB_TOKEN}" \
89   - "${GITLAB_API_URL}/projects/${GITLAB_PROJECT_ID}/merge_requests?source_branch=${CURRENT_BRANCH}&state=opened")
90   -
91   -HTTP_CODE=${CURL_META%%|*}
92   -EFFECTIVE_URL=${CURL_META#*|}
93   -
94   -if [ "$HTTP_CODE" != "200" ]; then
95   - echo "[create-mr] ⚠️ 查询已有 MR 失败 (HTTP $HTTP_CODE)" >&2
96   - echo " effective URL: $EFFECTIVE_URL" >&2
97   - FIRST=$(head -c 1 .tmp/existing.json 2>/dev/null || echo "")
98   - case "$FIRST" in
99   - '{'|'[')
100   - echo " 响应(JSON):" >&2
101   - jq -r '.message // .error // .' .tmp/existing.json 2>/dev/null | head -c 200 >&2
102   - echo >&2
103   - ;;
104   - '<')
105   - echo " 响应是 HTML(很可能反代/路由失配,把 API 请求送进了 web 处理链):" >&2
106   - head -c 200 .tmp/existing.json >&2
107   - echo >&2
108   - echo " 常见原因:GITLAB_API_URL 错 / GITLAB_PROJECT_ID 不是数字 ID / 反代规范化路径" >&2
109   - ;;
110   - *)
111   - echo " 响应非 JSON 非 HTML(前 200 bytes):" >&2
112   - head -c 200 .tmp/existing.json >&2
113   - echo >&2
114   - ;;
115   - esac
116   - rm -f .tmp/existing.json "$DESC_FILE"
117   - exit 1
118   -fi
119   -
120   -EXISTING_IID=$(jq -r '.[0].iid // empty' .tmp/existing.json)
121   -EXISTING_URL=$(jq -r '.[0].web_url // empty' .tmp/existing.json)
122   -rm -f .tmp/existing.json
123   -
124   -if [ -n "$EXISTING_IID" ]; then
125   - echo "[create-mr] 复用已有 opened MR: !$EXISTING_IID" >&2
126   - rm -f "$DESC_FILE"
127   - echo "$EXISTING_IID $EXISTING_URL"
128   - exit 0
129   -fi
130   -
131   -# 8. 创建新 MR(--rawfile desc 把 description 文件流入 jq → curl,不进 LLM 上下文)
132   -CREATE_RESP=$(curl -sS -X POST \
133   - --header "PRIVATE-TOKEN: ${GITLAB_TOKEN}" \
134   - --header "Content-Type: application/json" \
135   - --data "$(jq -n \
136   - --arg src "$CURRENT_BRANCH" \
137   - --arg tgt "$TARGET_BRANCH" \
138   - --arg title "$TITLE" \
139   - --rawfile desc "$DESC_FILE" \
140   - '{source_branch: $src, target_branch: $tgt, title: $title, description: $desc, remove_source_branch: false}')" \
141   - "${GITLAB_API_URL}/projects/${GITLAB_PROJECT_ID}/merge_requests")
142   -
143   -MR_IID=$(echo "$CREATE_RESP" | jq -r '.iid // empty')
144   -MR_URL=$(echo "$CREATE_RESP" | jq -r '.web_url // empty')
145   -
146   -if [ -z "$MR_IID" ]; then
147   - echo "[create-mr] ⚠️ MR 创建失败:" >&2
148   - echo "$CREATE_RESP" | jq . >&2
149   - rm -f "$DESC_FILE"
150   - exit 1
151   -fi
152   -
153   -rm -f "$DESC_FILE"
154   -echo "$MR_IID $MR_URL"
skills/coding/mr-create/templates/mr-description-template.md deleted
1   -## 完成报告
2   -
3   -见 `docs/superpowers/module-reports/{{date}}-{{module_id}}.md`(本 MR 仓库内完整贴入下方)。
4   -
5   ----
6   -
7   -{{module_report_contents}}
8   -
9   ----
10   -
11   -## 本地闸门证据
12   -
13   -- 测试: {{test_gate_conclusion}}(subagent: {{test_subagent_id}})
14   -
15   -## 审核入口
16   -
17   -- 本 MR = `{{module_id}}` 的唯一人工介入点(后端模块 / 前端阶段共用)
18   -- Approve + Merge 后,下次用户运行 `/erp-workflow:coding-start` 时入口会自动扫描 GitLab API `state=merged`,探测默认分支后 `git pull --ff-only` 同步并推进下一模块(后端阶段)或宣告全部完成(前端阶段)
skills/coding/mr-create/templates/mr-title-template.md deleted
1   -feat({{module_id}}): {{module_name}}
skills/coding/test-gate/SKILL.md
1 1 ---
2 2 name: test-gate
3   -description: MR 创建前的硬闸门。后端阶段子会话跑 scripts/test.sh,前端阶段跑前端测试命令;绿则进入 module-report,红则停下并按失败类型引导用户。
  3 +description: 打里程碑 tag 前的硬闸门。后端阶段子会话跑 scripts/test.sh,前端阶段跑前端测试命令;绿则进入 module-report,红则停下并按失败类型引导用户。
4 4 user-invocable: false
5 5 allowed-tools: Read Write Skill Agent Bash(git add *) Bash(git commit *) Bash(git branch *)
6 6 ---
... ... @@ -37,7 +37,7 @@ allowed-tools: Read Write Skill Agent Bash(git add *) Bash(git commit *) Bash(gi
37 37 }
38 38 ```
39 39 2. 按 `${CLAUDE_SKILL_DIR}/templates/test-gate-result-template.md` 渲染证据,写入 `docs/superpowers/module-reports/<phase_id>-test-gate.md`(后端:`<module_id>-test-gate.md`;前端:`frontend-phase-test-gate.md`)。
40   -3. Commit evidence 到当前分支(保证证据随 MR 合并进默认分支可审计):
  40 +3. Commit evidence 到当前分支(保证证据随里程碑 merge 进默认分支可审计):
41 41 ```bash
42 42 git add docs/superpowers/module-reports/<phase_id>-test-gate.md
43 43 git commit -m "chore(<phase_id>): add local test-gate evidence"
... ... @@ -67,7 +67,7 @@ allowed-tools: Read Write Skill Agent Bash(git add *) Bash(git commit *) Bash(gi
67 67 ## 护栏
68 68  
69 69 - **绝不**在主会话直接执行 `./scripts/test.sh` / `pnpm test` / `pnpm e2e`,必须通过子会话
70   -- **绝不**通过 `git push --no-verify` 绕过(hook `deny-no-verify.sh` 会硬拦)
  70 +- 本闸门是里程碑 tag 前唯一的硬测试门:红色时**绝不**跳过直接进入 `module-report` / `milestone-tag`
71 71  
72 72 ## 参考
73 73  
... ...
skills/crosscut/coding-start/SKILL.md
... ... @@ -2,7 +2,7 @@
2 2 name: coding-start
3 3 description: B 阶段(Coding)入口与阶段分发器。验证 Plan 完成后做后端 + 前端的完成性检查,每段检查后立即派发:后端未完成 → module-start(写后端);后端已完成 + 前端未完成 → frontend-start(写前端);都完成 → 全部完成。本 skill 只做分发,不做 prototype/ 门禁。
4 4 user-invocable: true
5   -allowed-tools: Skill Read Glob Grep Bash(cat *) Bash(curl *) Bash(jq *)
  5 +allowed-tools: Skill Read Glob Grep Bash(cat *) Bash(git tag *)
6 6 ---
7 7  
8 8 **所有输出必须使用中文。**
... ... @@ -33,26 +33,25 @@ cat &quot;${CLAUDE_PLUGIN_ROOT}/skills/crosscut/coding-start/banners/flow-overview.tx
33 33  
34 34 ### 步骤 3:后端完成性检查 + 派发
35 35  
36   -读 `docs/08 § 二`,对每个后端模块的 `MR:` 字段
  36 +读 `docs/08 § 二`,对每个后端模块的 `里程碑:` 字段(并用 `git tag -l 'milestone/<module_id>'` 校验 tag 真实存在)
37 37  
38   -- **任一模块 `MR: —` 或 state ∈ {`opened`, `closed`}** → 后端未完成,打印 `[coding-start] 后端未完成 → 派发 module-start(写后端)`,立即用 Skill 工具调用 module-start,本 skill 结束,不进入步骤 4。
  38 +- **任一模块 `里程碑: —` 或对应 `milestone/<module_id>` tag 不存在** → 后端未完成,打印 `[coding-start] 后端未完成 → 派发 module-start(写后端)`,立即用 Skill 工具调用 module-start,本 skill 结束,不进入步骤 4。
39 39  
40   -- **所有模块 `MR: !<iid>` 且 state == `merged`**(用API检查)→ 后端已完成,进入步骤 4。
  40 +- **所有模块 `里程碑: milestone/<module_id>` 且 tag 存在** → 后端已完成,进入步骤 4。
41 41  
42 42 ### 步骤 4:前端完成性检查 + 派发
43 43  
44   -读 `docs/08 § 三 整体 MR:` 字段
  44 +读 `docs/08 § 三 整体里程碑:` 字段(并用 `git tag -l 'milestone/frontend-phase'` 校验)
45 45  
46   -- **`MR: !<iid>` 且 state == `merged`**(用API检查)→ 前端已完成,打印 `所有阶段已完成(后端模块 + 前端阶段均已 merged)`,结束本 skill。
  46 +- **`整体里程碑: milestone/frontend-phase` 且 tag 存在** → 前端已完成,打印 `所有阶段已完成(后端模块 + 前端阶段里程碑均已标记)`,结束本 skill。
47 47  
48   -- **`MR: —` 或 state ∈ {`opened`, `closed`}** → 前端未完成,打印 `[coding-start] 后端已完成、前端未完成 → 派发 frontend-start(写前端)`,立即用 Skill 工具调用 frontend-start,本 skill 结束。
  48 +- **`整体里程碑: —` 或 tag 不存在** → 前端未完成,打印 `[coding-start] 后端已完成、前端未完成 → 派发 frontend-start(写前端)`,立即用 Skill 工具调用 frontend-start,本 skill 结束。
49 49  
50 50 ## 参考
51 51  
52 52 - `docs/08-模块任务管理.md § 一`(A0~A5 进度勾选,步骤 2 读取)
53   -- `docs/08-模块任务管理.md § 二`(后端模块元数据 + MR 字段,步骤 3 读取)
54   -- `docs/08-模块任务管理.md § 三`(前端阶段整体 MR,步骤 4 读取)
55   -- `.env.local`(GitLab API 凭据,步骤 3 / 4 读取)
  53 +- `docs/08-模块任务管理.md § 二`(后端模块元数据 + 里程碑字段,步骤 3 读取)
  54 +- `docs/08-模块任务管理.md § 三`(前端阶段整体里程碑,步骤 4 读取)
56 55 - 下游:
57 56 - `module-start`(写后端:步骤 3 派发)
58 57 - `frontend-start`(写前端:步骤 4 派发)
... ...
skills/crosscut/coding-start/banners/flow-overview.txt
... ... @@ -3,10 +3,10 @@
3 3 │ │
4 4 │ coding-start (只做分发) │
5 5 │ ① Plan 完成校验(docs/08 § 一 A0~A5) │
6   -│ ② 后端完成性检查(§ 二 + GitLab state)
  6 +│ ② 后端完成性检查(§ 二 + git tag)
7 7 │ ├ 未完成 → 立即派发 module-start,结束 │
8 8 │ └ 已完成 → 继续 ③ │
9   -│ ③ 前端完成性检查(§ 三 整体 MR + state)
  9 +│ ③ 前端完成性检查(§ 三 整体里程碑 + tag)
10 10 │ ├ 已完成 → 打印"全部完成",结束 │
11 11 │ └ 未完成 → 派发 frontend-start,结束 │
12 12 │ │
... ... @@ -38,9 +38,9 @@
38 38 │ ↓ 本模块所有 REQ approve │
39 39 │ test-gate(phase=backend) │
40 40 │ ↓ │
41   -│ module-report → mr-create │
42   -│ ↓ 停下,等人工 Approve + Merge │
43   -│ ↺ 用户重跑 coding-start → coding-start 再分发 │
  41 +│ module-report → milestone-tag │
  42 +│ ↓ 本地 merge 进默认分支 + 打 milestone tag │
  43 +│ ↺ 自动回 coding-start → 再分发(无人工) │
44 44 │ │
45 45 │ ┌─ 前端功能循环(每 FE-NN)─────┐ │
46 46 │ │ fe-feature-brainstorm │ │
... ... @@ -59,8 +59,8 @@
59 59 │ ↓ 全部 FE approve │
60 60 │ test-gate(phase=frontend) │
61 61 │ ↓ │
62   -│ module-report → mr-create │
63   -│ (分支 frontend-phase,docs/08 § 三 整体 MR) │
64   -│ ↓ 停下,等人工 Approve + Merge │
65   -│ ↺ 用户重跑 coding-start → 全部完成 │
  62 +│ module-report → milestone-tag │
  63 +│ (分支 frontend-phase,docs/08 § 三 整体里程碑)│
  64 +│ ↓ 本地 merge + 打 milestone/frontend-phase │
  65 +│ ↺ 自动回 coding-start → 全部完成 │
66 66 └────────────────────────────────────────────────────────┘
... ...
skills/crosscut/cross-module-log/templates/cross-module-log-template.md
1 1 # 跨模块改动日志 — {{module_name}}
2 2  
3   -软规则 S2:本模块开发期间对**非当前模块**代码的改动(无论目标模块是否已 MR merged)记录在此;模块完成报告必须单列「跨模块改动」节完整贴入。漏留痕或未评估影响 → 升级为中断。
  3 +软规则 S2:本模块开发期间对**非当前模块**代码的改动(无论目标模块是否已打里程碑)记录在此;模块完成报告必须单列「跨模块改动」节完整贴入。漏留痕或未评估影响 → 升级为中断。
4 4  
5 5 **本日志由 CC 自主维护**——hook `log-cross-module.sh` 自动落存根(含 `TBD(CC 补)` 占位),CC 调 `cross-module-log` skill 自主推断补「原因 / 影响评估」两列。**不需要人工填写**。
6 6  
... ...
skills/crosscut/plan-start/SKILL.md
... ... @@ -51,14 +51,14 @@ cat &quot;${CLAUDE_PLUGIN_ROOT}/skills/crosscut/plan-start/banners/flow-overview.txt&quot;
51 51 ⚠️ 进入 B 阶段前必须完成:
52 52 1. 人工通读 docs/* + CLAUDE.md + sql/migrations/V1 + 各 scripts/*
53 53  
54   - 2. 把全部 Plan 产物 commit
  54 + 2. 把全部 Plan 产物 commit 到本地默认分支(main / master)
55 55 git add -A && git commit -m "chore: plan phase A0~A5 done"
56 56  
57   - 3. 推到远程:
58   - git remote add origin <gitlab-url> # 若尚未添加
59   - git -c core.hooksPath=/dev/null push -u origin master
  57 + 3. B 阶段全程纯本地(无需远程仓库 / push / MR):
  58 + 每个模块由 milestone-tag 本地 merge 进默认分支并打 milestone/<id> tag。
  59 + 确认当前已在本地默认分支(main / master)上即可。
60 60  
61   - 4. main(或 master)就绪后,再运行 /erp-workflow:coding-start
  61 + 4. 运行 /erp-workflow:coding-start 进入 B 阶段
62 62 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
63 63 ```
64 64  
... ...
skills/plan/downstream-gen/SKILL.md
... ... @@ -122,30 +122,10 @@ cp &quot;${CLAUDE_SKILL_DIR}/templates/docs-10-header-template.md&quot; docs/10-验收检
122 122 ⚠️ 进入 B 阶段前必须完成:
123 123 1. 审核 docs/01~10 + CLAUDE.md + sql/migrations/V1 + 各 scripts/*
124 124  
125   - 2. 把全部 Plan 产物 commit
  125 + 2. 把全部 Plan 产物 commit 到本地默认分支(main / master)
126 126 git add -A && git commit -m "chore: plan phase done"
127 127  
128   - 3. 推到远程,按仓库状态二选一:
129   -
130   - 情况 A — 远程仓库是全新的(尚无 main / master):
131   - git remote add origin <gitlab-url> # 若尚未添加
132   - git -c core.hooksPath=/dev/null push -u origin master
133   -
134   - 情况 B — 远程已有 main 需要走 MR 审核:
135   - git checkout -b plan-init
136   - git push -u origin plan-init
137   - # 在 GitLab 打开 plan-init → main 的 MR,审核并合并
138   -
139   - 4. 补齐 `.env.local` 三个 GITLAB_* 字段
140   -
141   - - `GITLAB_TOKEN`:去 GitLab Profile → Account → Private token 生成后粘贴
142   - - `GITLAB_PROJECT_ID`,`GITLAB_API_URL`:按平台运行(脚本只依赖 git)
143   - macOS / Linux:
144   - bash <plugin-skill-dir>/scripts/derive-gitlab.sh
145   - Windows (PowerShell 5.1+,系统自带,无需额外安装):
146   - powershell -NoProfile -ExecutionPolicy Bypass -File <plugin-skill-dir>/scripts/derive-gitlab.ps1
147   -
148   - 5. remote git 就绪后,再运行 /erp-workflow:coding-start
  128 + 3. 运行 /erp-workflow:coding-start 进入 B 阶段
149 129 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
150 130 ```
151 131  
... ... @@ -157,4 +137,3 @@ cp &quot;${CLAUDE_SKILL_DIR}/templates/docs-10-header-template.md&quot; docs/10-验收检
157 137 - `${CLAUDE_SKILL_DIR}/templates/docs-06-module-pagelist-template.md`(追加到 docs/06 § 三)
158 138 - `${CLAUDE_SKILL_DIR}/templates/docs-08-module-row-template.md`(模块 bullet 行模板)
159 139 - `${CLAUDE_SKILL_DIR}/templates/docs-10-header-template.md`
160   -- `${CLAUDE_SKILL_DIR}/scripts/derive-gitlab.sh` / `derive-gitlab.ps1`(**用户可选辅助**:在 add origin 之后手动跑一次,自动派生 GITLAB_PROJECT_ID / GITLAB_API_URL 写入 .env.local;`.sh` 给 macOS/Linux,`.ps1` 给 Windows,两份严格等价 — 改动必须同步双方)
... ...
skills/plan/downstream-gen/scripts/derive-gitlab.ps1 deleted
1   -#!/usr/bin/env pwsh
2   -# derive-gitlab.ps1 — Windows 对应版(PowerShell 5.1+ 原生可跑,无外部依赖)
3   -# 与同目录 derive-gitlab.sh 严格等价 — 改动任一份必须同步对方。
4   -#
5   -# 用法: powershell -NoProfile -ExecutionPolicy Bypass -File derive-gitlab.ps1 [.env.local 路径]
6   -#
7   -# 派生字段、退出码、回填策略 见 derive-gitlab.sh 头部注释。
8   -
9   -[CmdletBinding()]
10   -param([string]$EnvFile = '.env.local')
11   -
12   -# 让 Chinese 输出在 cmd / PowerShell 控制台正常显示
13   -try { [Console]::OutputEncoding = [System.Text.Encoding]::UTF8 } catch {}
14   -
15   -if (-not (Test-Path -LiteralPath $EnvFile -PathType Leaf)) {
16   - [Console]::Error.WriteLine("derive-gitlab.ps1: env file not found: $EnvFile")
17   - exit 2
18   -}
19   -
20   -# ---- 取 origin URL ----
21   -$url = ''
22   -try {
23   - $raw = & git remote get-url origin 2>$null
24   - if ($LASTEXITCODE -eq 0 -and $raw) { $url = ($raw -join '').Trim() }
25   -} catch { $url = '' }
26   -
27   -if ([string]::IsNullOrEmpty($url)) {
28   - [Console]::Error.WriteLine("derive-gitlab.ps1: 未配置 origin 远程,GITLAB_* 留给用户手填")
29   - exit 0
30   -}
31   -
32   -# ---- 仅支持 http(s) ----
33   -$scheme = $null
34   -if ($url.StartsWith('https://')) { $scheme = 'https' }
35   -elseif ($url.StartsWith('http://')) { $scheme = 'http' }
36   -else {
37   - [Console]::Error.WriteLine("derive-gitlab.ps1: origin 不是 http(s) URL ($url),跳过派生")
38   - exit 0
39   -}
40   -
41   -$rest = $url.Substring("${scheme}://".Length)
42   -$slashIdx = $rest.IndexOf('/')
43   -if ($slashIdx -lt 0) {
44   - [Console]::Error.WriteLine("derive-gitlab.ps1: origin URL 缺少路径段 ($url),跳过派生")
45   - exit 0
46   -}
47   -$gitlabHost = $rest.Substring(0, $slashIdx)
48   -$pathRaw = $rest.Substring($slashIdx + 1)
49   -if ($pathRaw.EndsWith('.git')) { $pathRaw = $pathRaw.Substring(0, $pathRaw.Length - 4) }
50   -$repoName = Split-Path -Leaf $pathRaw
51   -
52   -$apiUrl = "${scheme}://${gitlabHost}/api/v3"
53   -
54   -# ---- 读 .env.local 全文,按原行尾切分 ----
55   -$rawBytes = [System.IO.File]::ReadAllBytes($EnvFile)
56   -$hasBom = ($rawBytes.Length -ge 3 -and $rawBytes[0] -eq 0xEF -and $rawBytes[1] -eq 0xBB -and $rawBytes[2] -eq 0xBF)
57   -$rawText = if ($hasBom) {
58   - [System.Text.Encoding]::UTF8.GetString($rawBytes, 3, $rawBytes.Length - 3)
59   -} else {
60   - [System.Text.Encoding]::UTF8.GetString($rawBytes)
61   -}
62   -$eol = if ($rawText -match "`r`n") { "`r`n" } else { "`n" }
63   -$hadTrailingNewline = $rawText.EndsWith("`n")
64   -$lines = [System.Collections.Generic.List[string]]::new()
65   -foreach ($l in ($rawText -split "`r?`n")) { $lines.Add($l) | Out-Null }
66   -if ($hadTrailingNewline -and $lines.Count -gt 0 -and $lines[$lines.Count - 1] -eq '') {
67   - $lines.RemoveAt($lines.Count - 1)
68   -}
69   -
70   -function Get-FieldStripped {
71   - param([string]$Key)
72   - for ($i = 0; $i -lt $script:lines.Count; $i++) {
73   - $ln = $script:lines[$i]
74   - if ($ln.StartsWith("$Key=")) {
75   - $val = $ln.Substring($Key.Length + 1)
76   - # 剥外层单/双引号
77   - if ($val.Length -ge 2) {
78   - $f = $val[0]; $l = $val[$val.Length - 1]
79   - if (($f -eq "'" -and $l -eq "'") -or ($f -eq '"' -and $l -eq '"')) {
80   - $val = $val.Substring(1, $val.Length - 2)
81   - }
82   - }
83   - return @{ Found = $true; Index = $i; Stripped = $val }
84   - }
85   - }
86   - return @{ Found = $false }
87   -}
88   -
89   -function Update-Field {
90   - param([string]$Key, [string]$NewVal)
91   - $info = Get-FieldStripped -Key $Key
92   - if (-not $info.Found) {
93   - [Console]::Error.WriteLine(" $Key = (.env.local 中无此行,跳过)")
94   - return
95   - }
96   - $stripped = $info.Stripped
97   - if ([string]::IsNullOrEmpty($stripped) -or $stripped -eq 'TBD(A5 自动补)') {
98   - $script:lines[$info.Index] = "$Key=$NewVal"
99   - $script:modified = $true
100   - Write-Host " $Key = $NewVal [已派生填入]"
101   - } elseif ($stripped -eq $NewVal) {
102   - Write-Host " $Key = $NewVal [已是派生值,无需更新]"
103   - } else {
104   - Write-Host " $Key = $stripped [保留用户手填,未覆盖派生值 $NewVal]"
105   - }
106   -}
107   -
108   -function Report-Token {
109   - $info = Get-FieldStripped -Key 'GITLAB_TOKEN'
110   - if (-not $info.Found) {
111   - [Console]::Error.WriteLine(" GITLAB_TOKEN = (.env.local 中无此行,跳过)")
112   - return
113   - }
114   - $stripped = $info.Stripped
115   - if ([string]::IsNullOrEmpty($stripped) -or $stripped.StartsWith('【人工填写:') -or $stripped.StartsWith('TBD')) {
116   - Write-Host " GITLAB_TOKEN = $stripped [待人工填写:GitLab Profile → Account → Private token]"
117   - } else {
118   - $masked = if ($stripped.Length -le 8) {
119   - ('*' * $stripped.Length)
120   - } else {
121   - $stripped.Substring(0, 4) + ('*' * ($stripped.Length - 8)) + $stripped.Substring($stripped.Length - 4)
122   - }
123   - Write-Host " GITLAB_TOKEN = $masked [已填入,长度 $($stripped.Length)]"
124   - }
125   -}
126   -
127   -$script:modified = $false
128   -
129   -Write-Host "derive-gitlab.ps1: 从 origin ($url) 派生 GitLab 凭据:"
130   -Update-Field -Key 'GITLAB_API_URL' -NewVal $apiUrl
131   -
132   -# ---- GITLAB_PROJECT_ID:经 GitLab API 解析数字 ID ----
133   -$tokenInfo = Get-FieldStripped -Key 'GITLAB_TOKEN'
134   -$tokenVal = if ($tokenInfo.Found) { $tokenInfo.Stripped } else { '' }
135   -
136   -$tokenUsable = $true
137   -if ([string]::IsNullOrEmpty($tokenVal) -or $tokenVal.StartsWith('【人工填写:') -or $tokenVal.StartsWith('TBD')) {
138   - Write-Host " GITLAB_PROJECT_ID = TBD [token 未填,跳过 API 解析;填完 token 后重跑此脚本]"
139   - $tokenUsable = $false
140   -}
141   -
142   -if ($tokenUsable) {
143   - # PS 5.1 默认 TLS1.0/1.1,自建 GitLab 通常需要 TLS1.2
144   - try { [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 } catch {}
145   - $headers = @{ 'PRIVATE-TOKEN' = $tokenVal }
146   -
147   - $userOk = $false
148   - try {
149   - $userResp = Invoke-WebRequest -Uri "$apiUrl/user" -Headers $headers -UseBasicParsing -ErrorAction Stop
150   - if ([int]$userResp.StatusCode -eq 200) { $userOk = $true }
151   - else { Write-Host " GITLAB_PROJECT_ID = TBD [token 验证失败 HTTP $([int]$userResp.StatusCode),留 TBD 待人工确认]" }
152   - } catch {
153   - $code = 0
154   - if ($_.Exception.Response) { try { $code = [int]$_.Exception.Response.StatusCode } catch {} }
155   - if ($code -eq 0) { $code = '000' }
156   - Write-Host " GITLAB_PROJECT_ID = TBD [token 验证失败 HTTP $code,留 TBD 待人工确认]"
157   - }
158   -
159   - if ($userOk) {
160   - try {
161   - $searchUri = "$apiUrl/projects?search=$([uri]::EscapeDataString($repoName))&simple=true&per_page=50"
162   - $projects = Invoke-RestMethod -Uri $searchUri -Headers $headers -UseBasicParsing -ErrorAction Stop
163   - $match = $projects | Where-Object { $_.path_with_namespace -eq $pathRaw } | Select-Object -First 1
164   - if ($match) {
165   - Update-Field -Key 'GITLAB_PROJECT_ID' -NewVal "$($match.id)"
166   - } else {
167   - Write-Host " GITLAB_PROJECT_ID = TBD [API 未匹配 path_with_namespace=$pathRaw,请到 GitLab 项目设置页查数字 ID 后填入]"
168   - }
169   - } catch {
170   - Write-Host " GITLAB_PROJECT_ID = TBD [API 调用失败:$($_.Exception.Message)]"
171   - }
172   - }
173   -}
174   -
175   -Report-Token
176   -
177   -# ---- 回写 .env.local(保持 EOL / BOM 状态)----
178   -if ($script:modified) {
179   - $newText = [string]::Join($eol, $lines.ToArray())
180   - if ($hadTrailingNewline) { $newText += $eol }
181   - $encoding = New-Object System.Text.UTF8Encoding($hasBom)
182   - [System.IO.File]::WriteAllText($EnvFile, $newText, $encoding)
183   -}
skills/plan/downstream-gen/scripts/derive-gitlab.sh deleted
1   -#!/usr/bin/env bash
2   -# derive-gitlab.sh — 从 git origin 远程派生 GitLab 凭据并回填 .env.local
3   -# macOS / Linux 用此版本;Windows 用同目录 derive-gitlab.ps1。
4   -# 两份脚本严格等价 — 改动任一份必须同步对方。
5   -#
6   -# 用法: bash derive-gitlab.sh [.env.local 路径,默认 .env.local]
7   -#
8   -# 派生字段:
9   -# GITLAB_API_URL = <scheme>://<host>/api/v3
10   -# GITLAB_PROJECT_ID = 通过 GitLab API(GET /projects?search=...)解析得到的项目数字 ID
11   -# 要求 GITLAB_TOKEN 已填且有效;token 缺失 / 验证失败 / 未匹配时留 TBD
12   -#
13   -# 仅当字段值为 TBD(A5 自动补) 或空时回填;用户手填值不动。
14   -# 仅支持 http(s) origin URL;其他协议(ssh / git@)跳过。
15   -# GITLAB_TOKEN 不派生,留给用户手填。
16   -#
17   -# 退出码:
18   -# 0 = 派生完成或主动跳过(origin 不存在 / 协议不支持)
19   -# 2 = .env.local 路径错
20   -
21   -set -uo pipefail
22   -
23   -ENV_FILE=${1:-.env.local}
24   -[ -f "$ENV_FILE" ] || { echo "derive-gitlab.sh: env file not found: $ENV_FILE" >&2; exit 2; }
25   -
26   -URL=$(git remote get-url origin 2>/dev/null || true)
27   -if [ -z "$URL" ]; then
28   - echo "derive-gitlab.sh: 未配置 origin 远程,GITLAB_* 留给用户手填" >&2
29   - exit 0
30   -fi
31   -
32   -case "$URL" in
33   - https://*) SCHEME=https ;;
34   - http://*) SCHEME=http ;;
35   - *)
36   - echo "derive-gitlab.sh: origin 不是 http(s) URL ($URL),跳过派生" >&2
37   - exit 0
38   - ;;
39   -esac
40   -
41   -REST=${URL#${SCHEME}://}
42   -HOST=${REST%%/*}
43   -PATH_RAW=${REST#*/}
44   -PATH_RAW=${PATH_RAW%.git}
45   -REPO_NAME=$(basename "$PATH_RAW")
46   -
47   -API_URL="${SCHEME}://${HOST}/api/v3"
48   -
49   -update_field() {
50   - local key=$1 newval=$2
51   - local line
52   - line=$(grep -E "^${key}=" "$ENV_FILE" | head -1)
53   - if [ -z "$line" ]; then
54   - echo " ${key} = (.env.local 中无此行,跳过)" >&2
55   - return
56   - fi
57   - local current=${line#${key}=}
58   - # 剥外层单/双引号再比较,模板里 TBD(A5 自动补) 因含空格/括号必须加引号才能被 source
59   - local stripped=$current
60   - case "$stripped" in
61   - \'*\') stripped=${stripped#\'}; stripped=${stripped%\'} ;;
62   - \"*\") stripped=${stripped#\"}; stripped=${stripped%\"} ;;
63   - esac
64   - if [ -z "$stripped" ] || [ "$stripped" = "TBD(A5 自动补)" ]; then
65   - sed -i.bak -E "s|^${key}=.*$|${key}=${newval}|" "$ENV_FILE" && rm -f "${ENV_FILE}.bak"
66   - echo " ${key} = ${newval} [已派生填入]"
67   - elif [ "$stripped" = "$newval" ]; then
68   - echo " ${key} = ${newval} [已是派生值,无需更新]"
69   - else
70   - echo " ${key} = ${stripped} [保留用户手填,未覆盖派生值 ${newval}]"
71   - fi
72   -}
73   -
74   -report_token() {
75   - local key=GITLAB_TOKEN
76   - local line
77   - line=$(grep -E "^${key}=" "$ENV_FILE" | head -1)
78   - if [ -z "$line" ]; then
79   - echo " ${key} = (.env.local 中无此行,跳过)" >&2
80   - return
81   - fi
82   - local current=${line#${key}=}
83   - local stripped=$current
84   - case "$stripped" in
85   - \'*\') stripped=${stripped#\'}; stripped=${stripped%\'} ;;
86   - \"*\") stripped=${stripped#\"}; stripped=${stripped%\"} ;;
87   - esac
88   - case "$stripped" in
89   - ""|"【人工填写:"*|"TBD"*)
90   - echo " ${key} = ${stripped} [待人工填写:GitLab Profile → Account → Private token]"
91   - ;;
92   - *)
93   - local masked
94   - if [ ${#stripped} -le 8 ]; then
95   - masked=$(printf '%*s' ${#stripped} '' | tr ' ' '*')
96   - else
97   - masked="${stripped:0:4}$(printf '%*s' $((${#stripped}-8)) '' | tr ' ' '*')${stripped: -4}"
98   - fi
99   - echo " ${key} = ${masked} [已填入,长度 ${#stripped}]"
100   - ;;
101   - esac
102   -}
103   -
104   -echo "derive-gitlab.sh: 从 origin ($URL) 派生 GitLab 凭据:"
105   -update_field GITLAB_API_URL "$API_URL"
106   -
107   -# GITLAB_PROJECT_ID:通过 GitLab API 解析数字 ID(要求 token 已填且有效)
108   -TOKEN_LINE=$(grep -E '^GITLAB_TOKEN=' "$ENV_FILE" | head -1)
109   -TOKEN_VAL=${TOKEN_LINE#GITLAB_TOKEN=}
110   -case "$TOKEN_VAL" in
111   - \'*\') TOKEN_VAL=${TOKEN_VAL#\'}; TOKEN_VAL=${TOKEN_VAL%\'} ;;
112   - \"*\") TOKEN_VAL=${TOKEN_VAL#\"}; TOKEN_VAL=${TOKEN_VAL%\"} ;;
113   -esac
114   -
115   -case "$TOKEN_VAL" in
116   - ""|"【人工填写:"*|"TBD"*)
117   - echo " GITLAB_PROJECT_ID = TBD [token 未填,跳过 API 解析;填完 token 后重跑此脚本]"
118   - ;;
119   - *)
120   - USER_HTTP=$(curl -sS -o /dev/null -w '%{http_code}' --header "PRIVATE-TOKEN: $TOKEN_VAL" "$API_URL/user" 2>/dev/null || echo "000")
121   - if [ "$USER_HTTP" != "200" ]; then
122   - echo " GITLAB_PROJECT_ID = TBD [token 验证失败 HTTP $USER_HTTP,留 TBD 待人工确认]"
123   - else
124   - SEARCH_RESP=$(curl -sS --header "PRIVATE-TOKEN: $TOKEN_VAL" \
125   - "$API_URL/projects?search=$REPO_NAME&simple=true&per_page=50" 2>/dev/null || echo "[]")
126   - NUMERIC_ID=$(echo "$SEARCH_RESP" | jq -r --arg p "$PATH_RAW" \
127   - '.[] | select(.path_with_namespace == $p) | .id' 2>/dev/null | head -1)
128   - if [ -n "$NUMERIC_ID" ]; then
129   - update_field GITLAB_PROJECT_ID "$NUMERIC_ID"
130   - else
131   - echo " GITLAB_PROJECT_ID = TBD [API 未匹配 path_with_namespace=$PATH_RAW,请到 GitLab 项目设置页查数字 ID 后填入]"
132   - fi
133   - fi
134   - ;;
135   -esac
136   -
137   -report_token
skills/plan/downstream-gen/templates/docs-02-template.md
... ... @@ -10,7 +10,7 @@
10 10  
11 11 ## 二、开发顺序清单(CC 分发权威)
12 12  
13   -> 本清单由 A5 `downstream-gen` 一次性生成。**每行是一个 REQ**,不是模块。CC 按表格行序从上到下扫描,对每个 REQ 所属模块查 `docs/08 § 二` 的 `MR:` 字段 + GitLab API `state`:`merged` 跳过,其他(`—` / opened / closed / 查不到)选为当前模块;`module-start` 会把该模块的所有 REQ 一次做完。
  13 +> 本清单由 A5 `downstream-gen` 一次性生成。**每行是一个 REQ**,不是模块。CC 按表格行序从上到下扫描,对每个 REQ 所属模块查 `docs/08 § 二` 的 `里程碑:` 字段 + 本地 `git tag -l 'milestone/<id>'`:tag 存在则跳过,否则(`—` / tag 不存在)选为当前模块;`module-start` 会把该模块的所有 REQ 一次做完。
14 14 >
15 15 > **约束**:同一模块的所有 REQ 必须**连续排列**。允许打破依赖拓扑(如环依赖、业务必须先做),但必须在「备注」列写明原因。
16 16  
... ... @@ -20,7 +20,7 @@
20 20 | {{index}} | **{{req_id}}** | {{module_id}} | {{rationale}} | {{note}} |
21 21 {{/each}}
22 22  
23   -> **后端模块全部 merged 后**:用户重跑 `/erp-workflow:coding-start` → coding-start 检测到 `backend_done=true && frontend_done=false` → 派发 `frontend-start`。`frontend-start` 步骤 1 自带 prototype/ 门禁(≥ 1 个 `*.html` mockup,缺失则 AskUserQuestion 提示用户补齐)。前端阶段以业务功能(不是 HTML 文件数)为粒度拆分 FE,每个 FE 跑一次 feature 循环(fe-feature-*),最后整个阶段合 1 个 MR(分支 `frontend-phase`,记录在 `docs/08 § 三 整体 MR`)。
  23 +> **后端模块全部打里程碑后**:milestone-tag 自动回调 `coding-start` → coding-start 检测到 `backend_done=true && frontend_done=false` → 派发 `frontend-start`。`frontend-start` 步骤 1 自带 prototype/ 门禁(≥ 1 个 `*.html` mockup,缺失则 AskUserQuestion 提示用户补齐)。前端阶段以业务功能(不是 HTML 文件数)为粒度拆分 FE,每个 FE 跑一次 feature 循环(fe-feature-*),最后整个阶段打 1 个里程碑 tag(分支 `frontend-phase`,记录在 `docs/08 § 三 整体里程碑`)。
24 24  
25 25 ## 三、关键说明
26 26 {{notes}}
... ...
skills/plan/downstream-gen/templates/docs-08-module-row-template.md
1 1 - {{module_id}} {{module_name}}
2 2 - 依赖: {{depends_on}}
3 3 - 路径: {{path_scopes}}
4   - - MR: —
  4 + - 里程碑: —
5 5 - 功能:
6 6 {{req_checklist}}
... ...
skills/plan/project-init/templates/CLAUDE-template.md
... ... @@ -21,8 +21,8 @@ B 阶段分两段,**全部固化到 skills**。入口:`/erp-workflow:coding-
21 21  
22 22 `coding-start` 每次入口做两段完成性检查后真值表派发:
23 23  
24   -- 后端完成性检查 → `backend_done`(扫 docs/08 § 二 + GitLab state)
25   -- 前端完成性检查 → `frontend_done`(扫 docs/08 § 三 整体 MR + state)
  24 +- 后端完成性检查 → `backend_done`(扫 docs/08 § 二 里程碑字段 + `git tag -l`)
  25 +- 前端完成性检查 → `frontend_done`(扫 docs/08 § 三 整体里程碑 + `git tag -l`)
26 26  
27 27 | `backend_done` | `frontend_done` | 派发 |
28 28 |---|---|---|
... ... @@ -32,33 +32,33 @@ B 阶段分两段,**全部固化到 skills**。入口:`/erp-workflow:coding-
32 32  
33 33 前端阶段前置(prototype/ 门禁)由 `frontend-start` 自带,不在 coding-start。`module-start` 与 `frontend-start` **互不感知对方**。
34 34  
35   -### 后端阶段(每模块一个 MR
  35 +### 后端阶段(每模块一个里程碑 tag
36 36  
37   -- **模块循环(外)**:`module-start` → `test-gate(phase=backend)` → `module-report` → `mr-create` → 人工 Approve MR → 用户重跑 coding-start → coding-start 再次路由
  37 +- **模块循环(外)**:`module-start` → `test-gate(phase=backend)` → `module-report` → `milestone-tag`(本地 merge 进默认分支 + 打 `milestone/<id>` tag)→ 自动回调 coding-start 路由下一阶段(无人工介入)
38 38 - **功能循环(内,每 REQ-XXX-NNN 一遍)**:`feature-brainstorm` → `feature-plan` → `feature-tdd` → `feature-verify` → `feature-review`
39 39 - 后端阶段任务严格落在 `backend/` 路径下;docs/01 REQ 卡片的 UI 描述在此阶段忽略,UI 推迟到前端阶段。
40 40  
41   -### 前端阶段(整体一个 MR,所有后端模块 merged 后启动)
  41 +### 前端阶段(整体一个里程碑 tag,所有后端模块打里程碑后启动)
42 42  
43   -- **FE 清单(AI 自主推导,无审阅断点)**:`frontend-start` 进入时扫 prototype + docs/01 + docs/05 → AI 自主推导 FE 业务功能清单写入 `docs/08 § 三`(已有则加载)。**FE 是业务功能粒度,与 prototype HTML 文件数无关**——一个 HTML 可拆多个 FE,多个 HTML 也可合成一个 FE。FE 清单的合理性由 fe-feature-review / mr-create 在整体 MR 提交时一并校核(人工只在 MR Approve+Merge 处介入)。
44   -- **FE 循环(外)**:`frontend-start` → fe-feature 循环 → `test-gate(phase=frontend)` → `module-report(phase=frontend)` → `mr-create`(分支 `frontend-phase`,docs/08 § 三 整体 MR)。
  43 +- **FE 清单(AI 自主推导,无审阅断点)**:`frontend-start` 进入时扫 prototype + docs/01 + docs/05 → AI 自主推导 FE 业务功能清单写入 `docs/08 § 三`(已有则加载)。**FE 是业务功能粒度,与 prototype HTML 文件数无关**——一个 HTML 可拆多个 FE,多个 HTML 也可合成一个 FE。FE 清单的合理性由 fe-feature-review / milestone-tag 在整体里程碑标记时一并校核(全程无人工介入)。
  44 +- **FE 循环(外)**:`frontend-start` → fe-feature 循环 → `test-gate(phase=frontend)` → `module-report(phase=frontend)` → `milestone-tag`(分支 `frontend-phase`,docs/08 § 三 整体里程碑)。
45 45 - **FE 功能循环(内,每个 FE-NN 一遍)**:`fe-feature-brainstorm` → `fe-feature-plan` → `fe-feature-tdd` → `fe-feature-verify` → `fe-feature-review`(专用 `fe-code-reviewer` agent,硬编码 7 维 review checklist)
46 46 - 前端阶段任务严格落在 `frontend/` 路径下;布局以 `prototype/` 为权威。
47 47  
48   -### MR 前测试闸门
  48 +### 里程碑前测试闸门
49 49  
50 50 - `test-gate`:后端阶段子会话跑 `scripts/test.sh`(含本模块新增 + 已合并模块回归);前端阶段子会话跑 vitest + playwright。
51   -- `.githooks/pre-push` 兜底;`git push --no-verify` 被 `deny-no-verify.sh` 硬拦
  51 +- `test-gate` 是打里程碑 tag 前唯一的硬测试门;红色不得跳过进入 `module-report` / `milestone-tag`
52 52  
53 53 ---
54 54  
55 55 ## ✅ 阶段完成判定规则
56 56  
57 57 `docs/08-模块任务管理.md` 分两段:
58   -- `§ 二`:后端模块元数据表(每个模块一行 bullet,记录依赖 / 路径 / MR iid / 功能子项)
59   -- `§ 三`:前端阶段元数据(整体 MR + FE 子项清单,由 `frontend-start` 在所有后端模块 merged 后填入)
  58 +- `§ 二`:后端模块元数据表(每个模块一行 bullet,记录依赖 / 路径 / 里程碑 tag / 功能子项)
  59 +- `§ 三`:前端阶段元数据(整体里程碑 + FE 子项清单,由 `frontend-start` 在所有后端模块打里程碑后填入)
60 60  
61   -**阶段完成判定**统一以 `MR:` 字段(§ 二 各模块) / `整体 MR:` 字段(§ 三)+ `GitLab API state=merged` 判定;子项勾选只作可视化进度,不参与完成判定。
  61 +**阶段完成判定**统一以 `里程碑:` 字段(§ 二 各模块) / `整体里程碑:` 字段(§ 三)+ 本地 `git tag -l 'milestone/<id>'` 判定;子项勾选只作可视化进度,不参与完成判定。
62 62  
63 63 ### 后端模块格式
64 64  
... ... @@ -68,37 +68,36 @@ B 阶段分两段,**全部固化到 skills**。入口:`/erp-workflow:coding-
68 68 - module_0 系统管理
69 69 - 依赖: —
70 70 - 路径: backend/module/sys/
71   - - MR: —
  71 + - 里程碑: —
72 72 - 功能:
73 73 - [ ] REQ-SYS-001 用户登录
74 74 - [ ] REQ-SYS-002 用户注册
75 75 ```
76 76  
77   -- `MR:` 字段由 `mr-create` 在创建 MR 时从 `—` 改为 `!<iid>`。
  77 +- `里程碑:` 字段由 `milestone-tag` 在打里程碑 tag 时从 `—` 改为 `milestone/<module_id>`。
78 78 - 每个 `REQ-*` 子项由 `feature-review` 在 `verdict=approve` 时自动勾选为 `[x]`。
79 79 - 路径限定为后端目录(如 `backend/module/sys/`);前端代码不在此阶段产生。
80 80  
81 81 ### 前端阶段格式(§ 三)
82 82  
83 83 ```markdown
84   -- 整体 MR: —
  84 +- 整体里程碑: —
85 85 - 功能:
86 86 - [ ] FE-01 用户登录与注册 | 关联 REQ:REQ-SYS-001, REQ-SYS-002 | 关联原型:prototype/auth.html
87 87 - [ ] FE-02 仪表盘总览 | 关联 REQ:REQ-DASH-001 | 关联原型:prototype/dashboard.html
88 88 ```
89 89  
90   -- `整体 MR:` 字段由 `mr-create` 在创建前端 MR 时从 `—` 改为 `!<iid>`。
91   -- "功能:" 列表由 `frontend-start` 进入时由 AI 自主推导写入(无人工审阅断点)。FE 是业务功能粒度,与 prototype HTML 文件数无关;合理性由 fe-feature-review / 整体 MR 时统一校核。
  90 +- `整体里程碑:` 字段由 `milestone-tag` 在打前端里程碑 tag 时从 `—` 改为 `milestone/frontend-phase`。
  91 +- "功能:" 列表由 `frontend-start` 进入时由 AI 自主推导写入(无人工审阅断点)。FE 是业务功能粒度,与 prototype HTML 文件数无关;合理性由 fe-feature-review / 整体里程碑标记时统一校核。
92 92 - 每个 `FE-NN` 子项由 `fe-feature-review` 在 `verdict=approve` 时自动勾选为 `[x]`。
93 93 - 进入前端阶段前 `frontend-start` 步骤 1 自带 prototype/ 门禁,强制检查项目根 `prototype/` 至少含 1 个 `*.html` mockup。
94 94  
95 95 ### 状态语义(后端模块 + 前端阶段共用)
96 96  
97   -| `MR:` 字段 | `GitLab API state` | 含义 | 你(Claude Code)的行为 |
  97 +| `里程碑:` 字段 | `git tag -l` | 含义 | 你(Claude Code)的行为 |
98 98 |---|---|---|---|
99   -| `—` | — | 该阶段未开始(未创建 MR) | ✅ 开始该阶段开发 |
100   -| `!<iid>` | `opened` / `closed` | 阶段开发中 / 打回 | ✅ 继续推进该阶段 |
101   -| `!<iid>` | `merged` | 阶段**已完成** | 🟢 后端:进入下一未完成模块;后端全完 → 前端阶段;前端 merged → 全部完成 |
  99 +| `—` | tag 不存在 | 该阶段未开始 / 进行中(未打里程碑) | ✅ 开始 / 继续该阶段开发 |
  100 +| `milestone/<id>` | tag 存在 | 阶段**已完成** | 🟢 后端:进入下一未完成模块;后端全完 → 前端阶段;前端已打里程碑 → 全部完成 |
102 101  
103 102 ### 模块完成报告
104 103  
... ... @@ -133,7 +132,7 @@ B 阶段分两段,**全部固化到 skills**。入口:`/erp-workflow:coding-
133 132 ### 你禁止做的 🚫
134 133  
135 134 1. **主会话直接 `mysql -e` 跑业务 DDL**(只读查询 / 临时本地调试除外)——业务 schema 必须走 `sql/migrations/V_n__*.sql`,详见下方 Schema 演化规约
136   -2. **手动 Edit `docs/08 § 二/§ 三` 的 `MR:` / `整体 MR:` 字段**,必须要由 `mr-create` 自动回写
  135 +2. **手动 Edit `docs/08 § 二/§ 三` 的 `里程碑:` / `整体里程碑:` 字段**,必须要由 `milestone-tag` 自动回写
137 136  
138 137 ### Schema 演化规约(Flyway migration)
139 138  
... ... @@ -167,7 +166,7 @@ B 阶段分两段,**全部固化到 skills**。入口:`/erp-workflow:coding-
167 166 | `docs` | **文档改动**——只动 Markdown / 代码注释,不动实现 |
168 167 | `style` | **格式调整**——空白 / 缩进 / import 顺序,逻辑 0 变化 |
169 168 | `test` | **只动测试代码**——补用例 / 修 fixture,不碰实现 |
170   -| `chore` | **流程维护**——构建 / 依赖 / 工具 / 证据档案 / MR 元数据等非业务动作 |
  169 +| `chore` | **流程维护**——构建 / 依赖 / 工具 / 证据档案 / 里程碑元数据等非业务动作 |
171 170  
172 171 ---
173 172  
... ...
skills/plan/project-init/templates/docs-08-initial-template.md
... ... @@ -2,7 +2,7 @@
2 2  
3 3 > 全流程进度跟踪。CC 每完成一项产出就勾选一项。
4 4 > - **§ 一 Plan(A0~A5)**:`plan-start` 找第一个未勾 A 子项分发到对应 skill
5   -> - **§ 二 Coding(模块)**:分发以 `docs/02-开发计划.md § 二 开发顺序清单` 为准;`coding-start` 按 docs/02 顺序扫描,对每个 REQ 所属模块查询本 § 二的 `MR:` 字段 + GitLab API `state`,找第一个非 merged 模块分发。本 § 二 行序无语义,仅作模块元数据表
  5 +> - **§ 二 Coding(模块)**:分发以 `docs/02-开发计划.md § 二 开发顺序清单` 为准;`coding-start` 按 docs/02 顺序扫描,对每个 REQ 所属模块查询本 § 二的 `里程碑:` 字段 + 本地 `git tag -l 'milestone/<id>'`,找第一个未打里程碑模块分发。本 § 二 行序无语义,仅作模块元数据表
6 6  
7 7 ## 一、Plan 阶段(一次性)
8 8  
... ... @@ -19,7 +19,7 @@
19 19  
20 20 - [ ] A2 骨架生成 — skeleton-gen
21 21 - [ ] 架构文档已生成(docs/04 § 一+、docs/06、docs/07、docs/09)
22   - - [ ] 工具脚本已生成(scripts/*.sh、.githooks/pre-push、.env.local)
  22 + - [ ] 工具脚本已生成(scripts/*.sh、.env.local)
23 23 - [ ] .gitignore 已配置
24 24  
25 25 - [ ] A3 DB 设计 + REQ 回填 — db-design-gen
... ... @@ -43,13 +43,13 @@
43 43  
44 44 ## 二、Coding 阶段(后端模块循环)
45 45  
46   -(A5 填入后,每行一个后端模块。每个模块的 `MR:` 字段在 `—` 和 `!<iid>` 之间变化,完成由 GitLab API `state=merged` 判定。`coding-start` 每次按 docs/02 REQ 序扫每模块的 MR state 决定派发。后端模块全部 merged 后自动进入 § 三 前端阶段。)
  46 +(A5 填入后,每行一个后端模块。每个模块的 `里程碑:` 字段在 `—` 和 `milestone/<id>` 之间变化,完成由本地 `git tag -l` 判定。`coding-start` 每次按 docs/02 REQ 序扫每模块的里程碑 tag 决定派发。后端模块全部打里程碑后自动进入 § 三 前端阶段。)
47 47  
48 48 <!-- 模块格式示例(由 A5 downstream-gen 追加;功能子项由 feature-review 在 approve 时勾选):
49 49 - module_0 系统管理
50 50 - 依赖: —
51 51 - 路径: backend/module/sys/
52   - - MR: —
  52 + - 里程碑: —
53 53 - 功能:
54 54 - [ ] REQ-SYS-001 用户登录
55 55 - [ ] REQ-SYS-002 用户注册
... ... @@ -57,9 +57,9 @@
57 57  
58 58 ## 三、Coding 阶段(前端整体)
59 59  
60   -(`frontend-start` 进入时扫 prototype/ + docs/01 + docs/05 → AI 自主推导 FE 业务功能清单写到下方"功能:"项(无人工审阅断点;合理性由整体 MR 时统一校核)。已有清单则直接加载。整个前端阶段 1 个 MR,分支 `frontend-phase`。)
  60 +(`frontend-start` 进入时扫 prototype/ + docs/01 + docs/05 → AI 自主推导 FE 业务功能清单写到下方"功能:"项(无人工审阅断点;合理性由整体里程碑标记时统一校核)。已有清单则直接加载。整个前端阶段 1 个里程碑 tag,分支 `frontend-phase`。)
61 61  
62   -- 整体 MR: —
  62 +- 整体里程碑: —
63 63 - 功能:
64 64 <!-- AI 进入时按以下行格式写入(每行 1 个 FE,可关联多个 REQ / 多份原型):
65 65 - [ ] FE-NN 功能名 | 关联 REQ:REQ-A, REQ-B | 关联原型:prototype/<file>.html, prototype/<other>.html
... ...
skills/plan/skeleton-gen/SKILL.md
... ... @@ -2,7 +2,7 @@
2 2 name: skeleton-gen
3 3 description: A2 骨架生成——基于 docs/04 § 零 技术栈 + docs/01-需求清单/index.md 模块索引,生成项目专属的架构文档(docs/04 § 一+、docs/06、docs/07、docs/09)和工具脚本。固定工具文件走 cp,架构文档由 LLM 按大纲生成。
4 4 user-invocable: false
5   -allowed-tools: Read Write Edit Skill Grep Glob AskUserQuestion Bash(mkdir *) Bash(cp *) Bash(touch *) Bash(chmod *) Bash(git config *) Bash(cat *) Bash(bash *)
  5 +allowed-tools: Read Write Edit Skill Grep Glob AskUserQuestion Bash(mkdir *) Bash(cp *) Bash(touch *) Bash(chmod *) Bash(cat *) Bash(bash *)
6 6 ---
7 7  
8 8 **所有输出必须使用中文。**
... ... @@ -61,10 +61,9 @@ docs/04 已由 scope-lock 写入 § 零。本步骤追加 § 一 ~ 三。
61 61 #### C.1 复制
62 62  
63 63 ```bash
64   -mkdir -p scripts .githooks sql/migrations src/styles
  64 +mkdir -p scripts sql/migrations src/styles
65 65 touch sql/migrations/.gitkeep
66 66 cp "${CLAUDE_SKILL_DIR}/templates/env-local-template" .env.local
67   -cp "${CLAUDE_SKILL_DIR}/templates/githooks-pre-push-template.sh" .githooks/pre-push
68 67 cp "${CLAUDE_SKILL_DIR}/templates/scripts-setup-test-db-template.sh" scripts/setup-test-db.sh
69 68 cp "${CLAUDE_SKILL_DIR}/templates/styles-tokens-template.css" src/styles/tokens.css
70 69 ```
... ... @@ -85,15 +84,14 @@ cp &quot;${CLAUDE_SKILL_DIR}/templates/styles-tokens-template.css&quot; src/styles/tokens.
85 84 >
86 85 > 表结构异常(列名变更 / 无中文前缀)时停下,用 `AskUserQuestion` 让用户显式确认每 stack 命令。
87 86  
88   -#### C.3 赋权 + 配置 git hooks
  87 +#### C.3 赋权
89 88  
90 89 ```bash
91   -chmod +x scripts/*.sh .githooks/pre-push
92   -git config core.hooksPath .githooks
  90 +chmod +x scripts/*.sh
93 91 ```
94 92  
95 93 完成后,用 `Edit` 在 `docs/08-模块任务管理.md` 中勾选:
96   -- ` - [ ] 工具脚本已生成(scripts/*.sh、.githooks/pre-push、.env.local)`
  94 +- ` - [ ] 工具脚本已生成(scripts/*.sh、.env.local)`
97 95 - ` - [ ] 样式 token 骨架已生成(src/styles/tokens.css)`
98 96  
99 97 ### D. 追加 .gitignore 忽略项
... ... @@ -113,7 +111,7 @@ bash &quot;${CLAUDE_SKILL_DIR}/scripts/merge-gitignore.sh&quot; &quot;${CLAUDE_SKILL_DIR}/templ
113 111  
114 112 用 `Grep` 在以下 8 个路径扫 `【人工填写:`,记录命中(文件 / 行号 / 说明):
115 113 - `docs/04-技术规范.md` / `docs/06-UI交互规范.md` / `docs/07-环境配置.md` / `docs/09-项目目录结构.md`
116   -- `scripts/*.sh` / `.githooks/pre-push` / `.gitignore`
  114 +- `scripts/*.sh` / `.gitignore`
117 115 - `.env.local`
118 116  
119 117 分两组:
... ... @@ -139,7 +137,7 @@ bash &quot;${CLAUDE_SKILL_DIR}/scripts/merge-gitignore.sh&quot; &quot;${CLAUDE_SKILL_DIR}/templ
139 137  
140 138 每次弹 QA 前重扫;有残留则打印残留位置清单(文件:行号 — 说明)+ 再弹 QA。
141 139  
142   -QA 横幅涵盖:产出文件清单(docs/04 / 06 / 07 / 09 + scripts/*.sh + .githooks/pre-push + .env.local + .gitignore)、占位状态(N=0 或待填清单)、「继续」/「有疑问先沟通」两选项。
  140 +QA 横幅涵盖:产出文件清单(docs/04 / 06 / 07 / 09 + scripts/*.sh + .env.local + .gitignore)、占位状态(N=0 或待填清单)、「继续」/「有疑问先沟通」两选项。
143 141  
144 142 通过后(N=0 且用户选「继续」),用 `Edit` 在 `docs/08-模块任务管理.md` 中勾选:
145 143 - `- [ ] A2 骨架生成 — skeleton-gen`
... ... @@ -158,7 +156,6 @@ QA 横幅涵盖:产出文件清单(docs/04 / 06 / 07 / 09 + scripts/*.sh + .
158 156 - `${CLAUDE_SKILL_DIR}/templates/docs-09-structure-template.md`(大纲)
159 157 - `${CLAUDE_SKILL_DIR}/templates/scripts-test-template.sh`(推断命令填充 7 槽:backend/frontend × build/lint/test + e2e;缺席 stack 填 `:`)
160 158 - `${CLAUDE_SKILL_DIR}/templates/scripts-setup-test-db-template.sh`(0 槽位)
161   -- `${CLAUDE_SKILL_DIR}/templates/githooks-pre-push-template.sh`(0 槽位)
162 159 - `${CLAUDE_SKILL_DIR}/templates/env-local-template`(0 槽位)
163 160 - `${CLAUDE_SKILL_DIR}/templates/gitignore-append-template`(0 槽位)
164 161 - `${CLAUDE_SKILL_DIR}/templates/styles-tokens-template.css`(0 槽位,样式 token 骨架)
... ...
skills/plan/skeleton-gen/templates/docs-04-skeleton-template.md
... ... @@ -6,22 +6,26 @@ skeleton-gen 读取 docs/04 § 零(技术栈表)和 docs/01-需求清单/ind
6 6  
7 7 ## 一、后端规范
8 8  
9   -### 1.1 分层结构
  9 +### 1.1 规则
  10 +<!-- 后端通用约定:保留下方占位符不要代填,由人工在 skeleton-gen § E 填写;每条一个 bullet,按需复制本行新增更多。 -->
  11 +- 【人工填写:一条后端通用约定,按需复制本行新增更多;无则填「无」】
  12 +
  13 +### 1.2 分层结构
10 14 <!-- 按 § 零 的后端框架定层次:controller/service/mapper 等;每层职责一句话。 -->
11 15  
12   -### 1.2 命名约定
  16 +### 1.3 命名约定
13 17 <!-- 包名(根包用【人工填写:根包名】占位)/ 类名 / 方法名 / 常量的大小写规则,含 2 个示例。 -->
14 18  
15   -### 1.3 统一响应格式
  19 +### 1.4 统一响应格式
16 20 <!-- 成功/失败的 JSON 结构,错误码段位划分。 -->
17 21  
18   -### 1.4 异常处理
  22 +### 1.5 异常处理
19 23 <!-- 全局异常处理器的使用方式;哪些异常要 catch,哪些禁止;**接口响应禁止回显后端异常堆栈**(返用户友好错误码 + 文案)。 -->
20 24  
21   -### 1.5 事务
  25 +### 1.6 事务
22 26 <!-- 事务边界(通常 service 层);跨服务调用的禁止/替代方案。 -->
23 27  
24   -### 1.6 认证
  28 +### 1.7 认证
25 29 <!-- 基于 § 零 认证方案推导:token 生命周期、刷新机制、密钥管理。 -->
26 30  
27 31 ## 二、前端规范
... ... @@ -62,4 +66,4 @@ skeleton-gen 读取 docs/04 § 零(技术栈表)和 docs/01-需求清单/ind
62 66  
63 67 ### 3.5 配置与安全
64 68 <!-- 配置:DB 连接 / 端口 / 密钥 / 第三方 URL 等一律放 `application.yml` + `.env.local`,代码里**禁止硬编码**。
65   - 前端安全:`localStorage` 不存敏感信息(token / 身份 / 个人数据),推荐 HttpOnly Cookie 或 内存 + 刷新 token 模式;接口响应禁止回显后端异常堆栈(与 § 1.4 一致)。 -->
  69 + 前端安全:`localStorage` 不存敏感信息(token / 身份 / 个人数据),推荐 HttpOnly Cookie 或 内存 + 刷新 token 模式;接口响应禁止回显后端异常堆栈(与 § 1.5 一致)。 -->
... ...
skills/plan/skeleton-gen/templates/docs-07-env-template.md
... ... @@ -3,7 +3,7 @@
3 3 skeleton-gen 基于 docs/04 § 零 技术栈表推导各节内容:
4 4 § 一 依赖清单 → 从技术栈的每一行技术推导运行时和构建依赖
5 5 § 二 端口约定 → 从后端/前端/数据库/缓存/反向代理 各取默认端口
6   - § 四 常用命令 → 基于构建工具、包管理器、MR 工具给出开发者最常用命令
  6 + § 四 常用命令 → 基于构建工具、包管理器给出开发者最常用命令
7 7 -->
8 8  
9 9 # 07-环境配置
... ... @@ -23,4 +23,4 @@ skeleton-gen 基于 docs/04 § 零 技术栈表推导各节内容:
23 23  
24 24 ## 四、常用命令
25 25  
26   -<!-- 表格:| 命令 | 说明 |;包含 启动后端 / 启动前端 / 打包 / 运行测试 / 重置测试数据 / 创建 MR。 -->
  26 +<!-- 表格:| 命令 | 说明 |;包含 启动后端 / 启动前端 / 打包 / 运行测试 / 重置测试数据。 -->
... ...
skills/plan/skeleton-gen/templates/docs-09-structure-template.md
... ... @@ -13,7 +13,7 @@ skeleton-gen 基于 docs/04 § 零 技术栈推导目录树:
13 13  
14 14 ## 一、仓库顶层
15 15  
16   -<!-- 用代码块画出顶层目录树,含 CLAUDE.md / README.md / .env.local / .githooks / scripts / docs / sql / backend / frontend 等。 -->
  16 +<!-- 用代码块画出顶层目录树,含 CLAUDE.md / README.md / .env.local / scripts / docs / sql / backend / frontend 等。 -->
17 17  
18 18 ## 二、后端目录
19 19  
... ...
skills/plan/skeleton-gen/templates/env-local-template
... ... @@ -23,15 +23,3 @@ JWT_SECRET=【人工填写:JWT 签名密钥,256+ bit 随机串】
23 23 # 仅用于你完全可控的测试库;生产/共享库/多人共享的 staging 库**千万别列**。
24 24 # (防护 2 还会检查 schema 名须含 test/_dev/_local/_ci,独立兜底。)
25 25 TEST_DB_ALLOWED_HOSTS=
26   -
27   -# GitLab REST API 接入(mr-create / coding-start / module-start 用 curl 调用,无需 glab CLI):
28   -# - GITLAB_API_URL:GitLab API base。本项目服务器用 v3。A5 `downstream-gen` 从 `git remote get-url origin`
29   -# 自动派生为 `<scheme>://<host>/api/v3`;如派生的 scheme 错(例如远程是 ssh 但实际 web 走 https),手动改掉即可
30   -# - GITLAB_TOKEN:GitLab v3 的 **Private Token**(用户 Profile → Account → Private token 生成;HTTP 调用仍用
31   -# `PRIVATE-TOKEN` 头。v3 token 是全权限、无细粒度 scope)。**无法派生,必须人工填**
32   -# - GITLAB_PROJECT_ID:项目数字 ID(GitLab 项目设置 → General → 顶部 Project ID 字段,纯整数)。
33   -# A5 `downstream-gen` 在 GITLAB_TOKEN 已填的前提下会调 API 自动解析数字 ID 写入;
34   -# token 未填 / API 解析失败时留 TBD,请人工到设置页查到后填入
35   -GITLAB_API_URL='TBD(A5 自动补)'
36   -GITLAB_TOKEN=【人工填写:GitLab Private Token(Profile → Account → Private token)】
37   -GITLAB_PROJECT_ID='TBD(A5 自动补)'
... ...
skills/plan/skeleton-gen/templates/githooks-pre-push-template.sh deleted
1   -#!/usr/bin/env bash
2   -# .githooks/pre-push — run scripts/test.sh before every push.
3   -# No --no-verify: the claude-code hook deny-no-verify.sh also blocks it.
4   -
5   -set -euo pipefail
6   -
7   -cd "$(git rev-parse --show-toplevel)"
8   -
9   -./scripts/test.sh
skills/plan/skeleton-gen/templates/scripts-test-template.sh
1 1 #!/usr/bin/env bash
2 2 # scripts/test.sh —— 合并到默认分支(main / master)前的测试闸门。
3 3 # 顺序:detect → setup-db → build → lint → unit+integration → e2e → reset-db
4   -# 由 .githooks/pre-push 和 test-gate skill(通过子会话)调用。
  4 +# 由 test-gate skill(通过子会话)调用。
5 5  
6 6 set -euo pipefail
7 7  
... ...