Commit 981f6aceb41952b9b41ee6f4624b88ef50d52515
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 | "name": "erp-workflow", | 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 | "version": "0.1.0", | 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,7 +2,7 @@ | ||
| 2 | 2 | ||
| 3 | Claude Code 插件:ERP / 后端管理系统全流程开发框架。 | 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,15 +27,15 @@ Claude Code 插件:ERP / 后端管理系统全流程开发框架。 | ||
| 27 | 27 | ||
| 28 | B-后端(按模块循环) | 28 | B-后端(按模块循环) |
| 29 | 功能循环:Brainstorm → Plan → TDD → Verify → Review | 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 | 入口门禁:检查项目根 prototype/ 至少含 1 个 *.html mockup(缺失则 AskUserQuestion 提示用户补齐) | 35 | 入口门禁:检查项目根 prototype/ 至少含 1 个 *.html mockup(缺失则 AskUserQuestion 提示用户补齐) |
| 36 | - FE 拆分:AI 自主推导功能清单(业务功能粒度,与 HTML 文件数无关)写入 docs/08 § 三;已有则加载——无人工审阅断点(人工只在 MR Approve+Merge 处介入) | 36 | + FE 拆分:AI 自主推导功能清单(业务功能粒度,与 HTML 文件数无关)写入 docs/08 § 三;已有则加载——无人工审阅断点(全程无人工介入) |
| 37 | FE 循环(每个 FE-NN):fe-feature-brainstorm → -plan → -tdd → -verify → -review | 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,7 +66,7 @@ Claude Code 插件:ERP / 后端管理系统全流程开发框架。 | ||
| 66 | ``` | 66 | ``` |
| 67 | /erp-workflow:coding-start | 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 | **路由规则(coding-start 真值表,只做分发)**: | 71 | **路由规则(coding-start 真值表,只做分发)**: |
| 72 | 72 | ||
| @@ -76,19 +76,19 @@ Claude Code 插件:ERP / 后端管理系统全流程开发框架。 | @@ -76,19 +76,19 @@ Claude Code 插件:ERP / 后端管理系统全流程开发框架。 | ||
| 76 | | `true` | `false` | `frontend-start`(写前端) | | 76 | | `true` | `false` | `frontend-start`(写前端) | |
| 77 | | `true` | `true` | 打印"所有阶段已完成",停下 | | 77 | | `true` | `true` | 打印"所有阶段已完成",停下 | |
| 78 | 78 | ||
| 79 | - GitLab API HTTP 非 200 / 查不到 / state 非法 → 停下报错(绝不静默假设未 merged)。 | 79 | + docs/08 里程碑字段与 `git tag -l` 不一致(字段填了但 tag 不存在,或反之)→ 停下报错(绝不静默假设完成状态)。 |
| 80 | 80 | ||
| 81 | **后端阶段(module-start 内,单一职责)**: | 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 | **前端阶段(frontend-start 内,自带前置门禁)**: | 84 | **前端阶段(frontend-start 内,自带前置门禁)**: |
| 85 | - 步骤 1:prototype/ 门禁(≥ 1 个 *.html,缺失则 AskUserQuestion 提示用户补齐 → 停下) | 85 | - 步骤 1:prototype/ 门禁(≥ 1 个 *.html,缺失则 AskUserQuestion 提示用户补齐 → 停下) |
| 86 | - 步骤 2:准备 FE 清单(无审阅断点)。§ 三 占位则 AI 扫 prototype + docs/01 + docs/05 自主推导 FE 业务功能清单写入 § 三(每个 FE 标注关联 REQ + 关联原型;FE 数与 HTML 文件数无关);§ 三 已有则直接加载 | 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,26 +98,24 @@ erp-workflow-plugin/ | ||
| 98 | │ └── plugin.json # 插件清单,声明 skills 四个子目录 | 98 | │ └── plugin.json # 插件清单,声明 skills 四个子目录 |
| 99 | ├── README.md # 本文档 | 99 | ├── README.md # 本文档 |
| 100 | ├── hooks/ | 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 | ├── agents/ | 103 | ├── agents/ |
| 104 | │ ├── superpower-code-reviewer.md # 后端 code-reviewer agent(feature-review 调用) | 104 | │ ├── superpower-code-reviewer.md # 后端 code-reviewer agent(feature-review 调用) |
| 105 | │ └── fe-code-reviewer.md # 前端专用 reviewer(fe-feature-review 调用,硬编码 7 维 review) | 105 | │ └── fe-code-reviewer.md # 前端专用 reviewer(fe-feature-review 调用,硬编码 7 维 review) |
| 106 | └── skills/ | 106 | └── skills/ |
| 107 | ├── plan/ # 阶段 A:6 个一次性规划 skill | 107 | ├── plan/ # 阶段 A:6 个一次性规划 skill |
| 108 | ├── coding/ # 阶段 B:15 个 skill = 9 个后端模块/功能循环 + frontend-start + 5 个 fe-feature-* | 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 | | Hook | 脚本 | 事件 | 触发条件 | 作用 | | 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 | ### Plan 阶段(6 个,`skills/plan/`) | 120 | ### Plan 阶段(6 个,`skills/plan/`) |
| 123 | 121 | ||
| @@ -125,7 +123,7 @@ erp-workflow-plugin/ | @@ -125,7 +123,7 @@ erp-workflow-plugin/ | ||
| 125 | |---|---|---|---| | 123 | |---|---|---|---| |
| 126 | | A0 | `project-init` | • 依赖检查(`mysql` 在 PATH,缺失则尝试自动安装)<br>• 空目录初始化:`cp` 模板创建 CLAUDE.md / docs/01/index.md / docs/08<br>• `git init` | `plan-start` | | 124 | | A0 | `project-init` | • 依赖检查(`mysql` 在 PATH,缺失则尝试自动安装)<br>• 空目录初始化:`cp` 模板创建 CLAUDE.md / docs/01/index.md / docs/08<br>• `git init` | `plan-start` | |
| 127 | | 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 | | 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 | | A3 | `db-design-gen` | • 从 docs/01 REQ 卡片正向设计 `docs/03-数据库设计文档.md`(schema SSoT)<br>• 回填 REQ 卡片依赖表(`TBD(A3 自动补)` → 实际表名)<br>• **停下**等人工审阅 docs/03,审阅完毕用 `/plan-start` 恢复续进 A4 | A2 | | 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 | | 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 | | 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 | | 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 | | 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,10 +136,10 @@ erp-workflow-plugin/ | ||
| 138 | /erp-workflow:coding-start ← 用户每次手动触发;阶段分发器(只做分发) | 136 | /erp-workflow:coding-start ← 用户每次手动触发;阶段分发器(只做分发) |
| 139 | │ | 137 | │ |
| 140 | │ ① Plan 完成校验(docs/08 § 一 A0~A5) | 138 | │ ① Plan 完成校验(docs/08 § 一 A0~A5) |
| 141 | - │ ② 后端完成性检查(§ 二 + GitLab state) | 139 | + │ ② 后端完成性检查(§ 二 + git tag) |
| 142 | │ ├ 未完成 → 立即派发 module-start,结束 | 140 | │ ├ 未完成 → 立即派发 module-start,结束 |
| 143 | │ └ 已完成 → 继续 ③ | 141 | │ └ 已完成 → 继续 ③ |
| 144 | - │ ③ 前端完成性检查(§ 三 整体 MR + state) | 142 | + │ ③ 前端完成性检查(§ 三 整体里程碑 + tag) |
| 145 | │ ├ 已完成 → 打印"所有阶段已完成",结束 | 143 | │ ├ 已完成 → 打印"所有阶段已完成",结束 |
| 146 | │ └ 未完成 → 派发 frontend-start,结束 | 144 | │ └ 未完成 → 派发 frontend-start,结束 |
| 147 | │ | 145 | │ |
| @@ -155,11 +153,10 @@ erp-workflow-plugin/ | @@ -155,11 +153,10 @@ erp-workflow-plugin/ | ||
| 155 | │ │ request-changes (=5) → 停下(升级给人) | 153 | │ │ request-changes (=5) → 停下(升级给人) |
| 156 | │ │ | 154 | │ │ |
| 157 | │ │ 本模块所有 REQ approve: | 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,23 +191,22 @@ erp-workflow-plugin/ | ||
| 194 | │ 全部 FE approve: | 191 | │ 全部 FE approve: |
| 195 | │ test-gate(phase=frontend)(vitest + playwright,子会话跑) | 192 | │ test-gate(phase=frontend)(vitest + playwright,子会话跑) |
| 196 | │ → module-report(phase=frontend) | 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 | | Skill | 做什么 | 谁触发它 | | 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 | | `feature-brainstorm` | 功能循环步骤 1:交互 brainstorm → 生成 `docs/superpowers/specs/*.md` | `module-start` 推进 REQ 时调用 | | 202 | | `feature-brainstorm` | 功能循环步骤 1:交互 brainstorm → 生成 `docs/superpowers/specs/*.md` | `module-start` 推进 REQ 时调用 | |
| 207 | | `feature-plan` | 功能循环步骤 2:spec → 任务级 plan(文件路径 + API 签名 + 测试意图 + 完成判据,代码由 TDD 阶段产出),输出 `docs/superpowers/plans/*.md` | `feature-brainstorm` 链式调用 | | 203 | | `feature-plan` | 功能循环步骤 2:spec → 任务级 plan(文件路径 + API 签名 + 测试意图 + 完成判据,代码由 TDD 阶段产出),输出 `docs/superpowers/plans/*.md` | `feature-brainstorm` 链式调用 | |
| 208 | | `feature-tdd` | 功能循环步骤 3:红绿循环(写失败测试 → 实现 → 子会话验证通过 → commit 到 `module-<id>` 分支);路径硬护栏:`impl_file` 落 `frontend/` 前缀 → 硬停(UI 推迟到前端阶段) | `feature-plan` 链式调用 | | 204 | | `feature-tdd` | 功能循环步骤 3:红绿循环(写失败测试 → 实现 → 子会话验证通过 → commit 到 `module-<id>` 分支);路径硬护栏:`impl_file` 落 `frontend/` 前缀 → 硬停(UI 推迟到前端阶段) | `feature-plan` 链式调用 | |
| 209 | | `feature-verify` | 功能循环步骤 4:将全量测试派发到子会话执行一次,用模板渲染 evidence | `feature-tdd` 链式调用;`feature-review` 在 request-changes 修复后重新调用 | | 205 | | `feature-verify` | 功能循环步骤 4:将全量测试派发到子会话执行一次,用模板渲染 evidence | `feature-tdd` 链式调用;`feature-review` 在 request-changes 修复后重新调用 | |
| 210 | | `feature-review` | 功能循环步骤 5:AI 自审,写 `docs/superpowers/reviews/*.md`。approve → 回 `module-start`;request-changes → 逐项 Edit + fix commit → 回 `feature-verify` 重新执行(最多 5 轮,第 5 轮仍 request-changes 则停下) | `feature-verify` 链式调用 | | 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 | | `module-report` | 中断检查 → 生成 12 节完成报告 `docs/superpowers/module-reports/<date>-<phase_id>.md`(前端阶段 § ④/§ ⑥ 写 N/A)→ commit 到当前分支(后端:module-* 分支;前端:frontend-phase 分支) | `test-gate` 链式调用 | | 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 | | `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 后回调 | | 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 | | `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[] }` | | 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 | | `fe-feature-plan` | 前端功能循环步骤 2:spec → 任务级计划(组件/路由/hook/API client,`impl_file` 必须 `frontend/` 前缀) | `fe-feature-brainstorm` 链式调用 | | 212 | | `fe-feature-plan` | 前端功能循环步骤 2:spec → 任务级计划(组件/路由/hook/API client,`impl_file` 必须 `frontend/` 前缀) | `fe-feature-brainstorm` 链式调用 | |
| @@ -223,7 +219,7 @@ erp-workflow-plugin/ | @@ -223,7 +219,7 @@ erp-workflow-plugin/ | ||
| 223 | | Skill | 作用 | 流程中谁调用 | | 219 | | Skill | 作用 | 流程中谁调用 | |
| 224 | |---|---|---| | 220 | |---|---|---| |
| 225 | | `plan-start` | **A 阶段入口**。读取 docs/08 § 一 找第一个未勾 A 子项 → 派发对应 A skill;A 全部完成时提示运行 coding-start | **用户手动**运行 `/erp-workflow:plan-start` | | 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 | | `interrupt-check` | 检查 CLAUDE.md 的 3 项中断清单;触发则追加 Blocker 到计划文件并停下 | 功能循环各步骤和生成重要制品前自动调用 | | 223 | | `interrupt-check` | 检查 CLAUDE.md 的 3 项中断清单;触发则追加 Blocker 到计划文件并停下 | 功能循环各步骤和生成重要制品前自动调用 | |
| 228 | | `cross-module-log` | 给 `log-cross-module.sh` 追加的跨模块改动存根批量补「原因 / 影响评估」 | `module-report` § ⑦ 硬验收时一次性调用(CC 编辑中途不主动调);`module-start` 初始化日志文件时也会用其模板 | | 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,7 +246,7 @@ step 0 流程图被抽到独立 `.txt` 文件,SKILL.md 步骤 0 改为 `bash cat | ||
| 250 | 246 | ||
| 251 | **字节对齐保证**:每个文件 17 行,每行 visible width = 58 cell(内宽 56 + 2 个 `│` 边框)。改动需重新校准。 | 247 | **字节对齐保证**:每个文件 17 行,每行 visible width = 58 cell(内宽 56 + 2 个 `│` 边框)。改动需重新校准。 |
| 252 | 248 | ||
| 253 | -## Templates 清单(44 份) | 249 | +## Templates 清单(41 份) |
| 254 | 250 | ||
| 255 | | 所属 Skill | 模板文件 | 用途 | | 251 | | 所属 Skill | 模板文件 | 用途 | |
| 256 | |---|---|---| | 252 | |---|---|---| |
| @@ -266,7 +262,6 @@ step 0 流程图被抽到独立 `.txt` 文件,SKILL.md 步骤 0 改为 `bash cat | @@ -266,7 +262,6 @@ step 0 流程图被抽到独立 `.txt` 文件,SKILL.md 步骤 0 改为 `bash cat | ||
| 266 | | skeleton-gen | `docs-09-structure-template.md` | docs/09 目录结构大纲 | | 262 | | skeleton-gen | `docs-09-structure-template.md` | docs/09 目录结构大纲 | |
| 267 | | skeleton-gen | `scripts-setup-test-db-template.sh` | 运行时 drop + create 空库脚本(0 槽位);schema apply 交给 Flyway | | 263 | | skeleton-gen | `scripts-setup-test-db-template.sh` | 运行时 drop + create 空库脚本(0 槽位);schema apply 交给 Flyway | |
| 268 | | skeleton-gen | `scripts-test-template.sh` | test.sh 骨架(4 个命令槽位:{{build_cmd}} / {{lint_cmd}} / {{test_cmd}} / {{e2e_cmd}},由 skeleton-gen 按技术栈推断填充) | | 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 | | skeleton-gen | `env-local-template` | 6 字段凭据模板(DB_* + JWT_SECRET) | | 265 | | skeleton-gen | `env-local-template` | 6 字段凭据模板(DB_* + JWT_SECRET) | |
| 271 | | skeleton-gen | `gitignore-append-template` | 插件推荐忽略项(`.env.local`、`.tmp/`、构建产物等) | | 266 | | skeleton-gen | `gitignore-append-template` | 插件推荐忽略项(`.env.local`、`.tmp/`、构建产物等) | |
| 272 | | db-design-gen | `docs-03-header-template.md` | docs/03 数据库设计头部 | | 267 | | db-design-gen | `docs-03-header-template.md` | docs/03 数据库设计头部 | |
| @@ -285,8 +280,6 @@ step 0 流程图被抽到独立 `.txt` 文件,SKILL.md 步骤 0 改为 `bash cat | @@ -285,8 +280,6 @@ step 0 流程图被抽到独立 `.txt` 文件,SKILL.md 步骤 0 改为 `bash cat | ||
| 285 | | feature-review | `feature-review-template.md` | 自审报告结构 | | 280 | | feature-review | `feature-review-template.md` | 自审报告结构 | |
| 286 | | test-gate | `test-gate-result-template.md` | 闸门结果渲染 | | 281 | | test-gate | `test-gate-result-template.md` | 闸门结果渲染 | |
| 287 | | module-report | `module-report-template.md` | 12 节模块报告 | | 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 | | interrupt-check | `interrupt-block-template.md` | Blocker 节追加模板 | | 283 | | interrupt-check | `interrupt-block-template.md` | Blocker 节追加模板 | |
| 291 | | cross-module-log | `cross-module-log-template.md` | cross-module 日志头(由 hook log-cross-module.sh 在首次跨模块改动时渲染创建;skill 自身不再读取) | | 284 | | cross-module-log | `cross-module-log-template.md` | cross-module 日志头(由 hook log-cross-module.sh 在首次跨模块改动时渲染创建;skill 自身不再读取) | |
| 292 | | cross-module-log | `cross-module-log-row-template.md` | 单条改动行模板 | | 285 | | cross-module-log | `cross-module-log-row-template.md` | 单条改动行模板 | |
| @@ -305,7 +298,7 @@ step 0 流程图被抽到独立 `.txt` 文件,SKILL.md 步骤 0 改为 `bash cat | @@ -305,7 +298,7 @@ step 0 流程图被抽到独立 `.txt` 文件,SKILL.md 步骤 0 改为 `bash cat | ||
| 305 | - **MySQL 8.x** 实例已就绪(推荐本地 / `*.local` host;A4 `db-init` 的安全守护要求 host 在白名单且 schema 名含 `test`/`dev`/`local`,避免误删生产库) | 298 | - **MySQL 8.x** 实例已就绪(推荐本地 / `*.local` host;A4 `db-init` 的安全守护要求 host 在白名单且 schema 名含 `test`/`dev`/`local`,避免误删生产库) |
| 306 | - **`mysql` 命令行**:A4 `db-init` 验证连接 + 自动 `DROP+CREATE` schema 后 apply V1;`scripts/setup-test-db.sh` 在测试闸门前后 drop+create 空库 | 299 | - **`mysql` 命令行**:A4 `db-init` 验证连接 + 自动 `DROP+CREATE` schema 后 apply V1;`scripts/setup-test-db.sh` 在测试闸门前后 drop+create 空库 |
| 307 | - **Spring Boot + Flyway**(**必需**):pom.xml 声明 `flyway-core` + `flyway-mysql`;Spring 启动时自动 apply `sql/migrations/V*.sql`。本插件生成的 `setup-test-db.sh` 只清库,schema 必须由 Flyway 应用 | 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 | - **本地可运行 `mvn test` / `pnpm test`**:测试闸门 `scripts/test.sh` 由 `skeleton-gen` 生成 | 302 | - **本地可运行 `mvn test` / `pnpm test`**:测试闸门 `scripts/test.sh` 由 `skeleton-gen` 生成 |
| 310 | 303 | ||
| 311 | ## 设计原则 | 304 | ## 设计原则 |
hooks/hooks.json
| 1 | { | 1 | { |
| 2 | "hooks": { | 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 | "PostToolUse": [ | 3 | "PostToolUse": [ |
| 12 | { | 4 | { |
| 13 | "matcher": "Edit|Write", | 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 | #!/usr/bin/env bash | 1 | #!/usr/bin/env bash |
| 2 | # PostToolUse hook: 检测 Edit/Write 是否触及"当前模块以外"的模块路径,若是则在当前模块的跨模块日志中留痕(软规则 S2)。 | 2 | # PostToolUse hook: 检测 Edit/Write 是否触及"当前模块以外"的模块路径,若是则在当前模块的跨模块日志中留痕(软规则 S2)。 |
| 3 | -# CC 在当前模块开发期间改动其他模块(无论目标模块是否已 merged)都会在此处留痕。 | 3 | +# CC 在当前模块开发期间改动其他模块(无论目标模块是否已打里程碑)都会在此处留痕。 |
| 4 | 4 | ||
| 5 | set -euo pipefail | 5 | set -euo pipefail |
| 6 | 6 | ||
| @@ -33,7 +33,7 @@ esac | @@ -33,7 +33,7 @@ esac | ||
| 33 | # - module_0 <name> | 33 | # - module_0 <name> |
| 34 | # - 依赖: ... | 34 | # - 依赖: ... |
| 35 | # - 路径: backend/module/xxx/, frontend/pages/xxx/ | 35 | # - 路径: backend/module/xxx/, frontend/pages/xxx/ |
| 36 | -# - MR: !N 或 — | 36 | +# - 里程碑: milestone/<id> 或 — |
| 37 | hit_module="" | 37 | hit_module="" |
| 38 | # 用 awk 逐模块解析:每碰到 `- module_` 记录 module_id($2),然后在其下找第一个 `- 路径:` 行 | 38 | # 用 awk 逐模块解析:每碰到 `- module_` 记录 module_id($2),然后在其下找第一个 `- 路径:` 行 |
| 39 | # current_module 已在上文计算,在外层循环被排除 → 只会命中"非当前模块"的路径 | 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,7 +20,7 @@ allowed-tools: Read Write Edit Skill Agent Bash(git add *) Bash(git commit *) | ||
| 20 | 3. 按 `verdict` 分派: | 20 | 3. 按 `verdict` 分派: |
| 21 | 21 | ||
| 22 | **approve** | 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 | - 输出 `fe-feature-review: <fe_id> round <N> 通过`,调用 `Skill(frontend-start)` 推进下一 FE 或进入 test-gate(phase=frontend) | 24 | - 输出 `fe-feature-review: <fe_id> round <N> 通过`,调用 `Skill(frontend-start)` 推进下一 FE 或进入 test-gate(phase=frontend) |
| 25 | 25 | ||
| 26 | **request-changes(round < 5)** | 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,7 +18,7 @@ allowed-tools: Read Write Edit Skill Agent Bash(git add *) Bash(git commit *) | ||
| 18 | 3. 按 `verdict` 分派: | 18 | 3. 按 `verdict` 分派: |
| 19 | 19 | ||
| 20 | **approve** | 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 | - 输出 `feature-review: <REQ> round <N> 通过`,调用 `Skill(module-start)` | 22 | - 输出 `feature-review: <REQ> round <N> 通过`,调用 `Skill(module-start)` |
| 23 | 23 | ||
| 24 | **request-changes(round < 5)** | 24 | **request-changes(round < 5)** |
skills/coding/frontend-start/SKILL.md
| @@ -2,7 +2,7 @@ | @@ -2,7 +2,7 @@ | ||
| 2 | name: frontend-start | 2 | name: frontend-start |
| 3 | description: 前端阶段循环入口。AI 自主推导 FE 业务功能清单写入 docs/08 § 三(已有则加载),定位未完成 FE 派发 fe-feature-brainstorm 或 test-gate(前端阶段)。幂等可重入。 | 3 | description: 前端阶段循环入口。AI 自主推导 FE 业务功能清单写入 docs/08 § 三(已有则加载),定位未完成 FE 派发 fe-feature-brainstorm 或 test-gate(前端阶段)。幂等可重入。 |
| 4 | user-invocable: false | 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,19 +29,18 @@ allowed-tools: Read Write Edit Skill Glob Grep AskUserQuestion Bash(git branch * | ||
| 29 | - [ ] FE-NN 功能名 | 关联 REQ:REQ-A, REQ-B | 关联原型:prototype/<file>.html | 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 | ### 步骤 4:切到 frontend-phase 分支 | 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 | ### 步骤 5:识别已完成的 FE | 45 | ### 步骤 5:识别已完成的 FE |
| 47 | 46 | ||
| @@ -59,7 +58,7 @@ allowed-tools: Read Write Edit Skill Glob Grep AskUserQuestion Bash(git branch * | @@ -59,7 +58,7 @@ allowed-tools: Read Write Edit Skill Glob Grep AskUserQuestion Bash(git branch * | ||
| 59 | ## 参考 | 58 | ## 参考 |
| 60 | 59 | ||
| 61 | - `${CLAUDE_SKILL_DIR}/templates/frontend-start-banner-template.md` | 60 | - `${CLAUDE_SKILL_DIR}/templates/frontend-start-banner-template.md` |
| 62 | -- `docs/08-模块任务管理.md § 三`(前端阶段元数据:整体 MR + FE 清单) | 61 | +- `docs/08-模块任务管理.md § 三`(前端阶段元数据:整体里程碑 + FE 清单) |
| 63 | - `prototype/`(HTML mockup,FE 拆分粒度与文件数无关) | 62 | - `prototype/`(HTML mockup,FE 拆分粒度与文件数无关) |
| 64 | - `docs/superpowers/reviews/*-FE-*.md`(verdict=approve 即完成) | 63 | - `docs/superpowers/reviews/*-FE-*.md`(verdict=approve 即完成) |
| 65 | - 上游:`coding-start`(步骤 4 派发,仅当后端完成 + 前端未完成);`fe-feature-review` approve 后回调 | 64 | - 上游:`coding-start`(步骤 4 派发,仅当后端完成 + 前端未完成);`fe-feature-review` approve 后回调 |
skills/coding/frontend-start/templates/frontend-start-banner-template.md
| 1 | ## 前端阶段(frontend-phase) | 1 | ## 前端阶段(frontend-phase) |
| 2 | 2 | ||
| 3 | - 分支:frontend-phase | 3 | - 分支:frontend-phase |
| 4 | -- 整体 MR:{{overall_mr}} | 4 | +- 整体里程碑:{{overall_milestone}} |
| 5 | - FE 进度(`x` = 已完成 review approve;FE 是业务功能粒度,与 prototype/ HTML 文件数无关): | 5 | - FE 进度(`x` = 已完成 review approve;FE 是业务功能粒度,与 prototype/ HTML 文件数无关): |
| 6 | {{#each fes}} | 6 | {{#each fes}} |
| 7 | - [{{status}}] {{fe_id}} {{name}} | 关联 REQ:{{reqs}} | 关联原型:{{prototypes}} | 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 | name: module-report | 2 | name: module-report |
| 3 | -description: 本地测试闸门通过后,生成标准化 12 节完成报告(后端模块 OR 前端阶段)并 commit 到当前分支供 MR 嵌入。 | 3 | +description: 本地测试闸门通过后,生成标准化 12 节完成报告(后端模块 OR 前端阶段)并 commit 到当前分支(供里程碑标记)。 |
| 4 | user-invocable: false | 4 | user-invocable: false |
| 5 | allowed-tools: Read Write Glob Grep Skill Bash(git diff *) Bash(git log *) Bash(git add *) Bash(git commit *) Bash(git branch *) | 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,7 +9,7 @@ allowed-tools: Read Write Glob Grep Skill Bash(git diff *) Bash(git log *) Bash( | ||
| 9 | 9 | ||
| 10 | # module-report | 10 | # module-report |
| 11 | 11 | ||
| 12 | -`test-gate` 绿色后渲染 12 节完成报告,commit 到当前分支供 MR 嵌入。**只读摘要,不读 diff 正文进上下文**。 | 12 | +`test-gate` 绿色后渲染 12 节完成报告,commit 到当前分支供里程碑标记。**只读摘要,不读 diff 正文进上下文**。 |
| 13 | 13 | ||
| 14 | 按当前分支自动推断 `phase`: | 14 | 按当前分支自动推断 `phase`: |
| 15 | 15 | ||
| @@ -59,12 +59,12 @@ allowed-tools: Read Write Glob Grep Skill Bash(git diff *) Bash(git log *) Bash( | @@ -59,12 +59,12 @@ allowed-tools: Read Write Glob Grep Skill Bash(git diff *) Bash(git log *) Bash( | ||
| 59 | git add docs/superpowers/module-reports/<phase_id>-cross-module.md | 59 | git add docs/superpowers/module-reports/<phase_id>-cross-module.md |
| 60 | git commit -m "docs(<phase_id>): add completion report + cross-module log" | 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 | - `${CLAUDE_SKILL_DIR}/templates/module-report-template.md`(12 节,后端 + 前端共用) | 68 | - `${CLAUDE_SKILL_DIR}/templates/module-report-template.md`(12 节,后端 + 前端共用) |
| 69 | - 上游:`test-gate`(绿色时派发) | 69 | - 上游:`test-gate`(绿色时派发) |
| 70 | -- 下游:`mr-create`(phase 由当前分支推断) | 70 | +- 下游:`milestone-tag`(phase 由当前分支推断) |
skills/coding/module-report/templates/module-report-template.md
skills/coding/module-start/SKILL.md
| 1 | --- | 1 | --- |
| 2 | name: module-start | 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 | user-invocable: false | 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,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 | ### 步骤 1:定位当前模块与本模块 REQ 列表 | 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 | 找到 `current_module` 后,从 docs/02 § 二 的 REQ 列表里取出所有 `module_id == current_module` 的项,按原序得 `req_list[]`(A5 约束保证同模块 REQ 连续)。模块名、需求卡目录等其它字段由后续步骤按需从 `docs/08 § 二` 或 `docs/01-需求清单/` 取,不在本步骤预读。 | 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 | - 结束本 skill,不派发下游 | 36 | - 结束本 skill,不派发下游 |
| 38 | 37 | ||
| 39 | ### 步骤 3:确保处于模块分支 | 38 | ### 步骤 3:确保处于模块分支 |
| @@ -42,9 +41,9 @@ allowed-tools: Read Write Skill Glob Grep Bash(git branch *) Bash(git checkout * | @@ -42,9 +41,9 @@ allowed-tools: Read Write Skill Glob Grep Bash(git branch *) Bash(git checkout * | ||
| 42 | 41 | ||
| 43 | - 已在该分支 → 继续步骤 4 | 42 | - 已在该分支 → 继续步骤 4 |
| 44 | - 该分支已存在但当前不在 → checkout 过去 | 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 | ### 步骤 4:计算已完成 REQ 集合 `done_reqs[]` | 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,10 +63,10 @@ allowed-tools: Read Write Skill Glob Grep Bash(git branch *) Bash(git checkout * | ||
| 64 | ## 参考 | 63 | ## 参考 |
| 65 | 64 | ||
| 66 | - `docs/02-开发计划.md § 二 开发顺序清单`(分发权威) | 65 | - `docs/02-开发计划.md § 二 开发顺序清单`(分发权威) |
| 67 | -- `docs/08-模块任务管理.md § 二`(后端模块元数据,含 `MR:` 字段;完成判定以 MR state 为准) | 66 | +- `docs/08-模块任务管理.md § 二`(后端模块元数据,含 `里程碑:` 字段;完成判定以 tag 存在为准) |
| 68 | - `docs/superpowers/reviews/*.md`(REQ 级进度事实——verdict=approve 即完成) | 67 | - `docs/superpowers/reviews/*.md`(REQ 级进度事实——verdict=approve 即完成) |
| 69 | - `${CLAUDE_SKILL_DIR}/templates/module-start-banner-template.md` | 68 | - `${CLAUDE_SKILL_DIR}/templates/module-start-banner-template.md` |
| 70 | - 下游: | 69 | - 下游: |
| 71 | - `feature-brainstorm`(每个未完成 REQ) | 70 | - `feature-brainstorm`(每个未完成 REQ) |
| 72 | - `test-gate`(本模块全部 REQ approve 后;phase=backend 由分支推断) | 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 | name: test-gate | 2 | name: test-gate |
| 3 | -description: MR 创建前的硬闸门。后端阶段子会话跑 scripts/test.sh,前端阶段跑前端测试命令;绿则进入 module-report,红则停下并按失败类型引导用户。 | 3 | +description: 打里程碑 tag 前的硬闸门。后端阶段子会话跑 scripts/test.sh,前端阶段跑前端测试命令;绿则进入 module-report,红则停下并按失败类型引导用户。 |
| 4 | user-invocable: false | 4 | user-invocable: false |
| 5 | allowed-tools: Read Write Skill Agent Bash(git add *) Bash(git commit *) Bash(git branch *) | 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,7 +37,7 @@ allowed-tools: Read Write Skill Agent Bash(git add *) Bash(git commit *) Bash(gi | ||
| 37 | } | 37 | } |
| 38 | ``` | 38 | ``` |
| 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`)。 | 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 | ```bash | 41 | ```bash |
| 42 | git add docs/superpowers/module-reports/<phase_id>-test-gate.md | 42 | git add docs/superpowers/module-reports/<phase_id>-test-gate.md |
| 43 | git commit -m "chore(<phase_id>): add local test-gate evidence" | 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,7 +67,7 @@ allowed-tools: Read Write Skill Agent Bash(git add *) Bash(git commit *) Bash(gi | ||
| 67 | ## 护栏 | 67 | ## 护栏 |
| 68 | 68 | ||
| 69 | - **绝不**在主会话直接执行 `./scripts/test.sh` / `pnpm test` / `pnpm e2e`,必须通过子会话 | 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,7 +2,7 @@ | ||
| 2 | name: coding-start | 2 | name: coding-start |
| 3 | description: B 阶段(Coding)入口与阶段分发器。验证 Plan 完成后做后端 + 前端的完成性检查,每段检查后立即派发:后端未完成 → module-start(写后端);后端已完成 + 前端未完成 → frontend-start(写前端);都完成 → 全部完成。本 skill 只做分发,不做 prototype/ 门禁。 | 3 | description: B 阶段(Coding)入口与阶段分发器。验证 Plan 完成后做后端 + 前端的完成性检查,每段检查后立即派发:后端未完成 → module-start(写后端);后端已完成 + 前端未完成 → frontend-start(写前端);都完成 → 全部完成。本 skill 只做分发,不做 prototype/ 门禁。 |
| 4 | user-invocable: true | 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 "${CLAUDE_PLUGIN_ROOT}/skills/crosscut/coding-start/banners/flow-overview.tx | @@ -33,26 +33,25 @@ cat "${CLAUDE_PLUGIN_ROOT}/skills/crosscut/coding-start/banners/flow-overview.tx | ||
| 33 | 33 | ||
| 34 | ### 步骤 3:后端完成性检查 + 派发 | 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 | ### 步骤 4:前端完成性检查 + 派发 | 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 | - `docs/08-模块任务管理.md § 一`(A0~A5 进度勾选,步骤 2 读取) | 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 | - `module-start`(写后端:步骤 3 派发) | 56 | - `module-start`(写后端:步骤 3 派发) |
| 58 | - `frontend-start`(写前端:步骤 4 派发) | 57 | - `frontend-start`(写前端:步骤 4 派发) |
skills/crosscut/coding-start/banners/flow-overview.txt
| @@ -3,10 +3,10 @@ | @@ -3,10 +3,10 @@ | ||
| 3 | │ │ | 3 | │ │ |
| 4 | │ coding-start (只做分发) │ | 4 | │ coding-start (只做分发) │ |
| 5 | │ ① Plan 完成校验(docs/08 § 一 A0~A5) │ | 5 | │ ① Plan 完成校验(docs/08 § 一 A0~A5) │ |
| 6 | -│ ② 后端完成性检查(§ 二 + GitLab state) │ | 6 | +│ ② 后端完成性检查(§ 二 + git tag) │ |
| 7 | │ ├ 未完成 → 立即派发 module-start,结束 │ | 7 | │ ├ 未完成 → 立即派发 module-start,结束 │ |
| 8 | │ └ 已完成 → 继续 ③ │ | 8 | │ └ 已完成 → 继续 ③ │ |
| 9 | -│ ③ 前端完成性检查(§ 三 整体 MR + state) │ | 9 | +│ ③ 前端完成性检查(§ 三 整体里程碑 + tag) │ |
| 10 | │ ├ 已完成 → 打印"全部完成",结束 │ | 10 | │ ├ 已完成 → 打印"全部完成",结束 │ |
| 11 | │ └ 未完成 → 派发 frontend-start,结束 │ | 11 | │ └ 未完成 → 派发 frontend-start,结束 │ |
| 12 | │ │ | 12 | │ │ |
| @@ -38,9 +38,9 @@ | @@ -38,9 +38,9 @@ | ||
| 38 | │ ↓ 本模块所有 REQ approve │ | 38 | │ ↓ 本模块所有 REQ approve │ |
| 39 | │ test-gate(phase=backend) │ | 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 | │ ┌─ 前端功能循环(每 FE-NN)─────┐ │ | 45 | │ ┌─ 前端功能循环(每 FE-NN)─────┐ │ |
| 46 | │ │ fe-feature-brainstorm │ │ | 46 | │ │ fe-feature-brainstorm │ │ |
| @@ -59,8 +59,8 @@ | @@ -59,8 +59,8 @@ | ||
| 59 | │ ↓ 全部 FE approve │ | 59 | │ ↓ 全部 FE approve │ |
| 60 | │ test-gate(phase=frontend) │ | 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 | # 跨模块改动日志 — {{module_name}} | 1 | # 跨模块改动日志 — {{module_name}} |
| 2 | 2 | ||
| 3 | -软规则 S2:本模块开发期间对**非当前模块**代码的改动(无论目标模块是否已 MR merged)记录在此;模块完成报告必须单列「跨模块改动」节完整贴入。漏留痕或未评估影响 → 升级为中断。 | 3 | +软规则 S2:本模块开发期间对**非当前模块**代码的改动(无论目标模块是否已打里程碑)记录在此;模块完成报告必须单列「跨模块改动」节完整贴入。漏留痕或未评估影响 → 升级为中断。 |
| 4 | 4 | ||
| 5 | **本日志由 CC 自主维护**——hook `log-cross-module.sh` 自动落存根(含 `TBD(CC 补)` 占位),CC 调 `cross-module-log` skill 自主推断补「原因 / 影响评估」两列。**不需要人工填写**。 | 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 "${CLAUDE_PLUGIN_ROOT}/skills/crosscut/plan-start/banners/flow-overview.txt" | @@ -51,14 +51,14 @@ cat "${CLAUDE_PLUGIN_ROOT}/skills/crosscut/plan-start/banners/flow-overview.txt" | ||
| 51 | ⚠️ 进入 B 阶段前必须完成: | 51 | ⚠️ 进入 B 阶段前必须完成: |
| 52 | 1. 人工通读 docs/* + CLAUDE.md + sql/migrations/V1 + 各 scripts/* | 52 | 1. 人工通读 docs/* + CLAUDE.md + sql/migrations/V1 + 各 scripts/* |
| 53 | 53 | ||
| 54 | - 2. 把全部 Plan 产物 commit: | 54 | + 2. 把全部 Plan 产物 commit 到本地默认分支(main / master): |
| 55 | git add -A && git commit -m "chore: plan phase A0~A5 done" | 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 "${CLAUDE_SKILL_DIR}/templates/docs-10-header-template.md" docs/10-验收检 | @@ -122,30 +122,10 @@ cp "${CLAUDE_SKILL_DIR}/templates/docs-10-header-template.md" docs/10-验收检 | ||
| 122 | ⚠️ 进入 B 阶段前必须完成: | 122 | ⚠️ 进入 B 阶段前必须完成: |
| 123 | 1. 审核 docs/01~10 + CLAUDE.md + sql/migrations/V1 + 各 scripts/* | 123 | 1. 审核 docs/01~10 + CLAUDE.md + sql/migrations/V1 + 各 scripts/* |
| 124 | 124 | ||
| 125 | - 2. 把全部 Plan 产物 commit: | 125 | + 2. 把全部 Plan 产物 commit 到本地默认分支(main / master): |
| 126 | git add -A && git commit -m "chore: plan phase done" | 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 "${CLAUDE_SKILL_DIR}/templates/docs-10-header-template.md" docs/10-验收检 | @@ -157,4 +137,3 @@ cp "${CLAUDE_SKILL_DIR}/templates/docs-10-header-template.md" docs/10-验收检 | ||
| 157 | - `${CLAUDE_SKILL_DIR}/templates/docs-06-module-pagelist-template.md`(追加到 docs/06 § 三) | 137 | - `${CLAUDE_SKILL_DIR}/templates/docs-06-module-pagelist-template.md`(追加到 docs/06 § 三) |
| 158 | - `${CLAUDE_SKILL_DIR}/templates/docs-08-module-row-template.md`(模块 bullet 行模板) | 138 | - `${CLAUDE_SKILL_DIR}/templates/docs-08-module-row-template.md`(模块 bullet 行模板) |
| 159 | - `${CLAUDE_SKILL_DIR}/templates/docs-10-header-template.md` | 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,7 +10,7 @@ | ||
| 10 | 10 | ||
| 11 | ## 二、开发顺序清单(CC 分发权威) | 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 | > **约束**:同一模块的所有 REQ 必须**连续排列**。允许打破依赖拓扑(如环依赖、业务必须先做),但必须在「备注」列写明原因。 | 15 | > **约束**:同一模块的所有 REQ 必须**连续排列**。允许打破依赖拓扑(如环依赖、业务必须先做),但必须在「备注」列写明原因。 |
| 16 | 16 | ||
| @@ -20,7 +20,7 @@ | @@ -20,7 +20,7 @@ | ||
| 20 | | {{index}} | **{{req_id}}** | {{module_id}} | {{rationale}} | {{note}} | | 20 | | {{index}} | **{{req_id}}** | {{module_id}} | {{rationale}} | {{note}} | |
| 21 | {{/each}} | 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 | {{notes}} | 26 | {{notes}} |
skills/plan/downstream-gen/templates/docs-08-module-row-template.md
skills/plan/project-init/templates/CLAUDE-template.md
| @@ -21,8 +21,8 @@ B 阶段分两段,**全部固化到 skills**。入口:`/erp-workflow:coding- | @@ -21,8 +21,8 @@ B 阶段分两段,**全部固化到 skills**。入口:`/erp-workflow:coding- | ||
| 21 | 21 | ||
| 22 | `coding-start` 每次入口做两段完成性检查后真值表派发: | 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 | | `backend_done` | `frontend_done` | 派发 | | 27 | | `backend_done` | `frontend_done` | 派发 | |
| 28 | |---|---|---| | 28 | |---|---|---| |
| @@ -32,33 +32,33 @@ B 阶段分两段,**全部固化到 skills**。入口:`/erp-workflow:coding- | @@ -32,33 +32,33 @@ B 阶段分两段,**全部固化到 skills**。入口:`/erp-workflow:coding- | ||
| 32 | 32 | ||
| 33 | 前端阶段前置(prototype/ 门禁)由 `frontend-start` 自带,不在 coding-start。`module-start` 与 `frontend-start` **互不感知对方**。 | 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 | - **功能循环(内,每 REQ-XXX-NNN 一遍)**:`feature-brainstorm` → `feature-plan` → `feature-tdd` → `feature-verify` → `feature-review` | 38 | - **功能循环(内,每 REQ-XXX-NNN 一遍)**:`feature-brainstorm` → `feature-plan` → `feature-tdd` → `feature-verify` → `feature-review` |
| 39 | - 后端阶段任务严格落在 `backend/` 路径下;docs/01 REQ 卡片的 UI 描述在此阶段忽略,UI 推迟到前端阶段。 | 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 | - **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) | 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 | - 前端阶段任务严格落在 `frontend/` 路径下;布局以 `prototype/` 为权威。 | 46 | - 前端阶段任务严格落在 `frontend/` 路径下;布局以 `prototype/` 为权威。 |
| 47 | 47 | ||
| 48 | -### MR 前测试闸门 | 48 | +### 里程碑前测试闸门 |
| 49 | 49 | ||
| 50 | - `test-gate`:后端阶段子会话跑 `scripts/test.sh`(含本模块新增 + 已合并模块回归);前端阶段子会话跑 vitest + playwright。 | 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 | `docs/08-模块任务管理.md` 分两段: | 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,37 +68,36 @@ B 阶段分两段,**全部固化到 skills**。入口:`/erp-workflow:coding- | ||
| 68 | - module_0 系统管理 | 68 | - module_0 系统管理 |
| 69 | - 依赖: — | 69 | - 依赖: — |
| 70 | - 路径: backend/module/sys/ | 70 | - 路径: backend/module/sys/ |
| 71 | - - MR: — | 71 | + - 里程碑: — |
| 72 | - 功能: | 72 | - 功能: |
| 73 | - [ ] REQ-SYS-001 用户登录 | 73 | - [ ] REQ-SYS-001 用户登录 |
| 74 | - [ ] REQ-SYS-002 用户注册 | 74 | - [ ] REQ-SYS-002 用户注册 |
| 75 | ``` | 75 | ``` |
| 76 | 76 | ||
| 77 | -- `MR:` 字段由 `mr-create` 在创建 MR 时从 `—` 改为 `!<iid>`。 | 77 | +- `里程碑:` 字段由 `milestone-tag` 在打里程碑 tag 时从 `—` 改为 `milestone/<module_id>`。 |
| 78 | - 每个 `REQ-*` 子项由 `feature-review` 在 `verdict=approve` 时自动勾选为 `[x]`。 | 78 | - 每个 `REQ-*` 子项由 `feature-review` 在 `verdict=approve` 时自动勾选为 `[x]`。 |
| 79 | - 路径限定为后端目录(如 `backend/module/sys/`);前端代码不在此阶段产生。 | 79 | - 路径限定为后端目录(如 `backend/module/sys/`);前端代码不在此阶段产生。 |
| 80 | 80 | ||
| 81 | ### 前端阶段格式(§ 三) | 81 | ### 前端阶段格式(§ 三) |
| 82 | 82 | ||
| 83 | ```markdown | 83 | ```markdown |
| 84 | -- 整体 MR: — | 84 | +- 整体里程碑: — |
| 85 | - 功能: | 85 | - 功能: |
| 86 | - [ ] FE-01 用户登录与注册 | 关联 REQ:REQ-SYS-001, REQ-SYS-002 | 关联原型:prototype/auth.html | 86 | - [ ] FE-01 用户登录与注册 | 关联 REQ:REQ-SYS-001, REQ-SYS-002 | 关联原型:prototype/auth.html |
| 87 | - [ ] FE-02 仪表盘总览 | 关联 REQ:REQ-DASH-001 | 关联原型:prototype/dashboard.html | 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 | - 每个 `FE-NN` 子项由 `fe-feature-review` 在 `verdict=approve` 时自动勾选为 `[x]`。 | 92 | - 每个 `FE-NN` 子项由 `fe-feature-review` 在 `verdict=approve` 时自动勾选为 `[x]`。 |
| 93 | - 进入前端阶段前 `frontend-start` 步骤 1 自带 prototype/ 门禁,强制检查项目根 `prototype/` 至少含 1 个 `*.html` mockup。 | 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,7 +132,7 @@ B 阶段分两段,**全部固化到 skills**。入口:`/erp-workflow:coding- | ||
| 133 | ### 你禁止做的 🚫 | 132 | ### 你禁止做的 🚫 |
| 134 | 133 | ||
| 135 | 1. **主会话直接 `mysql -e` 跑业务 DDL**(只读查询 / 临时本地调试除外)——业务 schema 必须走 `sql/migrations/V_n__*.sql`,详见下方 Schema 演化规约 | 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 | ### Schema 演化规约(Flyway migration) | 137 | ### Schema 演化规约(Flyway migration) |
| 139 | 138 | ||
| @@ -167,7 +166,7 @@ B 阶段分两段,**全部固化到 skills**。入口:`/erp-workflow:coding- | @@ -167,7 +166,7 @@ B 阶段分两段,**全部固化到 skills**。入口:`/erp-workflow:coding- | ||
| 167 | | `docs` | **文档改动**——只动 Markdown / 代码注释,不动实现 | | 166 | | `docs` | **文档改动**——只动 Markdown / 代码注释,不动实现 | |
| 168 | | `style` | **格式调整**——空白 / 缩进 / import 顺序,逻辑 0 变化 | | 167 | | `style` | **格式调整**——空白 / 缩进 / import 顺序,逻辑 0 变化 | |
| 169 | | `test` | **只动测试代码**——补用例 / 修 fixture,不碰实现 | | 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,7 +2,7 @@ | ||
| 2 | 2 | ||
| 3 | > 全流程进度跟踪。CC 每完成一项产出就勾选一项。 | 3 | > 全流程进度跟踪。CC 每完成一项产出就勾选一项。 |
| 4 | > - **§ 一 Plan(A0~A5)**:`plan-start` 找第一个未勾 A 子项分发到对应 skill | 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 | ## 一、Plan 阶段(一次性) | 7 | ## 一、Plan 阶段(一次性) |
| 8 | 8 | ||
| @@ -19,7 +19,7 @@ | @@ -19,7 +19,7 @@ | ||
| 19 | 19 | ||
| 20 | - [ ] A2 骨架生成 — skeleton-gen | 20 | - [ ] A2 骨架生成 — skeleton-gen |
| 21 | - [ ] 架构文档已生成(docs/04 § 一+、docs/06、docs/07、docs/09) | 21 | - [ ] 架构文档已生成(docs/04 § 一+、docs/06、docs/07、docs/09) |
| 22 | - - [ ] 工具脚本已生成(scripts/*.sh、.githooks/pre-push、.env.local) | 22 | + - [ ] 工具脚本已生成(scripts/*.sh、.env.local) |
| 23 | - [ ] .gitignore 已配置 | 23 | - [ ] .gitignore 已配置 |
| 24 | 24 | ||
| 25 | - [ ] A3 DB 设计 + REQ 回填 — db-design-gen | 25 | - [ ] A3 DB 设计 + REQ 回填 — db-design-gen |
| @@ -43,13 +43,13 @@ | @@ -43,13 +43,13 @@ | ||
| 43 | 43 | ||
| 44 | ## 二、Coding 阶段(后端模块循环) | 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 | <!-- 模块格式示例(由 A5 downstream-gen 追加;功能子项由 feature-review 在 approve 时勾选): | 48 | <!-- 模块格式示例(由 A5 downstream-gen 追加;功能子项由 feature-review 在 approve 时勾选): |
| 49 | - module_0 系统管理 | 49 | - module_0 系统管理 |
| 50 | - 依赖: — | 50 | - 依赖: — |
| 51 | - 路径: backend/module/sys/ | 51 | - 路径: backend/module/sys/ |
| 52 | - - MR: — | 52 | + - 里程碑: — |
| 53 | - 功能: | 53 | - 功能: |
| 54 | - [ ] REQ-SYS-001 用户登录 | 54 | - [ ] REQ-SYS-001 用户登录 |
| 55 | - [ ] REQ-SYS-002 用户注册 | 55 | - [ ] REQ-SYS-002 用户注册 |
| @@ -57,9 +57,9 @@ | @@ -57,9 +57,9 @@ | ||
| 57 | 57 | ||
| 58 | ## 三、Coding 阶段(前端整体) | 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 | <!-- AI 进入时按以下行格式写入(每行 1 个 FE,可关联多个 REQ / 多份原型): | 64 | <!-- AI 进入时按以下行格式写入(每行 1 个 FE,可关联多个 REQ / 多份原型): |
| 65 | - [ ] FE-NN 功能名 | 关联 REQ:REQ-A, REQ-B | 关联原型:prototype/<file>.html, prototype/<other>.html | 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,7 +2,7 @@ | ||
| 2 | name: skeleton-gen | 2 | name: skeleton-gen |
| 3 | description: A2 骨架生成——基于 docs/04 § 零 技术栈 + docs/01-需求清单/index.md 模块索引,生成项目专属的架构文档(docs/04 § 一+、docs/06、docs/07、docs/09)和工具脚本。固定工具文件走 cp,架构文档由 LLM 按大纲生成。 | 3 | description: A2 骨架生成——基于 docs/04 § 零 技术栈 + docs/01-需求清单/index.md 模块索引,生成项目专属的架构文档(docs/04 § 一+、docs/06、docs/07、docs/09)和工具脚本。固定工具文件走 cp,架构文档由 LLM 按大纲生成。 |
| 4 | user-invocable: false | 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,10 +61,9 @@ docs/04 已由 scope-lock 写入 § 零。本步骤追加 § 一 ~ 三。 | ||
| 61 | #### C.1 复制 | 61 | #### C.1 复制 |
| 62 | 62 | ||
| 63 | ```bash | 63 | ```bash |
| 64 | -mkdir -p scripts .githooks sql/migrations src/styles | 64 | +mkdir -p scripts sql/migrations src/styles |
| 65 | touch sql/migrations/.gitkeep | 65 | touch sql/migrations/.gitkeep |
| 66 | cp "${CLAUDE_SKILL_DIR}/templates/env-local-template" .env.local | 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 | cp "${CLAUDE_SKILL_DIR}/templates/scripts-setup-test-db-template.sh" scripts/setup-test-db.sh | 67 | cp "${CLAUDE_SKILL_DIR}/templates/scripts-setup-test-db-template.sh" scripts/setup-test-db.sh |
| 69 | cp "${CLAUDE_SKILL_DIR}/templates/styles-tokens-template.css" src/styles/tokens.css | 68 | cp "${CLAUDE_SKILL_DIR}/templates/styles-tokens-template.css" src/styles/tokens.css |
| 70 | ``` | 69 | ``` |
| @@ -85,15 +84,14 @@ cp "${CLAUDE_SKILL_DIR}/templates/styles-tokens-template.css" src/styles/tokens. | @@ -85,15 +84,14 @@ cp "${CLAUDE_SKILL_DIR}/templates/styles-tokens-template.css" src/styles/tokens. | ||
| 85 | > | 84 | > |
| 86 | > 表结构异常(列名变更 / 无中文前缀)时停下,用 `AskUserQuestion` 让用户显式确认每 stack 命令。 | 85 | > 表结构异常(列名变更 / 无中文前缀)时停下,用 `AskUserQuestion` 让用户显式确认每 stack 命令。 |
| 87 | 86 | ||
| 88 | -#### C.3 赋权 + 配置 git hooks | 87 | +#### C.3 赋权 |
| 89 | 88 | ||
| 90 | ```bash | 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 | 完成后,用 `Edit` 在 `docs/08-模块任务管理.md` 中勾选: | 93 | 完成后,用 `Edit` 在 `docs/08-模块任务管理.md` 中勾选: |
| 96 | -- ` - [ ] 工具脚本已生成(scripts/*.sh、.githooks/pre-push、.env.local)` | 94 | +- ` - [ ] 工具脚本已生成(scripts/*.sh、.env.local)` |
| 97 | - ` - [ ] 样式 token 骨架已生成(src/styles/tokens.css)` | 95 | - ` - [ ] 样式 token 骨架已生成(src/styles/tokens.css)` |
| 98 | 96 | ||
| 99 | ### D. 追加 .gitignore 忽略项 | 97 | ### D. 追加 .gitignore 忽略项 |
| @@ -113,7 +111,7 @@ bash "${CLAUDE_SKILL_DIR}/scripts/merge-gitignore.sh" "${CLAUDE_SKILL_DIR}/templ | @@ -113,7 +111,7 @@ bash "${CLAUDE_SKILL_DIR}/scripts/merge-gitignore.sh" "${CLAUDE_SKILL_DIR}/templ | ||
| 113 | 111 | ||
| 114 | 用 `Grep` 在以下 8 个路径扫 `【人工填写:`,记录命中(文件 / 行号 / 说明): | 112 | 用 `Grep` 在以下 8 个路径扫 `【人工填写:`,记录命中(文件 / 行号 / 说明): |
| 115 | - `docs/04-技术规范.md` / `docs/06-UI交互规范.md` / `docs/07-环境配置.md` / `docs/09-项目目录结构.md` | 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 | - `.env.local` | 115 | - `.env.local` |
| 118 | 116 | ||
| 119 | 分两组: | 117 | 分两组: |
| @@ -139,7 +137,7 @@ bash "${CLAUDE_SKILL_DIR}/scripts/merge-gitignore.sh" "${CLAUDE_SKILL_DIR}/templ | @@ -139,7 +137,7 @@ bash "${CLAUDE_SKILL_DIR}/scripts/merge-gitignore.sh" "${CLAUDE_SKILL_DIR}/templ | ||
| 139 | 137 | ||
| 140 | 每次弹 QA 前重扫;有残留则打印残留位置清单(文件:行号 — 说明)+ 再弹 QA。 | 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 | 通过后(N=0 且用户选「继续」),用 `Edit` 在 `docs/08-模块任务管理.md` 中勾选: | 142 | 通过后(N=0 且用户选「继续」),用 `Edit` 在 `docs/08-模块任务管理.md` 中勾选: |
| 145 | - `- [ ] A2 骨架生成 — skeleton-gen` | 143 | - `- [ ] A2 骨架生成 — skeleton-gen` |
| @@ -158,7 +156,6 @@ QA 横幅涵盖:产出文件清单(docs/04 / 06 / 07 / 09 + scripts/*.sh + . | @@ -158,7 +156,6 @@ QA 横幅涵盖:产出文件清单(docs/04 / 06 / 07 / 09 + scripts/*.sh + . | ||
| 158 | - `${CLAUDE_SKILL_DIR}/templates/docs-09-structure-template.md`(大纲) | 156 | - `${CLAUDE_SKILL_DIR}/templates/docs-09-structure-template.md`(大纲) |
| 159 | - `${CLAUDE_SKILL_DIR}/templates/scripts-test-template.sh`(推断命令填充 7 槽:backend/frontend × build/lint/test + e2e;缺席 stack 填 `:`) | 157 | - `${CLAUDE_SKILL_DIR}/templates/scripts-test-template.sh`(推断命令填充 7 槽:backend/frontend × build/lint/test + e2e;缺席 stack 填 `:`) |
| 160 | - `${CLAUDE_SKILL_DIR}/templates/scripts-setup-test-db-template.sh`(0 槽位) | 158 | - `${CLAUDE_SKILL_DIR}/templates/scripts-setup-test-db-template.sh`(0 槽位) |
| 161 | -- `${CLAUDE_SKILL_DIR}/templates/githooks-pre-push-template.sh`(0 槽位) | ||
| 162 | - `${CLAUDE_SKILL_DIR}/templates/env-local-template`(0 槽位) | 159 | - `${CLAUDE_SKILL_DIR}/templates/env-local-template`(0 槽位) |
| 163 | - `${CLAUDE_SKILL_DIR}/templates/gitignore-append-template`(0 槽位) | 160 | - `${CLAUDE_SKILL_DIR}/templates/gitignore-append-template`(0 槽位) |
| 164 | - `${CLAUDE_SKILL_DIR}/templates/styles-tokens-template.css`(0 槽位,样式 token 骨架) | 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,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 | <!-- 按 § 零 的后端框架定层次:controller/service/mapper 等;每层职责一句话。 --> | 14 | <!-- 按 § 零 的后端框架定层次:controller/service/mapper 等;每层职责一句话。 --> |
| 11 | 15 | ||
| 12 | -### 1.2 命名约定 | 16 | +### 1.3 命名约定 |
| 13 | <!-- 包名(根包用【人工填写:根包名】占位)/ 类名 / 方法名 / 常量的大小写规则,含 2 个示例。 --> | 17 | <!-- 包名(根包用【人工填写:根包名】占位)/ 类名 / 方法名 / 常量的大小写规则,含 2 个示例。 --> |
| 14 | 18 | ||
| 15 | -### 1.3 统一响应格式 | 19 | +### 1.4 统一响应格式 |
| 16 | <!-- 成功/失败的 JSON 结构,错误码段位划分。 --> | 20 | <!-- 成功/失败的 JSON 结构,错误码段位划分。 --> |
| 17 | 21 | ||
| 18 | -### 1.4 异常处理 | 22 | +### 1.5 异常处理 |
| 19 | <!-- 全局异常处理器的使用方式;哪些异常要 catch,哪些禁止;**接口响应禁止回显后端异常堆栈**(返用户友好错误码 + 文案)。 --> | 23 | <!-- 全局异常处理器的使用方式;哪些异常要 catch,哪些禁止;**接口响应禁止回显后端异常堆栈**(返用户友好错误码 + 文案)。 --> |
| 20 | 24 | ||
| 21 | -### 1.5 事务 | 25 | +### 1.6 事务 |
| 22 | <!-- 事务边界(通常 service 层);跨服务调用的禁止/替代方案。 --> | 26 | <!-- 事务边界(通常 service 层);跨服务调用的禁止/替代方案。 --> |
| 23 | 27 | ||
| 24 | -### 1.6 认证 | 28 | +### 1.7 认证 |
| 25 | <!-- 基于 § 零 认证方案推导:token 生命周期、刷新机制、密钥管理。 --> | 29 | <!-- 基于 § 零 认证方案推导:token 生命周期、刷新机制、密钥管理。 --> |
| 26 | 30 | ||
| 27 | ## 二、前端规范 | 31 | ## 二、前端规范 |
| @@ -62,4 +66,4 @@ skeleton-gen 读取 docs/04 § 零(技术栈表)和 docs/01-需求清单/ind | @@ -62,4 +66,4 @@ skeleton-gen 读取 docs/04 § 零(技术栈表)和 docs/01-需求清单/ind | ||
| 62 | 66 | ||
| 63 | ### 3.5 配置与安全 | 67 | ### 3.5 配置与安全 |
| 64 | <!-- 配置:DB 连接 / 端口 / 密钥 / 第三方 URL 等一律放 `application.yml` + `.env.local`,代码里**禁止硬编码**。 | 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,7 +3,7 @@ | ||
| 3 | skeleton-gen 基于 docs/04 § 零 技术栈表推导各节内容: | 3 | skeleton-gen 基于 docs/04 § 零 技术栈表推导各节内容: |
| 4 | § 一 依赖清单 → 从技术栈的每一行技术推导运行时和构建依赖 | 4 | § 一 依赖清单 → 从技术栈的每一行技术推导运行时和构建依赖 |
| 5 | § 二 端口约定 → 从后端/前端/数据库/缓存/反向代理 各取默认端口 | 5 | § 二 端口约定 → 从后端/前端/数据库/缓存/反向代理 各取默认端口 |
| 6 | - § 四 常用命令 → 基于构建工具、包管理器、MR 工具给出开发者最常用命令 | 6 | + § 四 常用命令 → 基于构建工具、包管理器给出开发者最常用命令 |
| 7 | --> | 7 | --> |
| 8 | 8 | ||
| 9 | # 07-环境配置 | 9 | # 07-环境配置 |
| @@ -23,4 +23,4 @@ skeleton-gen 基于 docs/04 § 零 技术栈表推导各节内容: | @@ -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,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,15 +23,3 @@ JWT_SECRET=【人工填写:JWT 签名密钥,256+ bit 随机串】 | ||
| 23 | # 仅用于你完全可控的测试库;生产/共享库/多人共享的 staging 库**千万别列**。 | 23 | # 仅用于你完全可控的测试库;生产/共享库/多人共享的 staging 库**千万别列**。 |
| 24 | # (防护 2 还会检查 schema 名须含 test/_dev/_local/_ci,独立兜底。) | 24 | # (防护 2 还会检查 schema 名须含 test/_dev/_local/_ci,独立兜底。) |
| 25 | TEST_DB_ALLOWED_HOSTS= | 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
skills/plan/skeleton-gen/templates/scripts-test-template.sh
| 1 | #!/usr/bin/env bash | 1 | #!/usr/bin/env bash |
| 2 | # scripts/test.sh —— 合并到默认分支(main / master)前的测试闸门。 | 2 | # scripts/test.sh —— 合并到默认分支(main / master)前的测试闸门。 |
| 3 | # 顺序:detect → setup-db → build → lint → unit+integration → e2e → reset-db | 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 | set -euo pipefail | 6 | set -euo pipefail |
| 7 | 7 |