Commit a6f9c34db2c6c668d718a081634a77616db2adb6
1 parent
cc94a5f4
edit
Showing
23 changed files
with
198 additions
and
88 deletions
.claude-plugin/plugin.json
| ... | ... | @@ -2,5 +2,5 @@ |
| 2 | 2 | "name": "erp-workflow", |
| 3 | 3 | "description": "ERP 项目全流程框架:阶段 A 计划(一次性) + 阶段 B 编码(模块循环 + 功能循环),含完整 skill 流水线 + 守门 hook + 软规则留痕。专为后端 Spring Boot + 前端 React + MySQL 8 的 ERP/管理类系统设计。", |
| 4 | 4 | "version": "0.1.0", |
| 5 | - "skills": ["./skills/plan", "./skills/coding", "./skills/crosscut"] | |
| 5 | + "skills": ["./skills/plan", "./skills/coding", "./skills/crosscut", "./skills/internal"] | |
| 6 | 6 | } | ... | ... |
README.md
| ... | ... | @@ -164,7 +164,7 @@ erp-workflow-plugin/ |
| 164 | 164 | |---|---|---| |
| 165 | 165 | | `erp-plan-start` | **A 阶段入口**。读取 docs/08 § 一 找第一个未勾 A 子项 → 派发对应 A skill;A 全部完成时提示运行 coding-start | **用户手动**运行 `/erp-workflow:erp-plan-start` | |
| 166 | 166 | | `erp-coding-start` | **B 阶段入口**。先验证 Plan 已完成;**按 `docs/02 § 二` REQ 序扫描**,对每个 REQ 所属模块查询 `MR: 字段 + glab mr view state`:`merged` 跳过;`—`/opened/closed/查不到 选为当前模块。派发前 `git checkout main + git pull --ff-only` 同步远程 base,然后调用 `erp-module-start` | **用户手动**运行 `/erp-workflow:erp-coding-start` | |
| 167 | -| `erp-red-flag-check` | 检查 CLAUDE.md 的 6 项红旗清单;命中则追加 Blocker 到计划文件并停下 | 功能循环各步骤和生成重要制品前自动调用 | | |
| 167 | +| `erp-red-flag-check` | 检查 CLAUDE.md 的 3 项红旗清单;命中则追加 Blocker 到计划文件并停下 | 功能循环各步骤和生成重要制品前自动调用 | | |
| 168 | 168 | | `erp-cross-module-log` | 给 `log-cross-module.sh` 追加的跨模块改动存根补「原因 / 影响评估」 | 用户看到 hook 提示后调用;`erp-module-start` 初始化日志文件时也会用其模板 | |
| 169 | 169 | |
| 170 | 170 | ## Templates 清单(38 份) | ... | ... |
skills/coding/erp-feature-brainstorm/SKILL.md
| ... | ... | @@ -11,7 +11,7 @@ allowed-tools: Read Write Skill Bash(mysql *) |
| 11 | 11 | |
| 12 | 12 | ## 说明 |
| 13 | 13 | |
| 14 | -针对一个 REQ-XXX-NNN,委托 `superpowers:brainstorming` 进行头脑风暴,再把输出填入标准规格模板,产出单页功能规格。 | |
| 14 | +针对一个 REQ-XXX-NNN,委托本插件的 `superpower-brainstorming`(superpowers:brainstorming 的本地 fork,已剥掉 approval gates)进行头脑风暴,再把输出填入标准规格模板,产出单页功能规格。 | |
| 15 | 15 | |
| 16 | 16 | ## 执行步骤 |
| 17 | 17 | |
| ... | ... | @@ -20,7 +20,7 @@ allowed-tools: Read Write Skill Bash(mysql *) |
| 20 | 20 | - 当前 REQ-XXX-NNN(从对话中获取,或 `docs/08` 当前模块下一个未完成的 REQ)。 |
| 21 | 21 | - REQ 卡片:`docs/01-需求清单/<module>.md` 中对应的 REQ-XXX-NNN 节。 |
| 22 | 22 | - 相关数据表(从 `docs/03` 或实时 mysql 命令行查询)。 |
| 23 | -3. 委托 `superpowers:brainstorming`,以 REQ 卡片 + schema 引用作为上下文。 | |
| 23 | +3. 委托本插件 `superpower-brainstorming`,以 REQ 卡片 + schema 引用作为上下文;把步骤 4 推导出的落盘路径作为 caller-provided path 传入。 | |
| 24 | 24 | 4. 推导路径:`docs/superpowers/specs/$(date +%F)-<REQ-id>.md`。如已存在,征求用户确认后覆盖。 |
| 25 | 25 | 5. 用 `Read` 读取 `${CLAUDE_SKILL_DIR}/templates/feature-spec-template.md`,从头脑风暴输出填充槽位: |
| 26 | 26 | - `goal`、`input`、`output`、`rules`、`constraints`、`schema_refs`、`api_refs`、`acceptance` |
| ... | ... | @@ -35,5 +35,5 @@ allowed-tools: Read Write Skill Bash(mysql *) |
| 35 | 35 | ## 参考 |
| 36 | 36 | |
| 37 | 37 | - `${CLAUDE_SKILL_DIR}/templates/feature-spec-template.md` |
| 38 | -- 委托:`superpowers:brainstorming` | |
| 38 | +- 委托:`superpower-brainstorming`(本插件 `skills/internal/superpower-brainstorming/`,superpowers:brainstorming 的无门 fork) | |
| 39 | 39 | - 守门:`erp-red-flag-check` | ... | ... |
skills/coding/erp-feature-plan/SKILL.md
| ... | ... | @@ -16,7 +16,7 @@ allowed-tools: Read Write Grep Skill |
| 16 | 16 | - 当前 REQ-XXX-NNN 及其规格文件 `docs/superpowers/specs/YYYY-MM-DD-<REQ>.md`(规格不存在则报错)。 |
| 17 | 17 | - 相关代码指针(已有的待修改文件,通过 Grep 发现)。 |
| 18 | 18 | - `docs/04-技术规范.md` 和 `docs/09-项目目录结构.md`(编码规范 + 目录规范)。 |
| 19 | -3. 委托 `superpowers:writing-plans`,以规格 + 代码指针 + 规范作为上下文。 | |
| 19 | +3. 委托本插件 `superpower-writing-plans`(superpowers:writing-plans 的本地 fork,已剥掉"Which approach?"执行交接门),以规格 + 代码指针 + 规范作为上下文;把步骤 4 推导出的落盘路径作为 caller-provided path 传入。 | |
| 20 | 20 | 4. 推导路径:`docs/superpowers/plans/$(date +%F)-<REQ-id>.md`。 |
| 21 | 21 | 5. 用 `Read` 读取 `${CLAUDE_SKILL_DIR}/templates/feature-plan-template.md`,填充 `files[]`、`tasks[]`、`commits[]`。 |
| 22 | 22 | 6. 强制要求:每个任务有失败测试标识、实现路径和完成标准。 |
| ... | ... | @@ -30,5 +30,5 @@ allowed-tools: Read Write Grep Skill |
| 30 | 30 | ## 参考 |
| 31 | 31 | |
| 32 | 32 | - `${CLAUDE_SKILL_DIR}/templates/feature-plan-template.md` |
| 33 | -- 委托:`superpowers:writing-plans` | |
| 33 | +- 委托:`superpower-writing-plans`(本插件 `skills/internal/superpower-writing-plans/`,superpowers:writing-plans 的无门 fork) | |
| 34 | 34 | - 守门:`erp-red-flag-check` | ... | ... |
skills/coding/erp-feature-review/SKILL.md
| ... | ... | @@ -11,7 +11,7 @@ allowed-tools: Read Write Edit Skill Agent Bash(git add *) Bash(git commit *) |
| 11 | 11 | |
| 12 | 12 | ## 执行步骤 |
| 13 | 13 | |
| 14 | -1. 委托 `superpowers:code-reviewer`,以该 REQ 的 diff(`git diff <feature-start>..HEAD`)和规格作为输入。 | |
| 14 | +1. 通过 `Agent(subagent_type=superpower-code-reviewer)` 调用本插件 code-reviewer agent(superpowers:code-reviewer 的本地 fork),以该 REQ 的 diff(`git diff <feature-start>..HEAD`)和规格作为输入。 | |
| 15 | 15 | 2. 推导路径:`docs/superpowers/reviews/$(date +%F)-<REQ-id>.md`。 |
| 16 | 16 | 3. 用 `Read` 读取 `${CLAUDE_SKILL_DIR}/templates/feature-review-template.md`,填充 `round`、`verdict`、`must_fix[]`、`nice_to_have[]`、`gaps`。verdict 必须是 `approve` 或 `request-changes`。 |
| 17 | 17 | 4. 写入报告。 |
| ... | ... | @@ -36,6 +36,6 @@ allowed-tools: Read Write Edit Skill Agent Bash(git add *) Bash(git commit *) |
| 36 | 36 | |
| 37 | 37 | - `${CLAUDE_SKILL_DIR}/templates/feature-review-template.md` |
| 38 | 38 | - Fix commit 格式与 `erp-feature-tdd` 的 `commit-message-template.md` 对齐(`fix(<scope>): <subject> <req_id>`) |
| 39 | -- 委托:`superpowers:code-reviewer` | |
| 39 | +- 委托:`superpower-code-reviewer`(本插件 `agents/superpower-code-reviewer.md`,superpowers:code-reviewer 的本地 fork) | |
| 40 | 40 | - 上游:`erp-feature-verify` |
| 41 | 41 | - 下游:`erp-module-start`(approve)或 `erp-feature-verify`(request-changes) | ... | ... |
skills/coding/erp-feature-review/templates/feature-review-template.md
skills/coding/erp-feature-tdd/SKILL.md
| ... | ... | @@ -23,7 +23,7 @@ allowed-tools: Read Write Edit Agent Skill Bash(git add *) Bash(git commit *) |
| 23 | 23 | b. **派发子会话**(通过 `Agent`,general-purpose)运行测试并确认失败;子会话只返回 `{command, exit_code, failing_assertion}`。主会话**不直接**运行测试。 |
| 24 | 24 | c. 在 `impl_file` 处实现最小代码使测试通过。 |
| 25 | 25 | d. **再次派发子会话**运行测试并确认通过。 |
| 26 | - e. 持续失败(同一测试 >10 次修复尝试)→ 调用 `erp-red-flag-check`(红旗 #4)。 | |
| 26 | + e. 持续失败(同一测试 >10 次修复尝试)→ 调用 `erp-red-flag-check`(红旗 #1)。 | |
| 27 | 27 | f. 暂存变更并使用 `${CLAUDE_SKILL_DIR}/templates/commit-message-template.md` 提交;`scope` 匹配任务的模块,`subject` ≤50 字符,`req_id` 必填。 |
| 28 | 28 | 5. 所有任务完成后 → 交接给 `erp-feature-verify`。 |
| 29 | 29 | |
| ... | ... | @@ -41,5 +41,5 @@ allowed-tools: Read Write Edit Agent Skill Bash(git add *) Bash(git commit *) |
| 41 | 41 | ## 参考 |
| 42 | 42 | |
| 43 | 43 | - `${CLAUDE_SKILL_DIR}/templates/commit-message-template.md` |
| 44 | -- 委托:`superpowers:test-driven-development` | |
| 44 | +- 原则参考:`superpowers:test-driven-development`(本插件未镜像;仅作为 TDD 原则手册参考,不做运行时 invoke — 本 skill 已把"子会话跑测试 + REQ tag commit"流程直接写死) | |
| 45 | 45 | - 守门:`erp-red-flag-check` | ... | ... |
skills/coding/erp-feature-verify/SKILL.md
| ... | ... | @@ -37,4 +37,4 @@ allowed-tools: Skill Read Write Agent |
| 37 | 37 | ## 参考 |
| 38 | 38 | |
| 39 | 39 | - `${CLAUDE_SKILL_DIR}/templates/feature-verify-evidence-template.md` |
| 40 | -- 委托:`superpowers:verification-before-completion` | |
| 40 | +- 原则参考:`superpowers:verification-before-completion`(本插件未镜像;仅作为"证据先于断言"原则参考,不做运行时 invoke — 本 skill 已把子会话派发 + 模板渲染证据流程直接写死) | ... | ... |
skills/coding/erp-local-test-gate/SKILL.md
| ... | ... | @@ -25,7 +25,7 @@ allowed-tools: Read Write Skill Agent Bash(git add *) Bash(git commit *) |
| 25 | 25 | |
| 26 | 26 | 3. 写入 `docs/superpowers/module-reports/<module_id>-test-gate.md`。 |
| 27 | 27 | |
| 28 | -3b. **commit evidence 到 module 分支**(确保 test-gate.md 随 MR 合并进 main,审计可追溯): | |
| 28 | +3b. **commit evidence 到 module 分支**(确保 test-gate.md 随 MR 合并进默认分支,审计可追溯): | |
| 29 | 29 | |
| 30 | 30 | ```bash |
| 31 | 31 | git add docs/superpowers/module-reports/<module_id>-test-gate.md |
| ... | ... | @@ -57,7 +57,7 @@ allowed-tools: Read Write Skill Agent Bash(git add *) Bash(git commit *) |
| 57 | 57 | (module-start 把该 REQ 视为未完成,重走 brainstorm→...→review 循环修复) |
| 58 | 58 | |
| 59 | 59 | ③ 环境/依赖问题(DB 连不上、外部 API 失败、证书失效) |
| 60 | - → 命中红旗 #6(外部接口不可达) | |
| 60 | + → 命中红旗 #3(外部接口不可达) | |
| 61 | 61 | → 调用 Skill(erp-red-flag-check) 追加 Blocker 到本模块任一 plan 文件 |
| 62 | 62 | → 修复环境后重新运行 /erp-workflow:erp-coding-start |
| 63 | 63 | ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ | ... | ... |
skills/coding/erp-module-report/SKILL.md
| ... | ... | @@ -31,7 +31,7 @@ allowed-tools: Read Write Glob Grep Skill Bash(git diff *) Bash(git log *) Bash( |
| 31 | 31 | - § ⑧ 必须列举所有偏离规格之处;如果没有,明确写"无偏离"。 |
| 32 | 32 | 5. 写入 `docs/superpowers/module-reports/$(date +%F)-<module_id>.md`。 |
| 33 | 33 | |
| 34 | -5b. **commit 模块报告 + cross-module 日志到 module 分支**(确保审计证据随 MR 合并进 main;erp-mr-create 的 worktree clean 前置条件依赖此步): | |
| 34 | +5b. **commit 模块报告 + cross-module 日志到 module 分支**(确保审计证据随 MR 合并进默认分支;erp-mr-create 的 worktree clean 前置条件依赖此步): | |
| 35 | 35 | |
| 36 | 36 | ```bash |
| 37 | 37 | git add docs/superpowers/module-reports/$(date +%F)-<module_id>.md | ... | ... |
skills/coding/erp-mr-create/SKILL.md
| ... | ... | @@ -2,7 +2,7 @@ |
| 2 | 2 | name: erp-mr-create |
| 3 | 3 | description: 模块报告完成后,验证当前分支为 module-<id> 且 worktree 干净,push 推代码和所有 evidence,创建 GitLab MR(报告嵌入描述),把 MR URL 追加到模块报告 § ⑫ 并 commit,把 MR iid 回写到 docs/08 该模块 `MR:` 字段并 commit,再次 push 同步。完成信号由 MR merged state 判定。停下等待人工审核。 |
| 4 | 4 | user-invocable: false |
| 5 | -allowed-tools: Read Write Edit Skill Bash(git *) Bash(glab *) Bash(sed *) Bash(awk *) Bash(cat *) Bash(echo *) Bash(mkdir -p .tmp) Bash(mv .tmp/*) Bash(rm -f .tmp/*) | |
| 5 | +allowed-tools: Read Write Edit Skill Bash(git *) Bash(glab *) Bash(jq *) Bash(sed *) Bash(awk *) Bash(cat *) Bash(echo *) Bash(mkdir -p .tmp) Bash(mv .tmp/*) Bash(rm -f .tmp/*) | |
| 6 | 6 | --- |
| 7 | 7 | |
| 8 | 8 | **所有输出必须使用中文。** |
| ... | ... | @@ -81,7 +81,20 @@ mv .tmp/mr-desc.final "$DESC_FILE" |
| 81 | 81 | |
| 82 | 82 | 关键:**模块报告内容只经 awk 管道流过**,从不进入 LLM 上下文。 |
| 83 | 83 | |
| 84 | -### 步骤 6:创建 MR | |
| 84 | +### 步骤 5.5:幂等守门——检查 source branch 是否已有 opened MR | |
| 85 | + | |
| 86 | +防止部分失败后重试创建重复 MR: | |
| 87 | + | |
| 88 | +```bash | |
| 89 | +EXISTING_JSON=$(glab mr list --source-branch "<current_branch>" --state opened -F json 2>/dev/null) | |
| 90 | +EXISTING_IID=$(echo "$EXISTING_JSON" | jq -r '.[0].iid // empty') | |
| 91 | +EXISTING_URL=$(echo "$EXISTING_JSON" | jq -r '.[0].web_url // empty') | |
| 92 | +``` | |
| 93 | + | |
| 94 | +- `EXISTING_IID` 非空 → 打印 `[erp-mr-create] 检测到已有 opened MR: !${EXISTING_IID}`,**跳过步骤 6**,直接用 `EXISTING_IID` / `EXISTING_URL` 进入步骤 7。 | |
| 95 | +- `EXISTING_IID` 为空 → 正常走步骤 6 创建新 MR。 | |
| 96 | + | |
| 97 | +### 步骤 6:创建 MR(仅当 5.5 未命中时) | |
| 85 | 98 | |
| 86 | 99 | ```bash |
| 87 | 100 | TITLE_FILE=.tmp/mr-title.txt |
| ... | ... | @@ -90,20 +103,23 @@ glab mr create --title "$(cat "$TITLE_FILE")" --description "$(cat "$DESC_FILE") |
| 90 | 103 | rm -f .tmp/mr-title.txt .tmp/mr-desc.md |
| 91 | 104 | ``` |
| 92 | 105 | |
| 93 | -### 步骤 7:追加 MR URL 到模块报告 § ⑫ 并 commit | |
| 106 | +解析返回的 `IID` 和 `URL`,赋给 `MR_IID` / `MR_URL`(对应 5.5 命中时复用 `EXISTING_IID` / `EXISTING_URL`)。 | |
| 107 | + | |
| 108 | +### 步骤 7:回写 docs/08 的 MR 字段并 commit(durable state 先持久化) | |
| 109 | + | |
| 110 | +> 先写 docs/08 再追模块报告——这样如果步骤 8 失败,重跑时 5.5 能直接识别已有 MR 且 docs/08 已含 IID,避免状态不一致。 | |
| 94 | 111 | |
| 95 | -- 解析返回的 MR URL 和 IID(`<iid>`)。 | |
| 96 | -- `Edit docs/superpowers/module-reports/<date>-<module_id>.md` 的 § ⑫:把 `{{mr_url}}` 占位替换为实际 URL(若已替换过,追加一行)。 | |
| 97 | -- `Bash`: `git add docs/superpowers/module-reports/<date>-<module_id>.md && git commit -m "docs(<module_id>): record MR !<iid> link in module report"`。 | |
| 112 | +- `Edit docs/08-模块任务管理.md`:把当前模块条目的 ` - MR: —` 改为 ` - MR: !<MR_IID>`(只改一行)。docs/08 § 二 中 `MR:` 是唯一动态字段。 | |
| 113 | +- `Bash`: `git add docs/08-模块任务管理.md && git commit -m "chore(<module_id>): record MR !<MR_IID> in docs/08"`。 | |
| 98 | 114 | |
| 99 | -### 步骤 8:回写 docs/08 的 MR 字段并 commit | |
| 115 | +### 步骤 8:追加 MR URL 到模块报告 § ⑫ 并 commit | |
| 100 | 116 | |
| 101 | -- `Edit docs/08-模块任务管理.md`:把当前模块条目的 ` - MR: —` 改为 ` - MR: !<iid>`(只改一行)。docs/08 § 二 中 `MR:` 是唯一动态字段。 | |
| 102 | -- `Bash`: `git add docs/08-模块任务管理.md && git commit -m "chore(<module_id>): record MR !<iid> in docs/08"`。 | |
| 117 | +- `Edit docs/superpowers/module-reports/<date>-<module_id>.md` 的 § ⑫:把 `{{mr_url}}` 占位替换为 `<MR_URL>`(若已替换过,追加一行)。 | |
| 118 | +- `Bash`: `git add docs/superpowers/module-reports/<date>-<module_id>.md && git commit -m "docs(<module_id>): record MR !<MR_IID> link in module report"`。 | |
| 103 | 119 | |
| 104 | 120 | ### 步骤 9:再次 push |
| 105 | 121 | |
| 106 | -步骤 3 的 push 之后,步骤 7 和 8 又产生了两个新 commit(MR link + docs/08 MR iid)。必须再次 push 让 MR 自动更新 commit 列表 + diff: | |
| 122 | +步骤 3 的 push 之后,步骤 7、8 又产生了两个新 commit(docs/08 MR iid + 模块报告 MR link)。必须再次 push 让 MR 自动更新 commit 列表 + diff: | |
| 107 | 123 | |
| 108 | 124 | `Bash`: `git push origin <current_branch>` |
| 109 | 125 | |
| ... | ... | @@ -111,13 +127,13 @@ rm -f .tmp/mr-title.txt .tmp/mr-desc.md |
| 111 | 127 | |
| 112 | 128 | ### 步骤 11:停止 — 等待人工 Approve + Merge |
| 113 | 129 | |
| 114 | -用户合并后再次运行 `/erp-workflow:erp-coding-start`,入口会自动检测 MR merged → `git checkout main` + `git pull --ff-only` 同步远程 + 派发下一模块。 | |
| 130 | +用户合并后再次运行 `/erp-workflow:erp-coding-start`,入口会自动检测 MR merged → 探测默认分支(`main` 或 `master`)→ `git checkout <默认分支>` + `git pull --ff-only origin <默认分支>` 同步远程 → 派发下一模块。 | |
| 115 | 131 | |
| 116 | 132 | ## 设计要点 |
| 117 | 133 | |
| 118 | -- **main 是 protected branch**,只能通过 MR 修改。MR diff 覆盖代码、模块报告、test-gate evidence、cross-module log,以及 docs/08 的 `MR: !<iid>` 字段。 | |
| 134 | +- **默认分支(main 或 master)是 protected branch**,只能通过 MR 修改。MR diff 覆盖代码、模块报告、test-gate evidence、cross-module log,以及 docs/08 的 `MR: !<iid>` 字段。 | |
| 119 | 135 | - **完成信号以 MR state 为准**:docs/08 § 二 中仅 `MR:` 字段在 `—` / `!<iid>` 之间变化,避免提前合并未完成模块的顺序错误。 |
| 120 | -- **worktree 干净前置**(步骤 2):保证 test-gate.md、module-report.md、cross-module log.md 都已进 repo,审计证据完整;防止下次 coding-start `git checkout main` 遇到 dirty state。 | |
| 136 | +- **worktree 干净前置**(步骤 2):保证 test-gate.md、module-report.md、cross-module log.md 都已进 repo,审计证据完整;防止下次 coding-start 切回默认分支时遇到 dirty state。 | |
| 121 | 137 | |
| 122 | 138 | ## 参考 |
| 123 | 139 | ... | ... |
skills/coding/erp-mr-create/templates/mr-description-template.md
| ... | ... | @@ -15,4 +15,4 @@ |
| 15 | 15 | ## 审核入口 |
| 16 | 16 | |
| 17 | 17 | - 本 MR = 模块 `{{module_id}}` 的唯一人工介入点 |
| 18 | -- Approve + Merge 后,下次用户运行 `/erp-workflow:erp-coding-start` 时入口会自动扫描到 `glab mr view state=merged`,`git pull --ff-only` 同步 main 并推进下一模块 | |
| 18 | +- Approve + Merge 后,下次用户运行 `/erp-workflow:erp-coding-start` 时入口会自动扫描到 `glab mr view state=merged`,探测默认分支后 `git pull --ff-only` 同步并推进下一模块 | ... | ... |
skills/crosscut/erp-coding-start/SKILL.md
| 1 | 1 | --- |
| 2 | 2 | name: erp-coding-start |
| 3 | -description: B 阶段(Coding)入å£ã€‚å…ˆéªŒè¯ Plan 已完æˆï¼›æŒ‰ docs/02 § 二 REQ å¼€å‘é¡ºåºæ¸…啿‰«æï¼Œå¯¹æ¯ä¸ª REQ 所属模å—用 docs/08 çš„ `MR:` å—æ®µ + `glab mr view state` 判定是å¦å®Œæˆâ€”—merged 跳过,`—` 或 opened/closed é€‰ä¸ºå½“å‰æ¨¡å—å¹¶æ´¾å‘到 erp-module-start。派å‘å‰å…ˆ git checkout main + pull --ff-only ä¿æŒ base 最新。 | |
| 3 | +description: B 阶段(Coding)入å£ã€‚å…ˆéªŒè¯ Plan 已完æˆï¼›æŒ‰ docs/02 § 二 REQ å¼€å‘é¡ºåºæ¸…啿‰«æï¼Œå¯¹æ¯ä¸ª REQ 所属模å—用 docs/08 çš„ `MR:` å—æ®µ + `glab mr view state` 判定是å¦å®Œæˆâ€”—merged 跳过,`—` 或 opened/closed é€‰ä¸ºå½“å‰æ¨¡å—å¹¶æ´¾å‘到 erp-module-start。派å‘å‰è‡ªåŠ¨æŽ¢æµ‹é»˜è®¤åˆ†æ”¯ï¼ˆmain / master)并 git checkout + pull --ff-only ä¿æŒ base 最新。 | |
| 4 | 4 | user-invocable: true |
| 5 | -allowed-tools: Skill Read Glob Grep Bash(glab mr *) Bash(git branch *) Bash(git checkout *) Bash(git pull *) Bash(git status *) | |
| 5 | +allowed-tools: Skill Read Glob Grep Bash(glab mr *) Bash(git branch *) Bash(git checkout *) Bash(git pull *) Bash(git status *) Bash(git symbolic-ref *) Bash(sed *) | |
| 6 | 6 | --- |
| 7 | 7 | |
| 8 | 8 | **æ‰€æœ‰è¾“å‡ºå¿…é¡»ä½¿ç”¨ä¸æ–‡ã€‚** |
| 9 | 9 | |
| 10 | -B 阶段(Coding)的入å£åˆ†å‘器。èŒè´£ï¼š**éªŒè¯ Plan å·²å®Œæˆ â†’ 按 docs/02 § 二 REQ åº + MR state 定ä½å½“剿¨¡å— → 切回 main å¹¶åŒæ¥è¿œç¨‹ → æ´¾å‘ erp-module-start**。ä¸ç›´æŽ¥ç”Ÿæˆä»»ä½•文件。开å‘顺åºä»¥ `docs/02 § 二` 为准;完æˆåˆ¤å®šä»¥ `docs/08 æ¡ç›®çš„ MR: å—æ®µ + glab mr view state` 为准。 | |
| 10 | +B 阶段(Coding)的入å£åˆ†å‘器。èŒè´£ï¼š**éªŒè¯ Plan å·²å®Œæˆ â†’ 按 docs/02 § 二 REQ åº + MR state 定ä½å½“剿¨¡å— → åˆ‡å›žé»˜è®¤åˆ†æ”¯å¹¶åŒæ¥è¿œç¨‹ → æ´¾å‘ erp-module-start**。ä¸ç›´æŽ¥ç”Ÿæˆä»»ä½•文件。开å‘顺åºä»¥ `docs/02 § 二` 为准;完æˆåˆ¤å®šä»¥ `docs/08 æ¡ç›®çš„ MR: å—æ®µ + glab mr view state` 为准。默认分支(`main` 或 `master`)在æ¥éª¤ 4 自动探测,ä¸ç¡¬ç¼–ç 。 | |
| 11 | 11 | |
| 12 | 12 | ## 执行æ¥éª¤ |
| 13 | 13 | |
| ... | ... | @@ -60,14 +60,28 @@ B 阶段(Coding)的入å£åˆ†å‘器。èŒè´£ï¼š**éªŒè¯ Plan å·²å®Œæˆ â†’ æŒ |
| 60 | 60 | å¹¶**åœä¸‹**。 |
| 61 | 61 | 6. 命ä¸åŽï¼šè®°å½• `current_module` çš„ `MR:` å—æ®µå€¼ï¼ˆ`—` / `!<iid>-opened` / `!<iid>-closed` / `!<iid>-查ä¸åˆ°`,用于æ¥éª¤ 5 横幅展示)。 |
| 62 | 62 | |
| 63 | -### æ¥éª¤ 4:切回 main + åŒæ¥è¿œç¨‹ï¼ˆå‡†å¤‡ module-start 切新分支的干净 base) | |
| 63 | +### æ¥éª¤ 4:探测默认分支 + åˆ‡å›žå¹¶åŒæ¥è¿œç¨‹ï¼ˆå‡†å¤‡ module-start 切新分支的干净 base) | |
| 64 | + | |
| 65 | +4.0 **探测默认分支**: | |
| 66 | + | |
| 67 | +```bash | |
| 68 | +DEFAULT_BRANCH=$(git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null | sed 's|refs/remotes/origin/||') | |
| 69 | +if [ -z "$DEFAULT_BRANCH" ]; then | |
| 70 | + # HEAD 未设置,回退:在 main / master 里å–第一个实际å˜åœ¨çš„远程分支 | |
| 71 | + DEFAULT_BRANCH=$(git branch -r --format='%(refname:short)' | grep -E '^origin/(main|master)$' | head -1 | sed 's|^origin/||') | |
| 72 | +fi | |
| 73 | +``` | |
| 74 | + | |
| 75 | +- `DEFAULT_BRANCH` 为空 → 打å°é”™è¯¯å¹¶**åœä¸‹**ï¼ˆæ—¢æ— `origin/main` ä¹Ÿæ— `origin/master`,说明远程未就绪,æç¤ºç”¨æˆ·å…ˆå®Œæˆ Plan 的首次 push 或 `git remote set-head origin -a` 设置 HEAD)。 | |
| 76 | + | |
| 77 | +4.1 **切回 + åŒæ¥**: | |
| 64 | 78 | |
| 65 | 79 | - `Bash`: `git branch --show-current` → `current_branch`。 |
| 66 | -- 若 `current_branch != main`: | |
| 80 | +- 若 `current_branch != $DEFAULT_BRANCH`: | |
| 67 | 81 | - `Bash`: `git status --porcelain`ï¼›éžç©º → 打å°ï¼š |
| 68 | 82 | ``` |
| 69 | 83 | â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â” |
| 70 | - [erp-coding-start] âš ï¸ å½“å‰åˆ†æ”¯ <current_branch> 有未æäº¤æ”¹åŠ¨ï¼Œæ— æ³•åˆ‡æ¢åˆ° main | |
| 84 | + [erp-coding-start] âš ï¸ å½“å‰åˆ†æ”¯ <current_branch> 有未æäº¤æ”¹åŠ¨ï¼Œæ— æ³•åˆ‡æ¢åˆ° <DEFAULT_BRANCH> | |
| 71 | 85 | |
| 72 | 86 | <git status 输出> |
| 73 | 87 | |
| ... | ... | @@ -75,17 +89,17 @@ B 阶段(Coding)的入å£åˆ†å‘器。èŒè´£ï¼š**éªŒè¯ Plan å·²å®Œæˆ â†’ æŒ |
| 75 | 89 | â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â” |
| 76 | 90 | ``` |
| 77 | 91 | å¹¶**åœä¸‹**。 |
| 78 | - - `Bash`: `git checkout main`。 | |
| 79 | -- `Bash`: `git pull --ff-only origin main`。 | |
| 92 | + - `Bash`: `git checkout "$DEFAULT_BRANCH"`。 | |
| 93 | +- `Bash`: `git pull --ff-only origin "$DEFAULT_BRANCH"`。 | |
| 80 | 94 | - å¤±è´¥ï¼ˆéž fast-forward / 网络 / 冲çªï¼‰â†’ 打å°é”™è¯¯æ¨ªå¹…: |
| 81 | 95 | ``` |
| 82 | 96 | â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â” |
| 83 | - [erp-coding-start] âš ï¸ åŒæ¥ main 失败 | |
| 97 | + [erp-coding-start] âš ï¸ åŒæ¥ <DEFAULT_BRANCH> 失败 | |
| 84 | 98 | |
| 85 | - 本地 main æ— æ³• fast-forward 到 remote。请手工处ç†ï¼š | |
| 99 | + 本地 <DEFAULT_BRANCH> æ— æ³• fast-forward 到 remote。请手工处ç†ï¼š | |
| 86 | 100 | git status |
| 87 | - git log main..origin/main # 远程领先的 commit | |
| 88 | - git log origin/main..main # 本地未推的 commit | |
| 101 | + git log <DEFAULT_BRANCH>..origin/<DEFAULT_BRANCH> # 远程领先的 commit | |
| 102 | + git log origin/<DEFAULT_BRANCH>..<DEFAULT_BRANCH> # 本地未推的 commit | |
| 89 | 103 | ä¿®å¤åŽé‡æ–°è¿è¡Œ /erp-workflow:erp-coding-start。 |
| 90 | 104 | â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â” |
| 91 | 105 | ``` |
| ... | ... | @@ -110,7 +124,7 @@ B 阶段(Coding)的入å£åˆ†å‘器。èŒè´£ï¼š**éªŒè¯ Plan å·²å®Œæˆ â†’ æŒ |
| 110 | 124 | ## 设计è¦ç‚¹ |
| 111 | 125 | |
| 112 | 126 | - **完æˆåˆ¤å®šç›´æŽ¥è¯»å– `MR:` å—æ®µ + `glab mr view state`**:MR 未 merge å‰ docs/08 没有任何"已完æˆ"æ ‡è®°ï¼›ç”¨æˆ·æå‰è§¦å‘ coding-start 时,æ¥éª¤ 3 扫æåˆ° MR opened ä»ä¼šé€‰ä¸å½“剿¨¡å—,module-start 会 `git checkout module-<id>` 回到原分支继ç»ï¼Œä¸ä¼šè·³åˆ°ä¸‹ä¸€æ¨¡å—。 |
| 113 | -- **æ¯æ¬¡æ´¾å‘å‰éƒ½ pull main**:代ç åŒæ¥çš„åŒæ—¶ï¼Œä¹Ÿä¿è¯ module-start 切出新分支时 base 新鲜。 | |
| 127 | +- **æ¯æ¬¡æ´¾å‘å‰éƒ½ pull 默认分支**:代ç åŒæ¥çš„åŒæ—¶ï¼Œä¹Ÿä¿è¯ module-start 切出新分支时 base 新鲜。默认分支由æ¥éª¤ 4.0 探测(main 或 master),ä¸ç¡¬ç¼–ç 。 | |
| 114 | 128 | |
| 115 | 129 | ## å‚考 |
| 116 | 130 | ... | ... |
skills/crosscut/erp-plan-start/SKILL.md
| ... | ... | @@ -64,10 +64,18 @@ A 阶段所有 checkbox 均 `[x]`。因无下游 A skill 接手,本步骤**自 |
| 64 | 64 | |
| 65 | 65 | ⚠️ 进入 B 阶段前必须完成: |
| 66 | 66 | 1. 人工通读 docs/01~10 + CLAUDE.md + sql/migrations/V1 + 各 scripts/* |
| 67 | - 2. 把全部 Plan 产物 commit 到 main 分支: | |
| 67 | + | |
| 68 | + 2. 把全部 Plan 产物 commit: | |
| 68 | 69 | git add -A && git commit -m "chore: plan phase A0~A5 done" |
| 69 | - 3. 建 Plan MR 提交团队审核,合并后 main 成为 B 阶段每个模块分支的基线 | |
| 70 | - 4. MR 合并后再运行 /erp-workflow:erp-coding-start 进入 B 阶段 | |
| 70 | + | |
| 71 | + 3. 推到远程: | |
| 72 | + git remote add origin <gitlab-url> # 若尚未添加 | |
| 73 | + git push --no-verify -u origin master | |
| 74 | + # 首次 push 用 --no-verify 跳过 pre-push 的 test.sh; | |
| 75 | + # 本地 DB 尚未就位、scripts/test.sh 此时必然失败,属正常 | |
| 76 | + # push 完成后到 GitLab UI 把 master(或 main)设为 protected | |
| 77 | + | |
| 78 | + 4. main(或 master)就绪后,再运行 /erp-workflow:erp-coding-start | |
| 71 | 79 | ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ |
| 72 | 80 | ``` |
| 73 | 81 | ... | ... |
skills/crosscut/erp-red-flag-check/SKILL.md
| 1 | 1 | --- |
| 2 | 2 | name: erp-red-flag-check |
| 3 | -description: 在每个功能循环步骤和生成重要制品前运行。检查 CLAUDE.md 中的 6 项红旗清单,命中任一项则追加 Blocker 到计划文件并停止。 | |
| 3 | +description: 在每个功能循环步骤和生成重要制品前运行。检查 CLAUDE.md 中的 3 项红旗清单,命中任一项则追加 Blocker 到计划文件并停止。 | |
| 4 | 4 | user-invocable: false |
| 5 | 5 | allowed-tools: Read Write Bash(mysql *) |
| 6 | 6 | --- |
| ... | ... | @@ -11,27 +11,26 @@ allowed-tools: Read Write Bash(mysql *) |
| 11 | 11 | |
| 12 | 12 | ## 说明 |
| 13 | 13 | |
| 14 | -验证 CLAUDE.md § 🚩 静默执行红旗清单中的 6 项均未触发。命中任一项则中断。 | |
| 14 | +验证 CLAUDE.md § 🚩 静默执行红旗清单中的 3 项均未触发。命中任一项则中断。 | |
| 15 | + | |
| 16 | +> 需求歧义 / schema 缺口 / 技术栈外组件引入等场景由各 feature-* skill 的 `AskUserQuestion` 流程承接,不进入本清单,不会在这里命中。 | |
| 15 | 17 | |
| 16 | 18 | ## 调用时机 |
| 17 | 19 | |
| 18 | 20 | - 每个功能循环步骤开始前(3.1-3.5) |
| 19 | 21 | - 生成模块级制品前(模块报告、MR 描述) |
| 20 | -- 用户请求涉及 schema 冲突、技术栈边界或外部依赖时 | |
| 22 | +- 用户请求涉及外部依赖、环境凭据变更时 | |
| 21 | 23 | |
| 22 | -## 检查清单(6 项 — 权威来源:CLAUDE.md) | |
| 24 | +## 检查清单(3 项 — 权威来源:CLAUDE.md) | |
| 23 | 25 | |
| 24 | -1. **需求与 schema 冲突** — 所需字段/表在实时 schema 中不存在 | |
| 25 | -2. **需求本身歧义** — 存在两种或以上合理解读 | |
| 26 | -3. **超技术栈边界** — 需要 CLAUDE.md 技术栈表以外的框架/中间件 | |
| 27 | -4. **测试反复失败** — 同一功能中同一测试连续 10 次修复失败 | |
| 28 | -5. **要改密钥/账密/包名** — 涉及 `docs/07-环境配置.md` 中的人工填写字段 | |
| 29 | -6. **外部接口不可达** — 第三方 API / 证书 / 网络问题 | |
| 26 | +1. **测试反复失败** — 同一功能中同一测试连续 10 次修复失败 | |
| 27 | +2. **要改密钥/账密/包名** — 涉及 `docs/07-环境配置.md` 中的人工填写字段 | |
| 28 | +3. **外部接口不可达** — 第三方 API / 证书 / 网络问题 | |
| 30 | 29 | |
| 31 | 30 | ## 执行步骤 |
| 32 | 31 | |
| 33 | 32 | 1. 读取当前功能的规格/计划文件路径(从对话或 `docs/08` 获取)。 |
| 34 | -2. 逐项检查 6 个红旗。如果全部未命中 → 输出 `red-flag-check: 通过`,退出。 | |
| 33 | +2. 逐项检查 3 个红旗。如果全部未命中 → 输出 `red-flag-check: 通过`,退出。 | |
| 35 | 34 | 3. 命中时: |
| 36 | 35 | - 用 `Read` 读取 `${CLAUDE_SKILL_DIR}/templates/red-flag-block-template.md` |
| 37 | 36 | - 填充槽位(flag_number、flag_name、description、affected_scope、recommendation、decision_needed) |
| ... | ... | @@ -46,5 +45,5 @@ allowed-tools: Read Write Bash(mysql *) |
| 46 | 45 | ## 参考 |
| 47 | 46 | |
| 48 | 47 | - `${CLAUDE_SKILL_DIR}/templates/red-flag-block-template.md` |
| 49 | -- `CLAUDE.md` § 🚩 静默执行红旗清单(权威 6 条) | |
| 48 | +- `CLAUDE.md` § 🚩 静默执行红旗清单(权威 3 条) | |
| 50 | 49 | - `CLAUDE.md` § 🟡 软规则(S2 跨模块改动,不触发红旗但需留痕) | ... | ... |
skills/crosscut/erp-red-flag-check/templates/red-flag-block-template.md
skills/plan/erp-db-design-gen/SKILL.md
| ... | ... | @@ -2,7 +2,7 @@ |
| 2 | 2 | name: erp-db-design-gen |
| 3 | 3 | description: A4 DB 设计生成 + REQ 回填——用 mysql CLI 反查 schema 生成 docs/03-数据库设计文档.md;然后用 Grep 在 docs/01-需求清单/*.md 定位 TBD(A4 自动补) 替换为实际表/字段引用。 |
| 4 | 4 | user-invocable: false |
| 5 | -allowed-tools: Read Write Edit Grep Glob Skill Bash(mysql *) Bash(source *) | |
| 5 | +allowed-tools: Read Write Edit Grep Glob Skill Bash(mysql *) Bash(set *) Bash(. .env.local) | |
| 6 | 6 | --- |
| 7 | 7 | |
| 8 | 8 | **所有输出必须使用中文。** |
| ... | ... | @@ -36,10 +36,10 @@ allowed-tools: Read Write Edit Grep Glob Skill Bash(mysql *) Bash(source *) |
| 36 | 36 | |
| 37 | 37 | ### A. 查询实时 schema |
| 38 | 38 | |
| 39 | -用 `Bash` source `.env.local` 后查询: | |
| 39 | +用 `Bash` 加载 `.env.local` 后查询(用 `set -a; . ...; set +a` 替代 `source`,避免密码中的 shell 特殊字符被展开): | |
| 40 | 40 | |
| 41 | 41 | ```bash |
| 42 | -source .env.local | |
| 42 | +set -a; . .env.local; set +a | |
| 43 | 43 | MYSQL_CMD="mysql -h${DB_HOST} -P${DB_PORT} -u${DB_USER} -p${DB_PASSWORD} -N -B" |
| 44 | 44 | |
| 45 | 45 | # 表列表 + 注释 | ... | ... |
skills/plan/erp-db-init/SKILL.md
| ... | ... | @@ -2,7 +2,7 @@ |
| 2 | 2 | name: erp-db-init |
| 3 | 3 | description: A3 验证 MySQL 连接 + 导出当前 schema 为 `sql/migrations/V1__initial_schema.sql`(Flyway 初始 migration,DDL only)+ 导出当前数据为 `sql/seed-data.sql`(INSERT only)。不执行任何 DDL。 |
| 4 | 4 | user-invocable: false |
| 5 | -allowed-tools: Read Write Edit Glob Skill Bash(mkdir *) Bash(mysql *) Bash(mysqldump *) Bash(source *) Bash(sed *) Bash(cat *) Bash(rm sql/migrations/*.raw) Bash(rm sql/*.raw) Bash(grep *) | |
| 5 | +allowed-tools: Read Write Edit Glob Skill Bash(mkdir *) Bash(mysql *) Bash(mysqldump *) Bash(set *) Bash(. .env.local) Bash(sed *) Bash(cat *) Bash(rm sql/migrations/*.raw) Bash(rm sql/*.raw) Bash(grep *) | |
| 6 | 6 | --- |
| 7 | 7 | |
| 8 | 8 | **所有输出必须使用中文。** |
| ... | ... | @@ -47,12 +47,15 @@ allowed-tools: Read Write Edit Glob Skill Bash(mkdir *) Bash(mysql *) Bash(mysql |
| 47 | 47 | |
| 48 | 48 | ### B. 验证 MySQL 连接 |
| 49 | 49 | |
| 50 | -用 `Bash` 执行(先 `source .env.local` 加载变量): | |
| 50 | +用 `Bash` 执行(先加载 `.env.local` 变量,用 `set -a; . ...; set +a` 避免 shell 展开密码中的特殊字符): | |
| 51 | 51 | |
| 52 | 52 | ```bash |
| 53 | -source .env.local && mysql -h"$DB_HOST" -P"$DB_PORT" -u"$DB_USER" -p"$DB_PASSWORD" -e "USE \`$DB_SCHEMA\`; SHOW TABLES;" | |
| 53 | +set -a; . .env.local; set +a | |
| 54 | +mysql -h"$DB_HOST" -P"$DB_PORT" -u"$DB_USER" -p"$DB_PASSWORD" -e "USE \`$DB_SCHEMA\`; SHOW TABLES;" | |
| 54 | 55 | ``` |
| 55 | 56 | |
| 57 | +> 注:密码中含 `$`、`` ` ``、空格、`!` 等字符时,`.env.local` 需用单引号包裹值,例如 `DB_PASSWORD='p@ss$w0rd!'`。`set -a; . file; set +a` 与 `source` 行为一致但更明确地声明"按 KEY=VALUE 加载并导出",配合单引号可避免展开。 | |
| 58 | + | |
| 56 | 59 | - **成功** → 记录表列表,继续步骤 C。 |
| 57 | 60 | - **失败** → 向用户输出具体错误(认证失败 / schema 不存在 / 主机不可达等),提示检查 `.env.local`,**停下**。 |
| 58 | 61 | |
| ... | ... | @@ -61,7 +64,9 @@ source .env.local && mysql -h"$DB_HOST" -P"$DB_PORT" -u"$DB_USER" -p"$DB_PASSWOR |
| 61 | 64 | 用 `Bash` 执行 mysqldump(**仅 DDL,不含数据**): |
| 62 | 65 | |
| 63 | 66 | ```bash |
| 64 | -mkdir -p sql/migrations && source .env.local && mysqldump --no-data --skip-comments -h"$DB_HOST" -P"$DB_PORT" -u"$DB_USER" -p"$DB_PASSWORD" "$DB_SCHEMA" > sql/migrations/V1__initial_schema.sql.raw | |
| 67 | +mkdir -p sql/migrations | |
| 68 | +set -a; . .env.local; set +a | |
| 69 | +mysqldump --no-data --skip-comments -h"$DB_HOST" -P"$DB_PORT" -u"$DB_USER" -p"$DB_PASSWORD" "$DB_SCHEMA" > sql/migrations/V1__initial_schema.sql.raw | |
| 65 | 70 | ``` |
| 66 | 71 | |
| 67 | 72 | 如果 `mysqldump` 命令不存在,向用户输出具体错误(提示安装 `mysql-client` / `brew install mysql-client` 等)并**停下**(mysql 和 mysqldump 是 A0 `erp-project-init` 的前置依赖,正常情况下应已就绪)。 |
| ... | ... | @@ -73,7 +78,7 @@ mkdir -p sql/migrations && source .env.local && mysqldump --no-data --skip-comme |
| 73 | 78 | ```bash |
| 74 | 79 | PROJECT="<从 CLAUDE.md 读到的项目名称>" |
| 75 | 80 | TS="$(date -u +%FT%TZ)" |
| 76 | -source .env.local | |
| 81 | +set -a; . .env.local; set +a | |
| 77 | 82 | { |
| 78 | 83 | sed -e "s|{{project_name}}|$PROJECT|g" \ |
| 79 | 84 | -e "s|{{timestamp}}|$TS|g" \ |
| ... | ... | @@ -94,7 +99,8 @@ rm sql/migrations/V1__initial_schema.sql.raw |
| 94 | 99 | 用 `Bash` 执行 mysqldump(**仅数据,INSERT only**): |
| 95 | 100 | |
| 96 | 101 | ```bash |
| 97 | -source .env.local && mysqldump --no-create-info --complete-insert --skip-comments --skip-extended-insert \ | |
| 102 | +set -a; . .env.local; set +a | |
| 103 | +mysqldump --no-create-info --complete-insert --skip-comments --skip-extended-insert \ | |
| 98 | 104 | -h"$DB_HOST" -P"$DB_PORT" -u"$DB_USER" -p"$DB_PASSWORD" "$DB_SCHEMA" > sql/seed-data.sql.raw |
| 99 | 105 | ``` |
| 100 | 106 | |
| ... | ... | @@ -103,7 +109,7 @@ source .env.local && mysqldump --no-create-info --complete-insert --skip-comment |
| 103 | 109 | ```bash |
| 104 | 110 | PROJECT="<从 CLAUDE.md 读到的项目名称>" |
| 105 | 111 | TS="$(date -u +%FT%TZ)" |
| 106 | -source .env.local | |
| 112 | +set -a; . .env.local; set +a | |
| 107 | 113 | { |
| 108 | 114 | sed -e "s|{{project_name}}|$PROJECT|g" \ |
| 109 | 115 | -e "s|{{timestamp}}|$TS|g" \ |
| ... | ... | @@ -146,7 +152,7 @@ rm sql/seed-data.sql.raw |
| 146 | 152 | |
| 147 | 153 | ## 不变量 |
| 148 | 154 | |
| 149 | -- 密码通过 `.env.local` 经 `source` 注入,不硬编码在命令里。 | |
| 155 | +- 密码通过 `.env.local` 以 `set -a; . .env.local; set +a` 方式导出到环境变量,不硬编码在命令里;特殊字符需用单引号包裹。 | |
| 150 | 156 | - 本 skill **只** 产生 V1 initial migration 和 seed-data.sql 快照;后续 V2/V3 及业务数据变化由 B 阶段 `erp-feature-tdd` 在 REQ 实现时写入。 |
| 151 | 157 | |
| 152 | 158 | ## 参考 | ... | ... |
skills/plan/erp-downstream-gen/SKILL.md
| ... | ... | @@ -156,10 +156,27 @@ docs/08 已由 A0 erp-project-init 创建(含 Plan 进度骨架)。本步骤 |
| 156 | 156 | |
| 157 | 157 | ⚠️ 进入 B 阶段前必须完成: |
| 158 | 158 | 1. 人工通读 docs/01~10 + CLAUDE.md + sql/migrations/V1 + 各 scripts/* |
| 159 | - 2. 把全部 Plan 产物 commit 到 main 分支: | |
| 159 | + | |
| 160 | + 2. 把全部 Plan 产物 commit: | |
| 160 | 161 | git add -A && git commit -m "chore: plan phase A0~A5 done" |
| 161 | - 3. 建 Plan MR 提交团队审核,合并后 main 成为 B 阶段每个模块分支的基线 | |
| 162 | - 4. MR 合并后再运行 /erp-workflow:erp-coding-start 进入 B 阶段 | |
| 162 | + | |
| 163 | + 3. 推到远程,按仓库状态二选一: | |
| 164 | + | |
| 165 | + 情况 A — 远程仓库是全新的(尚无 main / master): | |
| 166 | + git remote add origin <gitlab-url> # 若尚未添加 | |
| 167 | + git push --no-verify -u origin master | |
| 168 | + # 首次 push 用 --no-verify 跳过 pre-push 的 test.sh; | |
| 169 | + # 本地 DB 尚未就位、scripts/test.sh 此时必然失败,属正常 | |
| 170 | + # push 完成后到 GitLab UI 把 master(或 main)设为 protected | |
| 171 | + | |
| 172 | + 情况 B — 远程已有 main 需要走 MR 审核: | |
| 173 | + git checkout -b plan-init | |
| 174 | + git push -u origin plan-init | |
| 175 | + # 在 GitLab 打开 plan-init → main 的 MR,审核并合并 | |
| 176 | + | |
| 177 | + 4. main(或 master)就绪后,再运行 /erp-workflow:erp-coding-start | |
| 178 | + 进入 B 阶段。届时 .env.local 应指向本地 MySQL(非共享远程 DB), | |
| 179 | + 否则 B 阶段每次测试闸门都会因 setup-test-db.sh 的防护失败。 | |
| 163 | 180 | ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ |
| 164 | 181 | ``` |
| 165 | 182 | ... | ... |
skills/plan/erp-project-init/templates/CLAUDE-template.md
| ... | ... | @@ -63,7 +63,7 @@ |
| 63 | 63 | 4. 自动 git push(.githooks/pre-push 会再执行一遍 scripts/test.sh 作为硬闸门) |
| 64 | 64 | + glab mr create,报告嵌入 MR 描述 |
| 65 | 65 | 5. 人工 review MR → Approve + Merge(人工动作,唯一人工介入点) |
| 66 | -6. 下次用户运行 `/erp-workflow:erp-coding-start` 时,入口自动检测到本模块 `glab mr view state=merged` → `git checkout main && git pull --ff-only` 同步远程 → 扫描下一模块并派发 | |
| 66 | +6. 下次用户运行 `/erp-workflow:erp-coding-start` 时,入口自动检测到本模块 `glab mr view state=merged`,探测默认分支(main / master)后 `git checkout <默认分支> && git pull --ff-only` 同步远程 → 扫描下一模块并派发 | |
| 67 | 67 | 7. 你**不需要**手工 Edit docs/08(模块元数据不变;下次 coding-start 自动扫描 MR state 判定是否完成) |
| 68 | 68 | ``` |
| 69 | 69 | |
| ... | ... | @@ -96,7 +96,7 @@ |
| 96 | 96 | |
| 97 | 97 | 两层嵌套循环的详细步骤**全部固化到 skills**,CLAUDE.md 不展开。入口调 `/erp-workflow:erp-coding-start`,自动分发: |
| 98 | 98 | |
| 99 | -- **模块循环(外层,Layer 2)** → `erp-module-start` → `erp-local-test-gate`(commit test-gate.md)→ `erp-module-report`(commit 模块报告 + cross-module log)→ `erp-mr-create`(worktree clean 校验 → push → 创建 MR → 追加 MR URL 到报告并 commit → 写 `MR: !<iid>` 到 docs/08 并 commit → 再次 push)→ 人工 Approve+Merge → 下次运行 `/erp-workflow:erp-coding-start` 扫描到本模块 `glab mr view merged` → `git pull --ff-only main` → 推进下一模块 | |
| 99 | +- **模块循环(外层,Layer 2)** → `erp-module-start` → `erp-local-test-gate`(commit test-gate.md)→ `erp-module-report`(commit 模块报告 + cross-module log)→ `erp-mr-create`(worktree clean 校验 → push → 创建 MR → 追加 MR URL 到报告并 commit → 写 `MR: !<iid>` 到 docs/08 并 commit → 再次 push)→ 人工 Approve+Merge → 下次运行 `/erp-workflow:erp-coding-start` 扫描到本模块 `glab mr view merged` → 探测默认分支并 `git pull --ff-only` → 推进下一模块 | |
| 100 | 100 | - **功能循环(内层,Layer 3,每个 REQ-XXX-NNN 走一遍)** → `erp-feature-brainstorm` → `erp-feature-plan` → `erp-feature-tdd` → `erp-feature-verify` → `erp-feature-review` |
| 101 | 101 | |
| 102 | 102 | **本地测试闸门**: `erp-local-test-gate` 是 MR 前的唯一硬闸门,子会话执行 `scripts/test.sh`:脚本先由 `setup-test-db.sh` 清空库 → build / lint → 执行测试(Spring Boot 启动时 Flyway 自动 apply `sql/migrations/V*.sql`)→ e2e → 再次清库。详见 § 🧪 自测要求。`.githooks/pre-push` 在 push 时会再次执行 `scripts/test.sh` 作为兜底;`git push --no-verify` 被 hook `deny-no-verify.sh` 硬拦截。本项目不配置 GitLab CI/CD。 |
| ... | ... | @@ -214,12 +214,11 @@ refactor(common): 统一响应格式包装 |
| 214 | 214 | |
| 215 | 215 | | # | 红旗 | 例子 | |
| 216 | 216 | | - | --- | --- | |
| 217 | -| 1 | **需求与 schema 不一致** | REQ 提到的字段/表在现有 schema 里不存在 → 先向用户确认「加一个 migration 新增 / 修正 REQ 理解」;得到答复后继续,**不走下方 Blocker 文件流程** | | |
| 218 | -| 2 | **需求本身歧义** | spec 中某规则有两种合理解读,CC 无法判断 | | |
| 219 | -| 3 | **超技术栈边界** | 需要引入 `docs/tech-stack.md` 以外的框架 / 中间件 | | |
| 220 | -| 4 | **测试反复失败** | 同一测试同一功能内连续 **10 次**修复失败 | | |
| 221 | -| 5 | **要改密钥 / 账密 / 包名** | `docs/07-环境配置.md` 里由人工标注必须填的字段 | | |
| 222 | -| 6 | **外部接口不可达** | 第三方 API 无法连接、证书失效等环境问题 | | |
| 217 | +| 1 | **测试反复失败** | 同一测试同一功能内连续 **10 次**修复失败 | | |
| 218 | +| 2 | **要改密钥 / 账密 / 包名** | `docs/07-环境配置.md` 里由人工标注必须填的字段 | | |
| 219 | +| 3 | **外部接口不可达** | 第三方 API 无法连接、证书失效等环境问题 | | |
| 220 | + | |
| 221 | +> 其余需要人类判断的场景(需求歧义 / schema 缺口 / 技术栈外组件引入)一律走普通 `AskUserQuestion` Q&A,不升格为红旗、不写 Blocker 文件。见下方「📘 技术栈外组件的处理规则」与各 feature-* skill 的 Q&A 流程。 | |
| 223 | 222 | |
| 224 | 223 | **命中红旗时的固定动作:** |
| 225 | 224 | |
| ... | ... | @@ -232,7 +231,7 @@ refactor(common): 统一响应格式包装 |
| 232 | 231 | ```markdown |
| 233 | 232 | ## ⚠️ 需要人工决策 |
| 234 | 233 | |
| 235 | -**红旗编号**: [1–6 中的某一条] | |
| 234 | +**红旗编号**: [1–3 中的某一条] | |
| 236 | 235 | **问题描述**: [详细描述] |
| 237 | 236 | **影响范围**: [影响哪些模块 / 功能] |
| 238 | 237 | **我的建议**: [初步判断,可选] |
| ... | ... | @@ -241,6 +240,18 @@ refactor(common): 统一响应格式包装 |
| 241 | 240 | |
| 242 | 241 | --- |
| 243 | 242 | |
| 243 | +## 📘 技术栈外组件的处理规则 | |
| 244 | + | |
| 245 | +brainstorm / plan 阶段若发现需要 `docs/04-技术规范.md § 零` 技术栈表之外的框架、中间件或关键库: | |
| 246 | + | |
| 247 | +1. 用 `AskUserQuestion` 询问用户(选项至少含:接受引入 / 换方案 / 拒绝) | |
| 248 | +2. **接受** → 同会话直接在 `docs/04 § 零` 追加一行 → 继续流程 | |
| 249 | +3. **换方案 / 拒绝** → 视为常规歧义澄清,继续 Q&A 收敛 | |
| 250 | + | |
| 251 | +不写 Blocker 文件,不中断流程。 | |
| 252 | + | |
| 253 | +--- | |
| 254 | + | |
| 244 | 255 | ## 🟡 软规则(允许继续,但有强制后续动作) |
| 245 | 256 | |
| 246 | 257 | 以下情况 **不触发中断**,CC 可自行继续推进,但必须在约定位置留痕,模块完成时统一审计。漏留痕 = 红旗。 | ... | ... |
skills/plan/erp-skeleton-gen/SKILL.md
| ... | ... | @@ -101,7 +101,7 @@ cp "${CLAUDE_SKILL_DIR}/templates/scripts-setup-test-db-template.sh" scripts/set |
| 101 | 101 | |
| 102 | 102 | ```bash |
| 103 | 103 | #!/usr/bin/env bash |
| 104 | -# scripts/test.sh —— 合并到 main 前的唯一硬闸门。 | |
| 104 | +# scripts/test.sh —— 合并到默认分支(main / master)前的唯一硬闸门。 | |
| 105 | 105 | # 顺序:setup-db → build → lint → unit+integration → e2e → reset-db |
| 106 | 106 | # 由 .githooks/pre-push 和 erp-local-test-gate skill(通过子会话)调用。 |
| 107 | 107 | ... | ... |
skills/plan/erp-skeleton-gen/templates/env-local-template
| 1 | -DB_HOST=【人工填写:MySQL host,例如 localhost】 | |
| 1 | +# .env.local — 本地开发凭据(入 .gitignore,不提交) | |
| 2 | +# | |
| 3 | +# 规则: | |
| 4 | +# 1. 值含 `$`、反引号、空格、`!` 等 shell 特殊字符时,必须用单引号包裹: | |
| 5 | +# DB_PASSWORD='p@ss$w0rd!' | |
| 6 | +# 否则 `set -a; . .env.local; set +a` 会做变量展开导致密码错乱。 | |
| 7 | +# 2. DB_HOST 建议保持 localhost / 127.0.0.1;非本地 host 会被 scripts/setup-test-db.sh 防护拒绝。 | |
| 8 | +# 3. DB_SCHEMA 建议命名含 test / _dev / _local / _ci,避免与生产库同名。 | |
| 9 | + | |
| 10 | +DB_HOST=【人工填写:MySQL host,推荐 localhost】 | |
| 2 | 11 | DB_PORT=【人工填写:MySQL port,默认 3306】 |
| 3 | 12 | DB_USER=【人工填写:开发账号名】 |
| 4 | -DB_PASSWORD=【人工填写:对应密码】 | |
| 5 | -DB_SCHEMA=【人工填写:schema 名,例如 erp_dev】 | |
| 13 | +DB_PASSWORD=【人工填写:对应密码,含特殊字符时用单引号包裹】 | |
| 14 | +DB_SCHEMA=【人工填写:schema 名,推荐含 test/_dev/_local,例如 erp_dev】 | |
| 6 | 15 | JWT_SECRET=【人工填写:JWT 签名密钥,256+ bit 随机串】 | ... | ... |
skills/plan/erp-skeleton-gen/templates/scripts-setup-test-db-template.sh
| ... | ... | @@ -7,14 +7,44 @@ |
| 7 | 7 | # - scripts/test.sh 开头:清空库,让 Spring 启动时 Flyway 从 V1 开始重放所有 migration |
| 8 | 8 | # - scripts/test.sh 结尾:清空库,避免测试遗留污染下次运行 |
| 9 | 9 | # - 手动调试时:reset 到零状态 |
| 10 | +# | |
| 11 | +# 防护:本脚本只允许在本地 host + 测试库名上执行;非预期目标会被拒绝, | |
| 12 | +# 避免 .env.local 误指向 staging/prod 时触发不可逆 DROP。 | |
| 10 | 13 | |
| 11 | 14 | set -euo pipefail |
| 12 | 15 | |
| 13 | -source "$(dirname "$0")/../.env.local" | |
| 16 | +ENV_FILE="$(dirname "$0")/../.env.local" | |
| 17 | +[ -f "$ENV_FILE" ] || { echo "[setup-test-db] ⚠️ .env.local 不存在($ENV_FILE)" >&2; exit 1; } | |
| 18 | + | |
| 19 | +# 用 set -a 加载,让 KEY=VALUE 导出为环境变量;密码中含特殊字符时 .env.local 请用单引号包裹 | |
| 20 | +set -a; . "$ENV_FILE"; set +a | |
| 21 | + | |
| 22 | +# 防护 1:只允许本地 host(localhost / 127.0.0.1 / ::1) | |
| 23 | +case "${DB_HOST:-}" in | |
| 24 | + localhost|127.0.0.1|::1) ;; | |
| 25 | + *) | |
| 26 | + echo "[setup-test-db] ⚠️ 拒绝在非本地 host (${DB_HOST}) 上执行 DROP DATABASE" >&2 | |
| 27 | + echo " 如确需对远程 DB 重置(少见,常属误配),请显式声明:TEST_DB_ALLOW_REMOTE=1 $0" >&2 | |
| 28 | + [ "${TEST_DB_ALLOW_REMOTE:-0}" = "1" ] || exit 1 | |
| 29 | + ;; | |
| 30 | +esac | |
| 31 | + | |
| 32 | +# 防护 2:schema 名需像测试/开发库(含 test / _dev / _local),否则要求显式确认 | |
| 33 | +case "${DB_SCHEMA:-}" in | |
| 34 | + *test*|*_dev|*_local|*_ci) | |
| 35 | + ;; | |
| 36 | + *) | |
| 37 | + echo "[setup-test-db] ⚠️ schema '${DB_SCHEMA}' 不像测试库(期望命名含 test / _dev / _local / _ci)" >&2 | |
| 38 | + echo " 如确为期望行为,请显式声明:TEST_DB_ALLOW_PROD_NAME=1 $0" >&2 | |
| 39 | + [ "${TEST_DB_ALLOW_PROD_NAME:-0}" = "1" ] || exit 1 | |
| 40 | + ;; | |
| 41 | +esac | |
| 42 | + | |
| 43 | +# 防护 3:显式 banner,让人看见自己在 drop 什么 | |
| 44 | +echo "[setup-test-db] 即将 DROP + CREATE \`${DB_SCHEMA}\` on ${DB_HOST}:${DB_PORT}" | |
| 14 | 45 | |
| 15 | 46 | MYSQL_CMD="mysql -h${DB_HOST} -P${DB_PORT} -u${DB_USER} -p${DB_PASSWORD}" |
| 16 | 47 | |
| 17 | -echo "[setup-test-db] drop + create database ${DB_SCHEMA}" | |
| 18 | 48 | $MYSQL_CMD -e "DROP DATABASE IF EXISTS \`${DB_SCHEMA}\`; CREATE DATABASE \`${DB_SCHEMA}\` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;" |
| 19 | 49 | |
| 20 | 50 | echo "[setup-test-db] done — schema will be applied by Flyway when Spring Boot starts" | ... | ... |