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