SKILL.md 9.78 KB

name: erp-coding-start description: B 阶段(Coding)入口。先验证 Plan 已完成;按 docs/02 § 二 REQ 开发顺序清单扫描,对每个 REQ 所属模块用 docs/08 的 MR: 字段 + GitLab API state 判定是否完成——merged 跳过, 或 opened/closed 选为当前模块并派发到 erp-module-start。派发前自动探测默认分支(main / master)并 git checkout + pull --ff-only 保持 base 最新。 user-invocable: true

allowed-tools: Skill Read Glob Grep Bash(curl ) Bash(jq *) Bash(git branch *) Bash(git checkout *) Bash(git pull *) Bash(git status *) Bash(git symbolic-ref *) Bash(sed *) Bash(mkdir -p .tmp) Bash(rm -f .tmp/)

所有输出必须使用中文。

B 阶段(Coding)的入口分发器。职责:验证 Plan 已完成 → 按 docs/02 § 二 REQ 序 + MR state 定位当前模块 → 切回默认分支并同步远程 → 派发 erp-module-start。不直接生成任何文件。开发顺序以 docs/02 § 二 为准;完成判定以 docs/08 条目的 MR: 字段 + GitLab API state 为准(curl 调用,凭据读 .env.localGITLAB_API_URL / GITLAB_TOKEN / GITLAB_PROJECT_ID)。默认分支(mainmaster)在步骤 4 自动探测,不硬编码。

执行步骤

步骤 1:确认 docs/08 存在

Glob 检查 docs/08-模块任务管理.md

  • 不存在 → 打印"⚠️ 项目尚未初始化,请先运行 /erp-workflow:erp-plan-start"并停下。

步骤 2:Plan 完成性检查

Grepdocs/08-模块任务管理.md 搜索 ^- \[ \] A[0-5](pattern 可以直接匹配父项未勾的情况;也可以用更宽的 ^[[:space:]]*- \[ \].*A[0-5] 覆盖子项)。

  • 命中任一 A 未勾 → 打印: ``` ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ [erp-coding-start] ⚠️ Plan 尚未完成

docs/08 § 一 还有未勾选项,请先运行: /erp-workflow:erp-plan-start

继续 Plan 阶段直到 A5 下游文档生成完成,再回来运行 coding-start。 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

  **停下**。

- 无命中 → Plan 已完成,进入步骤 3。

### 步骤 3:按 docs/02 REQ 序 + MR state 找当前模块

1. 用 `Read` 读取 `docs/02-开发计划.md` 的 § 二;用 `Grep`(pattern `^\|\s*[0-9]+\s*\|\s*\*\*(REQ-[A-Z0-9]+-[0-9]+)\*\*\s*\|\s*(module_\w+)`,`-n`)抽取所有表格数据行,按行号升序得 `req_order[]`,每项含 `req_id` + `module_id`。
2. 若 `req_order` 为空 → 打印错误并**停下**(与原逻辑相同,略)。
3. **初始化模块完成缓存 `module_merged[module_id → bool]`**(空)。
4. 按序遍历 `req_order[]`:
   - 若 `module_merged[module_id]` 已有缓存:
     - `true` → 跳过本 REQ,继续下一个
     - `false` → `current_module = module_id`,结束遍历,进入步骤 4
   - 未缓存 → 读取 docs/08 § 二 该模块条目的 `  - MR:` 字段:
     - `MR: —` → `module_merged[module_id] = false`;`current_module = module_id`,结束遍历
     - `MR: !<iid>` → 先 `Bash`: `set -a; . ./.env.local; set +a` 加载凭据,然后**分步校验 HTTP 状态 + 返回条数 + state 枚举**(v3 API 用 iid 过滤列表):
       ```bash
       mkdir -p .tmp
       HTTP_CODE=$(curl -sS -o .tmp/mr.json -w '%{http_code}' \
         --header "PRIVATE-TOKEN: ${GITLAB_TOKEN}" \
         "${GITLAB_API_URL}/projects/${GITLAB_PROJECT_ID}/merge_requests?iid=<iid>")
       ```
       **硬停条件**(命中任一则打印诊断横幅并**停下**,不派发;任何"查不到就假设未 merged"的静默处理都禁止):
       1. `HTTP_CODE != 200`:API 不可达 / token 错 / URL 错
       2. `HTTP_CODE == 200` 但 `jq 'length' .tmp/mr.json != 1`:docs/08 记了 `!<iid>` 但远程查不到对应 MR(数据不一致)
       3. `state = jq -r '.[0].state' .tmp/mr.json` 不在 `{merged, opened, closed}` 三个合法值里

       诊断横幅模板:
       ```
       ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
        [erp-coding-start] ⚠️ 无法确定 MR !<iid>(模块 <module_id>)的状态

        原因: <HTTP <code> | 查不到 MR | state=<异常值>>
        API : ${GITLAB_API_URL}/projects/${GITLAB_PROJECT_ID}
        body: <jq -r '.message // .error // .' .tmp/mr.json | head -c 200>

        请按下列顺序核查:
          1. .env.local 的 GITLAB_TOKEN 是否有效(在 GitLab Profile → Private token 页检查)
          2. GITLAB_API_URL 前缀 / v3 路径 / host 是否匹配你的 GitLab 部署
          3. GITLAB_PROJECT_ID 是否是该项目的 URL-encoded 路径或数字 ID
          4. docs/08 记的 iid 是否存在于 GitLab 项目的 MR 列表

        修正后重跑 /erp-workflow:erp-coding-start。
       ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
       ```
       清理:`rm -f .tmp/mr.json`。

       校验通过后按 state 分派:
       - `merged` → `module_merged[module_id] = true`,跳过本 REQ
       - `opened` / `closed` → `module_merged[module_id] = false`;`current_module = module_id`,结束遍历
5. 全遍历完仍无命中(所有模块都 merged) → 打印:

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ [erp-coding-start] ✅ 所有模块已完成

docs/02 § 二 清单中每个 REQ 所属模块的 MR 都已 merged。项目结束。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

   并**停下**。
6. 命中后:记录 `current_module` 的 `MR:` 字段值(`—` / `!<iid>-opened` / `!<iid>-closed` / `!<iid>-查不到`,用于步骤 5 横幅展示)。

### 步骤 4:探测默认分支 + 切回并同步远程(准备 module-start 切新分支的干净 base)

4.0 **探测默认分支**:

```bash
DEFAULT_BRANCH=$(git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null | sed 's|refs/remotes/origin/||')
if [ -z "$DEFAULT_BRANCH" ]; then
  # HEAD 未设置,回退:在 main / master 里取第一个实际存在的远程分支
  DEFAULT_BRANCH=$(git branch -r --format='%(refname:short)' | grep -E '^origin/(main|master)$' | head -1 | sed 's|^origin/||')
fi
  • DEFAULT_BRANCH 为空 → 打印错误并停下(既无 origin/main 也无 origin/master,说明远程未就绪,提示用户先完成 Plan 的首次 push 或 git remote set-head origin -a 设置 HEAD)。

4.1 切回 + 同步

  • Bash: git branch --show-currentcurrent_branch
  • current_branch != $DEFAULT_BRANCH

    • Bash: git status --porcelain;非空 → 打印: ``` ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ [erp-coding-start] ⚠️ 当前分支 有未提交改动,无法切换到

    请手工处理后重新运行 /erp-workflow:erp-coding-start。 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

    并**停下**。
    - `Bash`: `git checkout "$DEFAULT_BRANCH"`。
    
  • Bash: git pull --ff-only origin "$DEFAULT_BRANCH"

    • 失败(非 fast-forward / 网络 / 冲突)→ 打印错误横幅: ``` ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ [erp-coding-start] ⚠️ 同步 失败

    本地 无法 fast-forward 到 remote。请手工处理: git status git log ..origin/ # 远程领先的 commit git log origin/.. # 本地未推的 commit 修复后重新运行 /erp-workflow:erp-coding-start。 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

    并**停下**。
    

步骤 5:打印横幅并分发

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 [erp-coding-start]
 阶段:B 编码
 当前模块:<current_module>
 MR 状态:<未建 | opened | closed | 查不到>
 下一步:invoke erp-module-start
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

然后立即用 Skill 工具调用 erp-module-start

分发前先调用 erp-red-flag-check;命中红旗则停在此不分发。

设计要点

  • 完成判定直接读取 MR: 字段 + GitLab API state(curl,PRIVATE-TOKEN 头):MR 未 merge 前 docs/08 没有任何"已完成"标记;用户提前触发 coding-start 时,步骤 3 扫描到 MR opened 仍会选中当前模块,module-start 会 git checkout module-<id> 回到原分支继续,不会跳到下一模块。
  • 每次派发前都 pull 默认分支:代码同步的同时,也保证 module-start 切出新分支时 base 新鲜。默认分支由步骤 4.0 探测(main 或 master),不硬编码。

参考

  • docs/02-开发计划.md § 二 开发顺序清单(分发权威)
  • docs/08-模块任务管理.md § 二(模块元数据,含 MR: 字段)
  • CLAUDE.md(项目指令)
  • erp-plan-start(姊妹入口,A 阶段)