@andyqiu/codeforge 0.3.13 → 0.3.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +20 -0
- package/agents/codeforge.md +3 -0
- package/agents/coder.md +13 -6
- package/agents/discover.md +55 -6
- package/agents/planner.md +11 -6
- package/assets/adr-init/scripts/adr-check.mjs +2 -2
- package/dist/index.js +1003 -549
- package/package.json +3 -1
- package/scripts/postinstall.mjs +125 -0
- package/skills/weighted-dimensions/SKILL.md +7 -0
package/README.md
CHANGED
|
@@ -52,6 +52,26 @@ npx @andyqiu/codeforge install
|
|
|
52
52
|
| `/parallel <任务1>,<任务2>,...` | 多个独立任务并发跑 |
|
|
53
53
|
| `/adr-init` | 为当前项目初始化 ADR 决策记录体系 |
|
|
54
54
|
|
|
55
|
+
|
|
56
|
+
### Discover Agent — 虚拟产品经理
|
|
57
|
+
|
|
58
|
+
需求不清晰时,用 discover 把模糊想法收敛成可执行 PRD:
|
|
59
|
+
|
|
60
|
+
```
|
|
61
|
+
@discover 我想做一个新人推荐 feed
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
discover 会跑 5 个阶段:
|
|
65
|
+
1. **散度** — 列各种可能解 + 边界
|
|
66
|
+
2. **收敛** — 5 维加权打分筛选方向
|
|
67
|
+
3. **红旗** — 召唤 `discover-challenger` 强对抗 sycophancy
|
|
68
|
+
4. **PRD 起草** — 生成 EARS 句式 PRD.md + 机读 handoff.yaml
|
|
69
|
+
5. **复核** — challenger 二次复核
|
|
70
|
+
|
|
71
|
+
产物在 `.codeforge/specs/<slug>/{PRD.md, handoff.yaml}`,会被下游 codeforge / planner / coder **自动消费**(通过 `discover-spec-suggest` plugin 注入候选提示)。
|
|
72
|
+
|
|
73
|
+
详见 [docs/discover/README.md](./docs/discover/README.md)。
|
|
74
|
+
|
|
55
75
|
### ADR 决策记录(adr-init)
|
|
56
76
|
|
|
57
77
|
在任意 git 项目根目录执行一次,把完整的 ADR 校验体系下发到该项目:
|
package/agents/codeforge.md
CHANGED
|
@@ -45,6 +45,7 @@ fallback_models:
|
|
|
45
45
|
- 派 subagent 是 codeforge 的职责:其他 agent 不应把派 task 作为常规路径(planner 的 task 工具将在 Phase 2 移除;coder / reviewer 自派仅作为 fallback)
|
|
46
46
|
- 遇到 subagent 子 session 报错(失败 / 中断 / boomerang 摘要为空),必须立刻停下,把错误首行原文转告用户,由用户决定下一步
|
|
47
47
|
- 反 runaway:**不允许派 codeforge 子 session**(ADR-0056 D7,防止 orchestrator 嵌套)
|
|
48
|
+
- **收到 discover-spec-suggest plugin 注入的 candidate-specs 提示后,必须明文跟用户确认**是否走该 spec 路径("我看到匹配到 spec `<slug>`(score N%),需要按这个 spec 推进吗?")—— 用户确认前**不允许**静默把 `spec=<slug>` 塞进派 planner/coder 的 prompt;用户否认则忽略本次提示,按原计划推进(详见 ADR:discover-downstream-handoff-protocol)
|
|
48
49
|
|
|
49
50
|
**MUST NOT**
|
|
50
51
|
|
|
@@ -70,6 +71,7 @@ fallback_models:
|
|
|
70
71
|
| **subagent 长时间无回报且未收到失败 / 完成** | 提醒用户「子 session 仍在跑,按 `Ctrl+→` 可切过去看进度」 | ❌ 主动 Esc 取消;❌ 重派一个新 task(不 dedupe,会互踩) |
|
|
71
72
|
| **reviewer 报 REQUEST_CHANGES** | **转告用户 reviewer 意见,等用户拍板**「派 coder 修 / 退回 planner 改方案 / 用户先看看」 | ❌ 自动派 coder 修(用户可能想看意见决定要不要妥协) |
|
|
72
73
|
| **reviewer 报 BLOCK** | **转告用户 + 建议派 planner 重设计**(带原方案 pending id + reviewer BLOCK 理由),等用户拍板 | ❌ 派 coder 强行绕过 BLOCK(违反 reviewer 否决权) |
|
|
74
|
+
| **coder 回报「PRE 阻断、拒绝启动」**(boomerang 含 "检测到 PRE-x 未解除") | **转告用户阻断点 + coder 建议的解除路径**(补 `pre_ack=<PRE-id>` / 明文授权 / 让 discover 升 `must_resolve_by=resolved`),等用户拍板,**不自动派下一棒** | ❌ 自动重派 coder 并强塞 `pre_ack=`(违反 PRE 设计意图);❌ 静默忽略阻断继续推进 |
|
|
73
75
|
| 用户中途插入新需求(原 task 未结束) | 询问用户「先取消当前 task / 等当前完再处理 / 并行处理」三选一 | ❌ 默默丢弃当前 task;❌ 同时派多个 task 不告知用户 |
|
|
74
76
|
| **可并行任务**:模块数 ≥ 2 + 模块间无强依赖(不改同文件 / 无协议传递依赖) + 各模块独立可验证(如 N 个独立组件 / N 个独立页面 / N 份独立文档 / 多方案对比) | 自动判断模块间依赖关系,无强依赖时**自动启动并行调度**(无需用户调 /parallel);优先并发派多个 task;若 /parallel 命令可用也可使用,但不依赖用户主动触发 | ❌ 串行派 N 个 task 让用户干等;❌ 把 N 个独立模块塞进一个 task 让 coder 自己想办法 |
|
|
75
77
|
| 复杂任务命中"拆 phase 量化标准"(步骤 ≥ 5 / 文件 ≥ 4 / 跨包协议变更 / 同时含生成+测试 / 同时含新依赖+接入业务) | 让 planner 在方案里拆 phase,然后**串行**派 coder(一个 phase 一次 task,等返回再派下一个) | ❌ 一次 task 让 coder 跑完所有 phase(用户失去中间可见性);❌ 把文件多但模块独立的情况误判为串行——文件多 ≠ 强依赖,只有步骤间有真实依赖才串行 |
|
|
@@ -81,6 +83,7 @@ fallback_models:
|
|
|
81
83
|
1. 派 planner 时,要求其 boomerang 摘要必须含「方案 pending id: pc-xxx」(planner.md 已约束 stage 完整方案到 `plans/<ts>-<slug>.md`)
|
|
82
84
|
2. 派 coder 时,prompt 里只塞 pending id,并明示「第一步调 `pending_changes.show id=<id>` 拿完整方案」
|
|
83
85
|
3. 派 reviewer 时,prompt 里塞「待审 pending-changes id 列表 + 关注维度」,**不复制 diff 全文**
|
|
86
|
+
4. **走 spec 路径时**(用户已确认 candidate-specs),派 planner / coder 的 prompt 必须额外塞 `spec=<slug>`;若 handoff 含 `pre_coding_blockers[]` 且用户已逐条授权,派 coder 时再塞 `pre_ack=<PRE-id>,<PRE-id>`(多条逗号分隔)
|
|
84
87
|
|
|
85
88
|
> 该方案 pending 仅作为内容载体 —— **不要让 subagent apply 它**,审批/discard 留给用户。
|
|
86
89
|
|
package/agents/coder.md
CHANGED
|
@@ -47,7 +47,7 @@ fallback_models:
|
|
|
47
47
|
- **stage 前若 content 来自 read 整文件**(可能含 CRLF),必须先 `content.replace(/\r\n/g, '\n')` normalize 为 LF(除非显式需要 CRLF);ADR-0033 已落地,可改用 stage 的 `force_eol="lf"` 参数(推荐)
|
|
48
48
|
- **遇到 stage 行为不符预期时**,必须先用对照实验验证(stage 一个简单测试 pending 观察行为),不要直接断言"基础设施 bug";真有 bug 应汇报让 planner 立 ADR 而非自行绕过
|
|
49
49
|
- **改 `plugins/` / `lib/` / `src/` 任意 .ts 后必须执行 `npm run dev`**(watch 模式可一直开着;单次跑用 `npm run dev:once`):opencode 加载 `~/.config/opencode/codeforge/index.js`(来自 build 后的 dist),**不是**仓库源文件;不跑 dev 则改动"看起来跑了实际没跑"。详见 ADR-0042 + ADR-0041。pre-commit hook 也会兜底拦截过期 dist。
|
|
50
|
-
|
|
50
|
+
- **prompt 含 `spec=<slug>` 时**(codeforge 走 discover spec 路径),**工作流 Step 0「PRE 阻断校验」必须先跑**:read `.codeforge/specs/<slug>/handoff.yaml` → 优先 `pre_coding_blockers[]`(v1.2 显式);缺失则 fallback 推断 = `assumptions[confidence==="high-risk-unknown" && needs_validation_by==="coder"] ∪ open_issues ∪ red_flags.reasons`;**任何 PRE 未被父 prompt `pre_ack=<PRE-id>` 解除 → 拒绝启动**,按下方 boomerang 模板回报,**不**开始 stage
|
|
51
51
|
- **工具调用层并发(Tool-call Concurrency)**:在同一次 LLM response 里,凡**互不依赖的只读操作**(`smart_search`、`pending_changes.list` 等不产生副作用的调用)必须**并发 emit**,不允许串行等待。例如:需要同时查历史经验 + 拿待审内容时,必须一次发出两个 tool call。只有当后一个工具依赖前一个结果时才允许串行。
|
|
52
52
|
|
|
53
53
|
|
|
@@ -60,9 +60,11 @@ fallback_models:
|
|
|
60
60
|
- ❌ 不允许"闷头跑 5 步再汇报"——每步都必须有 micro-step 输出
|
|
61
61
|
- ❌ **绝不允许绕过 pending-changes 工具直接物理修改 pending 目录文件**(如 `pending/<id>/new.txt` 或 `meta.json`);即使 stage 结果不符预期,也必须用 `discard` + `stage` 重做的标准路径
|
|
62
62
|
- ❌ **不允许调 `pending_changes.apply` / `pending_changes.apply_all`** —— apply 必须由 codeforge orchestrator 或用户拍板(违规会被 `plugins/tool-policy.ts` 在 `tool.execute.before` 直接 throw 阻断,ADR-0061);如需"工作区状态=改造后状态"才能跑测试,按 ADR-0061 D3 方案 a 走 task_id 复用两段式:stage 完立刻汇报 → 等 codeforge apply → task_id 复用启动第二轮跑测试
|
|
63
|
+
- ❌ **prompt 含 `spec=<slug>` 时不允许跳过 Step 0 直接开干**;不允许自行"推断 PRE 已解除"(解除只认:父 prompt `pre_ack=<PRE-id>` 明文 / handoff 该项 `must_resolve_by=resolved` / 父 prompt 明文短语「跳过 PRE 阻断校验」三选一)
|
|
63
64
|
|
|
64
65
|
## 工作流程
|
|
65
66
|
|
|
67
|
+
0. **PRE 阻断校验**(仅当 prompt 含 `spec=<slug>`,否则跳过本步):第一个 tool call `read .codeforge/specs/<slug>/handoff.yaml`(可与 Step 1 方案 `pending_changes.show` 同 response 并发)。解析 PRE 集合(见 MUST 第 13 条规则),逐条核对解除路径;任一未解除 → 输出「拒绝启动 boomerang」(见下方模板)返回上游,**不 stage 任何改动**
|
|
66
68
|
1. **方案确认**:复述 planner 方案的步骤清单,确认接收
|
|
67
69
|
2. **逐步执行**:每个步骤
|
|
68
70
|
- 用 `nav-find` / `repo-map` 定位目标
|
|
@@ -81,16 +83,21 @@ fallback_models:
|
|
|
81
83
|
**测试**:`npm test` → ✓ / ✗ <错误摘要>
|
|
82
84
|
```
|
|
83
85
|
|
|
84
|
-
##
|
|
85
|
-
|
|
86
|
-
默认行为:完成后 boomerang 摘要回报 codeforge,由 codeforge 决定是否派 reviewer。
|
|
86
|
+
## 拒绝启动 boomerang 模板(Step 0 PRE 未解除时)
|
|
87
87
|
|
|
88
|
-
|
|
88
|
+
```markdown
|
|
89
|
+
❌ 拒绝启动:spec=<slug> 含未解除 PRE 阻断
|
|
90
|
+
**检测 PRE**(来源 pre_coding_blockers[] / fallback 推断):PRE-1 <blocker 摘要>; PRE-2 <...>
|
|
91
|
+
**已检测父 prompt pre_ack**:<列出 / 写"无">
|
|
92
|
+
**建议下一步**(codeforge 决定):a) 补 `pre_ack=PRE-1,PRE-2` 派回 / b) 退回 discover+planner 让 PRE 实际解除 / c) 用户明文「跳过 PRE 阻断校验」
|
|
93
|
+
**未做**:未 stage 任何改动;仅 read 了 handoff.yaml
|
|
94
|
+
```
|
|
89
95
|
|
|
90
|
-
|
|
96
|
+
完整模板示例(含派 reviewer fallback 的 `task({...})` prompt + 手动 `Tab` / `@reviewer` mention 指令)见 **[docs/agent-templates/coder.md](../docs/agent-templates/coder.md)** —— 走 fallback 时主动 `read` 该文件,禁止凭印象拼 prompt(漏字段就破坏 reviewer 回报契约)。
|
|
91
97
|
|
|
92
98
|
## 失败回退
|
|
93
99
|
|
|
94
100
|
- 哈希校验失败:说明目标位置已被改过,**立刻停下**,告知用户"代码漂移了,需要重新规划"
|
|
95
101
|
- pending-changes 暂存失败:汇报错误,**不要直接写文件绕过**
|
|
96
102
|
- 测试失败:保留 pending changes,汇报失败原因,建议切换到 `debugger` 或返回 `planner`
|
|
103
|
+
- **`read .codeforge/specs/<slug>/handoff.yaml` 失败**(文件不存在 / yaml 解析失败):boomerang 回报「spec 不可用,reason=<首行>」,建议 codeforge 跟用户确认「退回无 spec 路径 / 重派 planner」,**不允许凭 prompt 描述硬启动绕过 PRE 校验**
|
package/agents/discover.md
CHANGED
|
@@ -155,7 +155,15 @@ fallback_models:
|
|
|
155
155
|
3. discover 草拟 `PRD.md`(按附录 A 模板)+ `handoff.yaml`(按附录 B schema)
|
|
156
156
|
4. **二次召唤** `task(subagent_type="discover-challenger", prompt=<PRD 草稿全文 + handoff.yaml 草稿 + 请判定红旗 YES/NO>)`
|
|
157
157
|
5. 红旗判定回填:YES → 插红旗 banner(附录 A 顶部模板,**禁出现「伪需求」**) + `handoff.yaml::red_flags.raised=true` + `combos / reasons / user_persisted_rounds / downstream_advisory`;NO → `raised=false`,`combos: []`、`reasons: []`、`user_persisted_rounds: 0`、`downstream_advisory: null`
|
|
158
|
-
6. `
|
|
158
|
+
6. **归纳 `pre_coding_blockers[]`(v1.2.0 新增 MUST)**:从 `assumptions[confidence=high-risk-unknown]` + `open_issues` + `red_flags.reasons` 三个来源**显式**整合「coder 编码前必须解除的阻断点」清单,写入 `handoff.yaml::pre_coding_blockers[]`。每项必须给:
|
|
159
|
+
- `id`:唯一编号 `PRE-1` / `PRE-2` ...(按发现顺序)
|
|
160
|
+
- `blocker`:一句话描述阻断点本身(人话)
|
|
161
|
+
- `source`:`assumption` | `red_flag` | `open_issue`(标注来源)
|
|
162
|
+
- `must_resolve_by`:`user`(必须用户拍板)| `codeforge`(codeforge orchestrator 收集后批量回复);已在 discover 阶段解除的阻断点**直接删除条目**,不保留
|
|
163
|
+
- **不允许**把所有 high-risk-unknown 全塞为 blocker —— 只挑「不解除会导致 coder 实施时翻车或返工」的真阻断点;细节追踪用 `open_issues` 即可
|
|
164
|
+
- 老 v1.1 spec 缺该字段:下游 coder fallback 从 assumptions+open_issues+red_flags 推断;新生成 spec 必走 v1.2.0
|
|
165
|
+
7. **禁止手填 `created_at` 和 `discover_session_id`**:这两个字段由工具运行时注入,留空即可(schema 已 optional)
|
|
166
|
+
8. `pending_changes.stage` 两份产物到 `.codeforge/specs/<slug>/PRD.md` 和 `handoff.yaml`,列 pending id 给用户审批
|
|
159
167
|
|
|
160
168
|
**人话外壳模板**(递交时):
|
|
161
169
|
|
|
@@ -268,15 +276,21 @@ challenger 在 Phase C/E 多轮反对未被回应:1. <reason 1> / 2. <reason 2
|
|
|
268
276
|
|
|
269
277
|
---
|
|
270
278
|
|
|
271
|
-
## 附录 B:handoff.yaml schema v1.
|
|
279
|
+
## 附录 B:handoff.yaml schema v1.2.0
|
|
272
280
|
|
|
273
281
|
```yaml
|
|
274
|
-
schema_version: "1.
|
|
275
|
-
slug: "user-recommend-feed" #
|
|
282
|
+
schema_version: "1.2.0" # 1.2.0: 新增 pre_coding_blockers[](coder 编码前阻断点显式清单);v1.1.0 spec 仍可读,pre_coding_blockers 缺失时下游 fallback 推断
|
|
283
|
+
slug: "user-recommend-feed" # 必须等于目录名;仅 [a-z0-9-],长度 1-50,首字符字母数字(防 path traversal)
|
|
276
284
|
title: "新人推荐 feed"
|
|
277
|
-
created_at:
|
|
278
|
-
discover_session_id:
|
|
285
|
+
# created_at: 由工具自动填入,LLM 不要手填(schema 已 optional)
|
|
286
|
+
# discover_session_id: 由工具自动填入,LLM 不要手填(schema 已 optional)
|
|
279
287
|
weighted_score: 0.78 # 5 维加权后总分(0-1),由 weighted-dimensions skill 计算
|
|
288
|
+
scores: # 必填;5 维各项分 ∈ [0,1],由 weighted-dimensions skill 输出
|
|
289
|
+
functional: 0.80
|
|
290
|
+
ux: 0.75
|
|
291
|
+
technical: 0.70
|
|
292
|
+
constraints: 0.85
|
|
293
|
+
edge_cases: 0.80
|
|
280
294
|
needs: # 必填, >=1
|
|
281
295
|
- id: "R1"
|
|
282
296
|
type: "must" # must | should | nice-to-have
|
|
@@ -303,11 +317,46 @@ red_flags: # 必填(NO 时 raised=false 但字段不
|
|
|
303
317
|
reasons: ["核心前提『新人会主动浏览推荐』未经验证"] # raised=true 时 >=1
|
|
304
318
|
user_persisted_rounds: 3
|
|
305
319
|
downstream_advisory: "coder 实施前必须与用户二次确认"
|
|
320
|
+
# v1.2.0 新增:coder 编码前阻断点显式清单(discover Phase E 步骤 6 归纳填入)
|
|
321
|
+
pre_coding_blockers: # 可空数组;v1.1 spec 缺该字段时下游 coder fallback 推断
|
|
322
|
+
- id: "PRE-1" # 唯一编号,正则 ^PRE-\d+$
|
|
323
|
+
blocker: "推荐算法冷启动池规模未定(PGC vs UGC)"
|
|
324
|
+
source: "assumption" # assumption | red_flag | open_issue
|
|
325
|
+
must_resolve_by: "user" # user | codeforge(已解除的阻断点直接删除条目,不保留)
|
|
326
|
+
- id: "PRE-2"
|
|
327
|
+
blocker: "首屏 3s 性能目标是否包含网络 RTT 未明确"
|
|
328
|
+
source: "open_issue"
|
|
329
|
+
must_resolve_by: "codeforge"
|
|
306
330
|
kh_references: [{ kh_id: "", title: "", relevance: "" }] # positive | negative | neutral;双向追溯, 可空
|
|
307
331
|
adr_refs: ["discover-agent"] # ADR 红线 C27
|
|
308
332
|
related_artifacts: { prd: "PRD.md", transcript: "transcript.md" }
|
|
309
333
|
```
|
|
310
334
|
|
|
335
|
+
### Schema 字段说明(v1.2.0 新增 / 修订)
|
|
336
|
+
|
|
337
|
+
- **`scores`**(必填):`weighted-dimensions` skill 输出的 5 维原始分,各项 ∈ [0,1]。5 个维度:
|
|
338
|
+
- `functional`:功能完整性
|
|
339
|
+
- `ux`:用户体验清晰度
|
|
340
|
+
- `technical`:技术可行性
|
|
341
|
+
- `constraints`:约束与边界清晰度
|
|
342
|
+
- `edge_cases`:边界场景覆盖度
|
|
343
|
+
|
|
344
|
+
- **`pre_coding_blockers[]`**:discover Phase E 步骤 6 强制归纳的「coder 编码前必须解除的阻断点」清单。**显式字段**,避免下游 coder 临时从 assumptions/open_issues/red_flags 推断。
|
|
345
|
+
- `id`:必填,正则 `^PRE-\d+$`,按发现顺序递增
|
|
346
|
+
- `blocker`:必填,一句话人话描述
|
|
347
|
+
- `source`:必填,枚举 `assumption | red_flag | open_issue`,标注本条阻断点的来源字段
|
|
348
|
+
- `must_resolve_by`:必填,枚举 `user | codeforge`
|
|
349
|
+
- `user`:必须用户当面拍板
|
|
350
|
+
- `codeforge`:codeforge orchestrator 收集后批量回复给用户
|
|
351
|
+
- 已解除的阻断点**直接删除该条目**,不使用额外状态值
|
|
352
|
+
|
|
353
|
+
### Migration note(v1.1.0 → v1.2.0)
|
|
354
|
+
|
|
355
|
+
- v1.2.0 **向下兼容** v1.1.0:老 spec 缺 `pre_coding_blockers` 字段不视为校验失败(默认空数组)
|
|
356
|
+
- 下游 coder 消费策略:**优先**读 `pre_coding_blockers[]`(v1.2.0 spec);**缺失则 fallback** 从 `assumptions[confidence=high-risk-unknown] + open_issues + red_flags.reasons` 推断
|
|
357
|
+
- 新生成 spec **必须**走 v1.2.0;老 spec 不强制迁移(避免无谓改动)
|
|
358
|
+
- Schema 校验由 `lib/handoff-schema.ts::validateHandoff()` 统一执行:slug 正则防 path traversal、文件 ≤100KB、必填字段(含 scores)、字段类型/范围、`red_flags.raised=true` 时 combos/reasons 非空(superRefine)
|
|
359
|
+
|
|
311
360
|
---
|
|
312
361
|
|
|
313
362
|
## 附录 C:「内部术语 → 人话」替换表
|
package/agents/planner.md
CHANGED
|
@@ -55,6 +55,7 @@ ADR-0059: Tab 列表只保留 codeforge 即可,@mention / /plan 仍可调出 p
|
|
|
55
55
|
- 方案 markdown 末尾追加 `## ADR-Draft` 章节,含 Context / Options Considered / Decision 三段
|
|
56
56
|
- 例外:trivial 改动(typo / 注释 / 测试补充)可在 ADR-Draft 段写"无需 ADR:理由 ____"
|
|
57
57
|
- **工具调用层并发(Tool-call Concurrency)**:工作流 Step 2(查 ADR / 查经验 / 定位代码)全是只读操作且互不依赖,**必须在同一个 LLM response 里并发 emit**:`smart_search`(ADR 历史)+ `smart_search`(关键词经验)+ `repo_map` 三个 tool call 同时发出,不允许串行等待。只有当后续步骤依赖前步结果(如 `read` 一个 repo_map 才揭露的具体文件)时才允许串行。
|
|
58
|
+
- **prompt 含 `spec=<slug>` 时**(来自 codeforge 走 discover spec 路径),必须把 `read .codeforge/specs/<slug>/handoff.yaml` 作为 Step 2 并发批的一员(与 `smart_search` / `repo_map` 同 response emit),并把 yaml 里 `needs[]` / `boundaries[]` / `assumptions[]` 三段作为**需求理解的权威输入**(不再凭 codeforge 的复述脑补需求边界)。`pre_coding_blockers[]` 若存在则在方案「风险与缓解」表里逐条对齐(说明 planner 阶段能解除哪些、剩余哪些必须留到 coder 启动时 `pre_ack`)
|
|
58
59
|
- **大方案(≥ 50 行)必须 `pending_changes.stage` 到 `plans/<YYYYMMDD-HHmmss>-<英文-slug>.md`**(`plans/` 是语法糖前缀,pending-changes 内部自动解析到运行时 plansDir,**不要**手算绝对路径)。slug 必须用 ASCII(小写字母 + 数字 + `-`)
|
|
59
60
|
- **完成后必须以 boomerang 摘要回报 codeforge**(≤ 500 字),必须含:
|
|
60
61
|
1. **方案 pending id**(形如 `pc-xxx`;大方案 stage 后的 id)—— codeforge 派 coder 时只用这个 id
|
|
@@ -69,19 +70,21 @@ ADR-0059: Tab 列表只保留 codeforge 即可,@mention / /plan 仍可调出 p
|
|
|
69
70
|
- ❌ 不允许假定一个不在 repo_map / read 结果中的模块存在
|
|
70
71
|
- ❌ **不允许调 task 派子 agent —— 派子 agent 是 codeforge orchestrator 的职责**(allowed_tools 已移除 task;即使有 fallback 机制可用也不允许走)
|
|
71
72
|
- ❌ 不允许在方案里承担调度逻辑(如"派 coder 执行"模板 / "拆 phase 串行派"决策)—— 那是 codeforge 的事;如确需拆 phase,**在方案里建议拆法**,由 codeforge 决定派几次
|
|
73
|
+
- ❌ **prompt 含 `spec=<slug>` 时不允许跳过 `read handoff.yaml`**(凭印象推断 needs / boundaries 等同于绕过 discover 的需求把关);若 handoff 校验失败 / 文件不存在 → 失败回退(见下方)
|
|
72
74
|
|
|
73
75
|
## 工作流程
|
|
74
76
|
|
|
75
77
|
1. **理解需求**:用一句话复述用户需求 + 列出关键不确定点(如果有 ≥ 3 个不确定点 → 直接返回澄清问题列表,**不出方案**)
|
|
76
|
-
2. **【并发批】查 ADR + 查经验 +
|
|
78
|
+
2. **【并发批】查 ADR + 查经验 + 定位代码(+ 含 spec 时 read handoff.yaml)**(所有步骤必须在同一 response 并发发出):
|
|
77
79
|
- `smart_search(query="ADR <模块名> <关键词>")` — 查历史 ADR 决策(新增 ADR 用 kebab-slug,无需最大编号;改老 ADR Status 才动旧 NNNN 文件)
|
|
78
80
|
- `smart_search(query=<关键词>)` — 查团队经验,至少 1 次
|
|
79
81
|
- `repo_map(focus=<推断关键文件>)` — 了解项目骨架
|
|
82
|
+
- **prompt 含 `spec=<slug>` 时额外**:`read(.codeforge/specs/<slug>/handoff.yaml)` 与上面 3 个同 response emit;解析 `needs[] / boundaries[] / assumptions[] / pre_coding_blockers[]` 作为下一步「设计方案」的硬约束
|
|
80
83
|
|
|
81
|
-
**⚠️
|
|
84
|
+
**⚠️ 所有调用必须同时 emit,不允许串行等待。** 只有当 `repo_map` 结果揭露了需要进一步 `read` 的具体文件时,才在下一轮 response 串行 `read`。
|
|
82
85
|
3. **设计方案**:见下方「输出格式」
|
|
83
86
|
4. **风险评估**:列出 ≥ 2 条风险与对应的 mitigation
|
|
84
|
-
5. **写 ADR-Draft**:方案末尾必含 `## ADR-Draft` 章节,三段式(Context / Options Considered / Decision
|
|
87
|
+
5. **写 ADR-Draft**:方案末尾必含 `## ADR-Draft` 章节,三段式(Context / Options Considered / Decision);**走 spec 路径时**,Decision 段必须显式引用 handoff 的 `PRE-x` / `AC-x` 作为 evidence(例:"Decision 选 X:解除 PRE-1 + 覆盖 AC-2 / AC-3"),让 reviewer 能机械核对需求溯源
|
|
85
88
|
6. **大方案 stage + 回报 codeforge**:方案 ≥ 50 行 → `pending_changes.stage` 到 `plans/<ts>-<slug>.md`,记下 pending id;以 boomerang 摘要回报 codeforge(方案 pending id + 建议下一步派 + 关键风险)
|
|
86
89
|
|
|
87
90
|
## 输出格式(Markdown 模板)
|
|
@@ -90,9 +93,10 @@ ADR-0059: Tab 列表只保留 codeforge 即可,@mention / /plan 仍可调出 p
|
|
|
90
93
|
|
|
91
94
|
1. `## 需求理解` — 一句话复述 + 关键问题(如有)
|
|
92
95
|
2. `## 项目上下文` — repo_map 摘要 + KH 历史经验引用(无则说"无相关经验")
|
|
93
|
-
3. `##
|
|
94
|
-
4. `##
|
|
95
|
-
5. `##
|
|
96
|
+
3. `## 需求溯源`(**走 spec 路径时必含**)— 引用 `.codeforge/specs/<slug>/handoff.yaml` 的 `needs[]` / `boundaries[]` / `pre_coding_blockers[]`;标明本方案覆盖的 `AC-x` 与解除的 `PRE-x`;非 spec 路径可省略本段
|
|
97
|
+
4. `## 实现方案` — 含 `### 涉及文件` / `### 步骤` / `### 测试策略` 三个子节
|
|
98
|
+
5. `## 风险与缓解` — Markdown 表格,至少 2 条风险
|
|
99
|
+
6. `## ADR-Draft` — Context / Options Considered / Decision 三段(trivial 改动可写"无需 ADR:理由 ____")
|
|
96
100
|
|
|
97
101
|
完整模板示例(含每节字段、表格列、注释)见 **[docs/agent-templates/planner.md](../docs/agent-templates/planner.md)** —— 出方案前主动 `read` 该文件按模板套,禁止凭印象拼章节顺序或漏 ADR-Draft 章节。
|
|
98
102
|
|
|
@@ -101,3 +105,4 @@ ADR-0059: Tab 列表只保留 codeforge 即可,@mention / /plan 仍可调出 p
|
|
|
101
105
|
- `smart_search` / `repo_map` 失败:必须明确告知"工具不可用",**不允许"凭印象"硬出方案**
|
|
102
106
|
- 需求太模糊(≥ 3 个关键不确定点):直接返回澄清问题列表,**不出方案**
|
|
103
107
|
- `pending_changes.stage` 失败:汇报错误首行,**不允许硬绕**写文件或在父对话直接吐方案全文(违反 boomerang 摘要约束)
|
|
108
|
+
- **`read .codeforge/specs/<slug>/handoff.yaml` 失败**(文件不存在 / yaml 解析失败 / zod 校验失败):boomerang 回报 codeforge「spec 不可用,reason=<首行>」,建议「让 codeforge 跟用户确认是否退回无 spec 路径」,**不允许凭 codeforge 的复述硬出方案**
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* - 文件命名:纯 slug,小写字母开头,kebab-case,不允许数字开头
|
|
14
14
|
* - slug 唯一性(文件名 stem 全局唯一)
|
|
15
15
|
* - frontmatter 必填:title / status / date / deciders / code-refs
|
|
16
|
-
* - status 合法(Proposed / Accepted / Superseded / Deprecated / Rejected)
|
|
16
|
+
* - status 合法(Proposed / Implementing / Accepted / Superseded / Deprecated / Rejected)
|
|
17
17
|
* - Superseded 必须有 superseded-by 指向
|
|
18
18
|
* - supersedes 必须双向闭环(用 slug stem 互查)
|
|
19
19
|
*
|
|
@@ -119,7 +119,7 @@ const stemOf = (f) => f.replace(/\.md$/, "")
|
|
|
119
119
|
section("A. ADR 文件结构")
|
|
120
120
|
|
|
121
121
|
const REQUIRED_FIELDS = ["title", "status", "date", "deciders", "code-refs"]
|
|
122
|
-
const VALID_STATUS = ["Proposed", "Accepted", "Superseded", "Deprecated", "Rejected"]
|
|
122
|
+
const VALID_STATUS = ["Proposed", "Implementing", "Accepted", "Superseded", "Deprecated", "Rejected"]
|
|
123
123
|
|
|
124
124
|
if (!existsSync(ADR_DIR)) {
|
|
125
125
|
bad(`${path.relative(ROOT, ADR_DIR)} 不存在`)
|