@zhushanwen/pi-cw-tool 0.4.2 → 0.5.0

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.
@@ -1,115 +0,0 @@
1
- ---
2
- description: "cw 递归编排的 wave 层主 agent。负责 wave 内 design/replan、派 design-review 审查、派 dev 执行编码、retrospect 收尾。不亲自 execute。"
3
- name: wave-agent
4
- tools: cw_wave, subagent
5
- ---
6
-
7
- # Wave Agent(wave 层主)
8
-
9
- 你是 cw 递归编排中 wave 层的层主 agent。wave 是最小可执行单元,内部三层嵌套(v4 §6):你(层主)管 design/replan/调度/retrospect,dev subagent 扛编码与测试,review subagent 独立审查。你不亲自 execute。
10
-
11
- ## 核心原则:cw guidance 是流程唯一权威
12
-
13
- 你不记忆流程。每个 turn 先调 cw 拿 guidance,按 guidance 照做(v4 §7)。cw 每 action 返回四段:位置 / 下一步+派发指导 / 恢复指导 / 续 turn 指导。
14
-
15
- > 现状兼容(v5 G1 落地前):当前 cw 引擎实际只返回「位置 / 下一步 / subagent 调度」,恢复指导与续 turn 指导两段尚未实现。缺失段按本模板对应章节执行(失败恢复见下文 L0-L3,被唤醒见下文续 turn 指导)。
16
-
17
- ## 工具白名单与硬约束
18
-
19
- 你只有 `cw_wave`(cw-tool,限 wave 层主 action)和 `subagent`。
20
-
21
- - 无 `bash` / `read` / `write` / `edit`:写不了代码,必须派 dev。
22
- - `cw_wave` 不含 `execute` / `test`:调不了编码命令,必须派 dev(cw_dev 才有 execute/test)。
23
- - `cw_wave` 不含 `design-review` / `exec-review`:调不了审查命令,必须派 review-agent。
24
-
25
- 工具白名单硬保证三层分离(v4 §6/§7)。试图调不在白名单的 action 会被工具层拒绝。
26
-
27
- ## 记法
28
-
29
- `cw_wave <action>` 表示调 cw_wave 工具且 action 参数取该值。可调 action:design / replan / retrospect / closeout + 只读 status / handoff / list / tree / frontier。
30
-
31
- ## 生命周期(v4 §6)
32
-
33
- 你被父(slice/feature 层主)用 subagent 工具带 `worktree: true` 后台派出,在专属 worktree 工作。
34
-
35
- ### turn 1
36
-
37
- 1. `cw_wave handoff`(unitId=本 wave):拿上下文与 guidance。
38
- 2. `cw_wave design`(unitId=本 wave,input=testCases/files):设计本 wave 的测试用例与改动文件清单(cw E1 已合并旧 clarify+plan)。
39
- 3. **派 design-review subagent 审 design**(派子模板见下)。
40
- - 主观不通过 -> 你 `cw_wave replan` 改 design -> 重派 design-review。
41
- - 通过 -> 下一步。
42
- 4. **派 dev subagent 执行编码**(cw_dev 有 execute/test)。
43
- 5. turn 结束,进入空闲。
44
-
45
- ### turn 2+(被 dev 或 review 完成 steer 唤醒)
46
-
47
- 1. `cw_wave status`(unitId=本 wave)查进度。
48
- - dev 未完成(还在编码/测试/exec-review)-> 结束 turn 继续等。
49
- - dev 完成(exec-review 通过或可跟进)-> 进入收尾。
50
-
51
- ### 收尾
52
-
53
- 1. `cw_wave retrospect`(unitId=本 wave)。
54
- 2. `cw_wave closeout`(unitId=本 wave)。
55
- 3. wave 完成 -> pi reap 你的 worktree(分支保留,commitHash 已记进 cw)-> steer 唤醒父。
56
-
57
- ## 调 cw-tool 约定
58
-
59
- - `unitId` 必传,从 task prompt 或上一次 cw 响应获取。
60
- - input 作为**参数**(JSON 字符串)传给 cw-tool 的 `input` 参数,cw-tool 经 stdin 传给 cw(`--input -`)。你无 write 工具,不自己写文件。
61
- - 每次调用后读 guidance,按「下一步 + 派发指导」行动。
62
-
63
- ## 派子模板
64
-
65
- 派发用 subagent 工具(start action,后台)。子 agent 在你所在 worktree 工作,**不带 worktree**(worktree:false)。
66
-
67
- **派 design-review subagent**
68
-
69
- ```
70
- agent: review-agent
71
- task: 审查 wave <本 wave> 的 design。
72
- 1. cw_review 查 status(unitId=本 wave)读 design
73
- 2. 主观审:testCases 是否覆盖目标、files 清单是否合理、有无遗漏
74
- 3. 通过 -> cw_review design-review(unitId=本 wave)提交 judgment
75
- 4. 不通过 -> 不提交,must-fix 清单回报(steer 唤醒我)
76
- worktree: false
77
- ```
78
-
79
- **派 dev subagent**
80
-
81
- ```
82
- agent: dev-agent
83
- task: 执行 wave <本 wave> 的编码。
84
- 1. write/edit 按 design 写码 -> bash git commit 拿 hash -> cw_dev execute(unitId=本 wave,--commitHash <hash>)记进 cw(execute 是状态跃迁+commitHash 记录,不写码)
85
- 2. cw_dev test
86
- 3. 派 exec-review subagent 审执行结果
87
- 4. test 失败:代码问题->改码重 execute/test;plan 问题->steer 报回我(wave 层主)replan
88
- 5. exec-review 通过/可跟进 -> 完成 -> steer 唤醒我
89
- worktree: false
90
- ```
91
-
92
- ## 续 turn 指导(被 steer 唤醒)
93
-
94
- 子完成注入 steer 事件唤醒你开新 turn。被唤醒后:
95
-
96
- 1. `cw_wave status`(unitId=本 wave)查进度。
97
- 2. 看 guidance「下一步 / 派发指导」:dev 完成 -> retrospect + closeout;没完 -> 结束 turn 继续等。
98
- > 现状 cw 无「续 turn 指导」段——被唤醒后的动作按本模板此章节执行。
99
- 3. dev 报回 plan 问题(test 失败因 plan 缺陷)-> 你 `cw_wave replan` 改 design -> 重走 design-review -> 重派 dev。
100
- 4. 收到 blockedUpstream(L2,父拆错)-> 等父 replan 级联处理。
101
-
102
- ## 失败恢复(v4 §8 L0-L1)
103
-
104
- wave 层内自处理 L0-L1,L2 以上升级父:
105
-
106
- - **L0**(cw gate fail 或 review 审出 must-fix):turn 内处理。design 问题 -> `cw_wave design`/`replan` 改 -> 重派 design-review;编码问题交 dev 改码。unit 不销毁。
107
- - **L1**(L0 重试 ≤2 次不行,方案缺陷):`cw_wave replan`(unitId=本 wave)就地改方案 -> 重审。
108
- - **L2**(根源在上游父拆错):通过 task 返回值上报父,返回值结构 `{ escalation: "blockedUpstream", unitId, reason, l1Attempts }`(父据 escalation 字段识别 L2),等父 replan 级联标 abandoned。
109
-
110
- ## 约束
111
-
112
- - 不亲自 execute(cw_wave 无 execute/test)。
113
- - 不亲自审查(cw_wave 无审查 action)。
114
- - 每个决策以 cw guidance 为准。
115
- - verify-by-state:调 cw status 核实子状态,不信子自报。
@@ -1,226 +0,0 @@
1
- # cw 递归编排方案 v4(主 agent 发起 + steer 事件驱动 + 独立审查 + chain 合并)
2
-
3
- > 状态:定稿(替代 v0.3)
4
- > 日期:2026-08-06
5
- > 依据:pi 源码(explorer sa-4bf20c0a / sa-60edc8ef)+ cw 源码(explorer sa-ca0f0a92)
6
- > 适用:cw 引擎 v2(本项目假设 cw 现状,不依赖 E1-E6)+ recursive-split 重写
7
- > 注:本设计中编排 skill 原名 recursive-split,后更名为 pi-cw(随 @zhushanwen/pi-cw-tool 发布)。文中 recursive-split 多指编排方案代号或已删除的 workflow 脚本(recursive-split.js),skill 实体即 pi-cw。
8
-
9
- ---
10
-
11
- ## 0. 方案演进与边界
12
-
13
- 三次关键简化(每次都有源码依据):
14
-
15
- 1. **v0.3 → v4a**:workflow worker 当宿主要轮询(因为 worker 不能 steer);改 **session 宿主 + steer 事件驱动**(派发者和 agent 都是有 session 的 pi agent,子完成 pi 自动唤醒父,无需轮询)。
16
- 2. **v4a → v4b**:既然 agent 自递归,workflow 脚本多余——**主 agent 直接发起**(调 cw create + 派第一个 epic subagent),recursive-split 从 workflow 脚本变成 skill + agent 模板。
17
- 3. **v4b → v4(本版)**:审查不能自审、wave 合并是独立步骤——**design-review/exec-review 派独立 review subagent**;**wave 全完后派 chain workflow 合并分支 + 清理 worktree**。
18
-
19
- **边界**:本项目改的是 recursive-split 重写(删 `.pi/workflows/recursive-split.js`,新增 skill + agent 模板)。终态用 cw E1 合并后的 `design` action(需求澄清+方案合一,design→design-review 命名对称);cw 现状(1.3.0)仍 clarify/plan 分开,本项目落地时若 cw 还没合并,agent 连续调 `cw clarify`+`cw plan`(当一个 design 阶段)。
20
-
21
- ---
22
-
23
- ## 1. 核心机制(五条,全源码确证)
24
-
25
- 1. **派发=后台,父空闲**:`subagent` 工具 start 后台立即返回(`subagent-service.ts:468-474`),父结束 turn 进空闲态(session 保活)。
26
- 2. **完成=steer 自动唤醒父**:子完成注入 `subagent-bg-notify`+`triggerTurn:true`(`notifier.ts:195-206`),pi 给空闲父**开新 turn**(`agent-session.js:1087`)。回溯自底向上链式,事件驱动,**无轮询**。
27
- 3. **cw 是 CLI 工具,裸用无身份绑定**:`cw design-review/exec-review` 无 caller/owner/session 校验(`dispatch.js:41` 只 loadWorkUnit+guard),任何能跑 cw 的进程都能调。裸 cw 下"不自审"只靠 prompt。
28
- 4. **cw-tool 包装(堵 bash 洞 + 硬保证独立 review)**:cw 命令包成 pi 自定义工具(cw-tool),**按 role 限制可调 action**——planning/wave 层主的 cw-tool 不含 `design-review/exec-review`(只能 design/execute/retrospect/closeout/replan/status/handoff)→ **物理上调不了审查命令,必须派 review-agent**(独立 review 从软变硬);review 的 cw-tool 只含审查命令;dev 的含 execute/test。层主工具只给 `cw-tool + subagent`(无 bash/read/write/edit)→ 堵 bash 万能洞。dev/merge 需 bash(git),合理。
29
- 5. **cw guidance 是流程权威**:cw 每 action 返回的 guidance 不只"下一步命令+input schema",还含**派发指导**(这步派谁、子 task 模板)、**恢复指导**(gate fail 的 L0-L3)、**续 turn 指导**(被唤醒做什么)。agent 不记流程,每 turn 调 cw 拿 guidance 照做——流程从 agent 记忆(软)迁到 cw(权威)。详见 §7。
30
-
31
- ---
32
-
33
- ## 2. 架构(主 agent 发起,无 workflow 宿主)
34
-
35
- ```
36
- 主 agent(你对话那个)
37
- │ bash: cw create epic → subagent 工具派 epic-agent(后台)
38
- └─ 空闲,等 epic 完成 steer 唤醒 → 报告
39
- ↓
40
- epic-agent(planning 模板)自递归:
41
- cw design → 派 review-agent 审 → execute 派 feature-agent → ...
42
- ↓ (层层同构,直到 wave)
43
- wave 层主(wave 模板):design→派 design-review审→派 dev→(dev: execute写码+test+派exec-review审)→retrospect
44
- ↓ 完成 steer 唤醒 slice
45
- slice-agent:cw status 查 wave 全完 → 派 chain workflow(merge-agent 合并+清理) → retrospect → closeout
46
- ↑ steer 层层回溯到 epic → 主 agent
47
- ```
48
-
49
- **workflow 的定位**:recursive-split 整体编排**不用 workflow 脚本**(删 recursive-split.js)。但 agent 会**调用 pi builtin workflow 当工具**:`review-fix-loop`(多维审查)、`chain`(串行合并)。workflow 不当宿主,是被调用的能力。
50
-
51
- ---
52
-
53
- ## 3. 角色与模板(6 种)
54
-
55
- | 模板 | 谁用 | 工具 | 职责 | 派子? |
56
- |---|---|---|---|---|
57
- | **planning-agent** | epic/feature/slice 层主 | `cw-tool` `subagent`(无 bash/read/write/edit) | design 本层方案 → 派 review 审 → execute 派下层 → (被唤醒)派 chain 合并 → retrospect/closeout | 是 |
58
- | **wave-agent**(层主) | wave 层 | `cw-tool` `subagent` | design + replan + 派 design-review + 派 dev + retrospect。**不亲自 execute** | 是 |
59
- | **dev-agent** | wave 内 dev | `bash`(git) `read` `write` `edit` `cw-tool`(execute/test) `subagent` | execute 写码 + test + 派 exec-review | 是 |
60
- | **review-agent** | 审 design/exec 结果 | `cw-tool`(design-review/exec-review) `read`(无 bash/write/edit) | **主观审** + 调 cw 提交 judgment。不改被审物 | 否 |
61
- | **merge-agent** | chain 内 | `bash`(git) `read` | git merge + 测试 + worktree prune。冲突上报 | 否 |
62
- | 主 agent | 发起者 | 原有 + `cw-tool` | cw create epic + 派 epic-agent + 等唤醒 + 报告 | 派第一个 |
63
-
64
- > **cw-tool 按 role 限可调 action**:planning/wave 的 cw-tool 不含 design-review/exec-review(层主物理上调不了审查→**必须派 review-agent**,独立 review 硬保证);review 的只含审查;dev 的含 execute/test。这把"独立 review"从 prompt 软约束变成工具白名单硬约束。
65
-
66
- ---
67
-
68
- ## 4. 关键认知:cw gate vs 主观审查(两层职责)
69
-
70
- | 层 | 干什么 | 谁做 | pass 含义 |
71
- |---|---|---|---|
72
- | **cw gate(机器)** | 结构校验:字段填没填、格式合不合法、split DAG 有无环 | cw 引擎跑确定性规则 | **只=必填字段填全了**,≠ 方案对 |
73
- | **主观审查(AI)** | 判方案对不对:有没有遗漏、权衡合不合理、风险可控吗 | 独立 review-agent(可走 review-fix-loop 多维) | = review-agent 认可方案 |
74
-
75
- **衔接**:review-agent 先主观审;**主观通过后**才调 cw design-review 提交 judgment 过结构 gate。所以 design-review 被调起本身 = review-agent 主观放行;cw gate 是最后结构闸门。
76
-
77
- **designReviewJudgment 无 problems/verdict 字段**(cw 源码确证),review-agent 表达"审不通过"靠**行为**:不提交 design-review,而是把问题 steer 回报层主,层主改 design 后重派 review-agent。审通过才提交(填 sufficiency.meceNote 说无 gap、risks 都有 mitigation 等)。
78
-
79
- exec-review 略不同:有 `overallVerdict`(pass/needs-followup)+ `followupActions`,review-agent 可用 verdict 表达"有问题但可跟进"(不阻塞 closeout,followupActions 记技术债)。
80
-
81
- ---
82
-
83
- ## 5. planning-agent 生命周期(以 slice 为例,三层同构)
84
-
85
- ```
86
- 被父 feature-agent 用 subagent 工具派发(后台启动)
87
- turn 1:
88
- cw handoff --unitId slice-1a (拿上下文+guidance)
89
- cw design --unitId slice-1a --input ... (需求澄清+方案+拆分)
90
- ── 派 review-agent 审 slice-1a 的 design ──
91
- review-agent:
92
- 读 design(cw status 查 / .cw 产物)
93
- 主观审(可用 review-fix-loop 多维并行)
94
- ├ must-fix 问题 → steer 唤醒 slice 带问题 → [见 L0 回路]
95
- └ 审通过 → 调 cw design-review --unitId slice-1a --input {designReviewJudgment...}
96
- ├ gate fail(结构) → review-agent 修 judgment 重交
97
- └ gate pass → review-agent 完成 → steer 唤醒 slice
98
- cw execute --unitId slice-1a (cw 自动建 wave 子单元)
99
- 对每个 wave:派 wave-agent(worktree:true,后台) → turn 1 结束,空闲
100
- ... wave-agent 在各自 worktree 跑 ...
101
- turn 2(被某 wave 完成 steer 唤醒):
102
- cw status --unitId slice-1a 查:所有子 wave 都 closed?
103
- ├ 没全完 → turn 结束,继续空闲等下一个 wave 唤醒
104
- └ 全完 → 派 chain workflow:
105
- 每个 merge-agent 顺序:git merge <wave分支> + per-merge 测试 + git worktree prune
106
- ├ 冲突 → 上报(merge-agent 自身不解决,升级回 slice → L2/L3)
107
- └ 合并成功 → 清理该 wave 的 worktree 残留
108
- chain 完成 → cw retrospect + cw closeout → slice-1a 完成 → steer 唤醒 feature
109
- ```
110
-
111
- **worktree 信息流**:wave 用 `worktree:true` 派出,pi 建独立 worktree。wave `cw execute --commitHash` 把 commit 记进 cw。wave 完成 pi reap 工作目录(分支保留)。slice 从 `cw status` 查各 wave 的 commitHash,据此让 merge-agent 合并。worktree 路径/分支名:pi reap 后工作目录已删,但 git worktree 记录需 `git worktree prune` 清理(merge-agent 做)。**分支名规则待查 pi subagent-service 的 worktree 命名**(实施时确认)。
112
-
113
- ---
114
-
115
- ## 6. wave 内部三层(层主 / dev / exec-review)
116
-
117
- wave 不是单 agent 串行,而是三层嵌套(保证上下文清晰):
118
-
119
- ```
120
- wave 层主 agent [W] (worktree:true 派出,在专属 worktree)
121
- cw handoff
122
- cw design(testCases/files)
123
- 派 design-review subagent [R] 审 design (同 §5 主观/gate 区分)
124
- ├ 主观不通过 → [W] replan design → 重派 design-review
125
- └ 通过 → [W] 派 dev subagent [DEV]
126
- dev subagent [DEV]:
127
- cw execute --commitHash (写码)
128
- cw test
129
- ├ 代码问题 → [DEV] 改码 (重 execute/test)
130
- └ plan 问题 → 报回 [W] → [W] replan design → 重走 design-review → 重派 dev
131
- 派 exec-review subagent [R] 审执行结果
132
- ├ 严重 → [DEV] 改码
133
- └ 通过/可跟进 → [DEV] 完成 → steer 唤醒 [W]
134
- [W] cw retrospect + cw closeout → wave 完成 → pi reap worktree → steer 唤醒 slice
135
- ```
136
-
137
- **为什么三层**:[W] 层主保持轻上下文(只管 design/replan/调度/retrospect),不亲自 execute;[DEV] 扛完整开发上下文(execute+test 同 subagent,因 test 验证 execute 产物);[R] 独立审(dev 派,独立视角,不自审)。
138
-
139
- **cw test 失败分叉**:代码问题→dev 改码(回 execute);plan 问题→报回 wave 层主 replan design(重走 design-review 再重派 dev)。exec-review 有 `overallVerdict`(pass/needs-followup),needs-followup 可跟进不阻塞,严重才改码。
140
-
141
- ---
142
-
143
- ## 7. 可执行性:如何保证 agent 按流程
144
-
145
- LLM agent 不是状态机,无法 100% 保证按流程。靠**硬约束挡大头 + cw guidance 权威化 + 偏离可恢复**。
146
-
147
- ### 硬约束(确定性)
148
-
149
- | 约束 | 保证 | 实现 |
150
- |---|---|---|
151
- | **cw 状态机** | 不能跳步骤(没 design-review 就 execute → illegal_transition 挡) | cw action 的 from 状态约束 |
152
- | **cw-tool 工具白名单** | 层主只能调 cw + 派子(无 bash/write/edit)→ 写不了码,必须派 dev | pi tools 字段 |
153
- | **cw-tool 按 role 限 action** | 层主的 cw-tool 不含 design-review/exec-review → **调不了审查命令,必须派 review-agent**(独立 review 硬保证!) | cw-tool 包装层 action 白名单 |
154
-
155
- **cw-tool 是核心**:既堵 bash 洞(层主无 bash),又按 role 限 action(层主调不了审查)。dev/merge 需 bash(git),但其职责就是 git,合理。
156
-
157
- ### cw guidance 权威化(流程从 agent 记忆迁到 cw)
158
-
159
- cw 每 action 返回的 guidance 含四段:
160
- 1. **位置**:unit/状态/树路径
161
- 2. **下一步 + 派发指导**:不只"调 cw xxx",还告诉**这步派谁、子 task 模板**。例:wave 层主 execute 阶段 guidance="派 dev subagent(task:execute+test+派exec-review)";design-review 阶段="派 review subagent(task:审 design 并调 cw design-review 提交)"
162
- 3. **恢复指导**:gate fail 给 L0-L3(读 mustFix 重做 / cw replan / 上报父)
163
- 4. **续 turn 指导**:被 steer 唤醒="查 cw status,子全完则派 chain/retrospect,没完则等"
164
-
165
- agent 不记流程,每 turn 调 cw 拿 guidance 照做。cw guidance 是流程唯一权威,接收 guidance 的 agent 按其中的**派发指导**分情况派子(execute 派 dev/review,续 turn 派 chain 等)。
166
-
167
- ### 软约束(靠纪律)
168
-
169
- - **verify-by-state**:父调 cw status 核实子(不信自报),子乱来父查 cw 露馅
170
- - **maxTurns/预算**:防失控
171
-
172
- ### 设计哲学
173
-
174
- **不追求 100% 按流程,追求"偏离可发现 + 状态不丢 + 可恢复"**:cw 是真相铁轨(持久),agent 跑偏状态还在,从 frontier 重派接着走。最坏某 unit 卡住,不波及整棵树(cw 状态隔离 + 父核实)。
175
-
176
- ---
177
-
178
- ## 8. 失败恢复 L0-L3(替代旧版 abort)
179
-
180
- **旧问题**:gate fail → 脚本 `cw abort` 销毁 unit 重建。**新版**:agent turn 内处理,unit 不销毁。abort 只剩 L3(人决定)。
181
-
182
- | 级 | 触发 | 谁处理 | 动作 |
183
- |---|---|---|---|
184
- | **L0** | cw gate fail 或 review-agent 审出 must-fix | 当前层主 agent(turn 内) | 读 mustFix/审查问题 → 改 design(或 wave 改码)→ 重派 review-agent 重审。**unit 不动** |
185
- | **L1** | L0 重试 ≤2 次不行(方案缺陷) | 当前层主 agent | `cw replan --unitId <自己>` 就地改方案(标记废弃条目,不销毁)→ 重审 |
186
- | **L2** | 根源在上游(父拆错)或 L1 超限 | **父 agent**(被 blockedUpstream steer 唤醒) | 父 `cw replan --unitId <父>` → cw 级联标子 unit abandoned → 父对受影响未完成的子**重派**;父核对 abandoned 清单 |
187
- | **L3** | 反复失败/超预算/波及已合并代码 | 人 | 停下上报。唯一真正 abort 场景 |
188
-
189
- **replan 谁调**:L1=出问题 agent 自己;L2=父 agent。**replan 后派发**:父 replan 后 cw 级联标 abandoned,父续 turn 对受影响未完成子重调 subagent 派新 agent,已 closed 的不动(除非 L3)。
190
-
191
- ---
192
-
193
- ## 9. 与 v0.3 差异
194
-
195
- | 项 | v0.3 | v4 |
196
- |---|---|---|
197
- | 编排宿主 | workflow worker(轮询) | 主 agent session(steer 事件驱动) |
198
- | 事件泵 | 必需(60s 轮询) | **删除** |
199
- | stateless parent | 父用完即弃 | 父保持 session,steer 续 turn |
200
- | design-review/exec-review | 层主 agent 自审提交 | **派独立 review-agent 审+提交** |
201
- | wave 合并 | 壳执行 | **slice 派 chain workflow(merge-agent)** |
202
- | recursive-split.js | 重写为壳 | **删除**(改 skill + agent 模板) |
203
- | cw gate / 主观审查 | 混为一谈 | **两层职责分离**(cw=结构,review-agent=主观) |
204
- | cw 状态机/gate/worktree 隔离/L0-L3 | 保留 | 保留(不变) |
205
-
206
- ---
207
-
208
- ## 10. 待验证风险
209
-
210
- 1. **长 session compaction 漂移**:epic agent 跨多天被反复 steer 唤醒,compaction 后是否忘协议?——v0.3 引入 stateless 的原始顾虑,未论证。验证:跑 3-5 层 mini-epic 看 epic 是否守 prompt。
211
- 2. **subagent 空闲保活**:派子后空闲 session 能活多久?pi 有无 idle 超时自动 close?close 了 steer 送不到。需查 pi session 保活。
212
- 3. **worktree reap 与 merge 时序**:pi reap 后工作目录删,但分支/git worktree 记录状态?merge-agent 用 commitHash merge + prune 是否够?分支名规则待查 pi。
213
- 4. **review-agent 与层主的往返**:review 审出 must-fix → steer 层主 → 层主改 design → 重派 review。这个往返次数/maxTurns 要控(层主被反复唤醒,maxTurns 累积)。
214
- 5. **dispose 连坐**:`session_shutdown` 会 `killAllSpawnedChildren`(`subagent-service.ts:335`)。编排期间所有 agent session 不能被外部关。主 agent session 是宿主,关了整棵树丢。
215
-
216
- ---
217
-
218
- ## 11. 本项目改动清单
219
-
220
- - **删除** `.pi/workflows/recursive-split.js` + `recursive-split-utils.cjs` + 3 个测试文件(编排宿主脚本层蒸发)
221
- - **新增** skill `pi-cw`(教主 agent:cw create epic + 派 epic-agent + 等唤醒)
222
- - **新增** 6 个 agent 模板:planning-agent / wave-agent(层主) / dev-agent / review-agent / merge-agent(+ 主 agent 用现有)
223
- - **新增** cw-tool(pi 自定义工具,registerTool):包装 cw 命令,**按 role 限制可调 action**(层主不含审查命令),堵 bash 洞 + 硬保证独立 review。分配给 planning-agent / wave-agent(层主) / dev-agent(execute/test) / review-agent(审查) / 主 agent
224
- - **cw guidance 增强**:每 action 返回四段(位置/下一步+派发指导/恢复指导/续turn指导),让接收 guidance 的 agent 按派发指导分情况派子(详见 §7)
225
- - **~~cw.config.json:可能加 perLayer.model(planning 强模型/wave 便宜模型)~~** —— **已否决**:模型在派发点(subagent 工具 `model` 参数)决定,默认不指定 = 继承父 agent 模型(pi 三层解析:override → agent frontmatter → 父 agent 当前模型),递归全树同模型,无需也不应逐层配置;按层差异化只作参考,须用户显式指定才生效
226
- - **不依赖 cw 引擎 E1-E6**(本项目用 cw 现状 action 名;cw-tool 包装层可屏蔽未来 E1 合并差异)
@@ -1,163 +0,0 @@
1
- /**
2
- * detectRepoWorkspace 真实 git 探测测试 + buildCwArgs 纯函数构造测试。
3
- *
4
- * executeCwAction 的 workspace 门控行为测试已移到 workspace-gate.test.ts
5
- * (门控后 spawner 被调两次:probe `cw --version` + action,calls[0] 语义变化,
6
- * 集成测试在那里用区分 probe/action 的 gateSpawner 覆盖)。本文件只测两个纯函数。
7
- *
8
- * 测试框架:vitest(从 vitest 导入 describe/it/expect)。
9
- */
10
- import { execSync } from "node:child_process";
11
- import { mkdirSync, mkdtempSync, realpathSync, rmSync } from "node:fs";
12
- import { tmpdir } from "node:os";
13
- import * as path from "node:path";
14
-
15
- import { afterEach, describe, expect, it } from "vitest";
16
-
17
- import { buildCwArgs, detectRepoWorkspace } from "../cw-runner.ts";
18
-
19
- // ── 临时目录管理 ────────────────────────────────────────────────
20
-
21
- const tmpDirs: string[] = [];
22
-
23
- /** 建一个独立临时目录(afterEach 统一清理)。 */
24
- function makeTempDir(prefix: string): string {
25
- const dir = mkdtempSync(path.join(tmpdir(), prefix));
26
- tmpDirs.push(dir);
27
- return dir;
28
- }
29
-
30
- /** 在 dir 下初始化一个含一次空 commit 的 git repo,返回 realpath 规范化后的 repo 根。 */
31
- function createGitRepo(parentDir: string, name: string): string {
32
- const repo = path.join(parentDir, name);
33
- mkdirSync(repo);
34
- execSync("git init -q", { cwd: repo });
35
- execSync("git -c user.name=test -c user.email=test@test.local commit -q --allow-empty -m init", {
36
- cwd: repo,
37
- });
38
- // macOS 上 /tmp → /private/tmp:git rev-parse 输出 realpath,与 mkdtempSync 返回路径不一致,
39
- // 统一以 realpath 为准(--workspace 最终传的也是 git 输出的规范化路径)。
40
- return realpathSync(repo);
41
- }
42
-
43
- /** 建 bare repo + worktree workspace(xyz-agent 模式:.bare + worktree 子目录)。
44
- * 返回 realpath 规范化的 worktree 路径。bare repo worktree 内 git-common-dir basename 是 .bare(非 .git),
45
- * 是 detectRepoWorkspace 加固分支的核心场景(设计文档 §2.4 / 决策 2)。 */
46
- function createBareRepoWorkspace(parentDir: string, name: string): string {
47
- const wsRoot = path.join(parentDir, name);
48
- mkdirSync(wsRoot);
49
- // 先建普通 seed repo(含初始 commit,bare repo 不能直接 commit)
50
- const seed = path.join(parentDir, `${name}-seed`);
51
- mkdirSync(seed);
52
- execSync("git init -q", { cwd: seed });
53
- execSync("git -c user.name=test -c user.email=test@test.local commit -q --allow-empty -m init", { cwd: seed });
54
- // clone --bare 成 .bare,再 worktree add
55
- execSync(`git clone -q --bare ${seed} .bare`, { cwd: wsRoot });
56
- const worktree = path.join(wsRoot, "main");
57
- execSync('git --git-dir=.bare worktree add -q main', { cwd: wsRoot });
58
- return realpathSync(worktree);
59
- }
60
-
61
- afterEach(() => {
62
- for (const dir of tmpDirs.splice(0)) {
63
- rmSync(dir, { recursive: true, force: true });
64
- }
65
- });
66
-
67
- // ── detectRepoWorkspace(真实 git)─────────────────────────────
68
-
69
- describe("detectRepoWorkspace(真实 git)", () => {
70
- it("git repo 根目录 → 返回 repo 根(等于 --show-toplevel)", () => {
71
- const base = makeTempDir("cw-detect-");
72
- const repo = createGitRepo(base, "repo");
73
- const toplevel = execSync("git rev-parse --show-toplevel", { cwd: repo })
74
- .toString()
75
- .trim();
76
- expect(detectRepoWorkspace(repo)).toBe(toplevel);
77
- });
78
-
79
- it("repo 子目录(cwd 不在根)→ 仍返回 repo 根", () => {
80
- const base = makeTempDir("cw-detect-");
81
- const repo = createGitRepo(base, "repo");
82
- const sub = path.join(repo, "src", "deep");
83
- mkdirSync(sub, { recursive: true });
84
- const toplevel = execSync("git rev-parse --show-toplevel", { cwd: sub })
85
- .toString()
86
- .trim();
87
- expect(detectRepoWorkspace(sub)).toBe(toplevel);
88
- });
89
-
90
- it("同一 repo 的所有 worktree 返回相同值(repo 级统一,MF-1 核心证据)", () => {
91
- const base = makeTempDir("cw-detect-");
92
- const repo = createGitRepo(base, "repo");
93
- const wtDir = path.join(base, "wt1");
94
- execSync(`git worktree add -q ${wtDir}`, { cwd: repo });
95
-
96
- const mainWs = detectRepoWorkspace(repo);
97
- const wtWs = detectRepoWorkspace(wtDir);
98
- expect(mainWs).toBe(repo);
99
- expect(wtWs).toBe(repo);
100
- expect(wtWs).toBe(mainWs);
101
- });
102
-
103
- it("非 git 目录 → undefined", () => {
104
- const plain = makeTempDir("cw-detect-plain-");
105
- expect(detectRepoWorkspace(plain)).toBeUndefined();
106
- });
107
-
108
- it("不存在的路径 → undefined(不抛)", () => {
109
- const base = makeTempDir("cw-detect-");
110
- expect(detectRepoWorkspace(path.join(base, "does-not-exist"))).toBeUndefined();
111
- });
112
- });
113
-
114
- // ── detectRepoWorkspace(bare repo + worktree 模式)──────────────
115
-
116
- describe("detectRepoWorkspace(bare repo + worktree 模式)", () => {
117
- it("bare repo worktree(.bare)→ undefined(dirname(.bare)=容器根非 git 目录,不传 --workspace)", () => {
118
- const base = makeTempDir("cw-bare-");
119
- const worktree = createBareRepoWorkspace(base, "ws");
120
- expect(detectRepoWorkspace(worktree)).toBeUndefined();
121
- });
122
-
123
- it("防误用:--is-bare-repository 在 worktree 内返回 false(不可作 bare 判据)", () => {
124
- const base = makeTempDir("cw-bare-isbare-");
125
- const worktree = createBareRepoWorkspace(base, "ws");
126
- const isBare = execSync("git rev-parse --is-bare-repository", { cwd: worktree })
127
- .toString()
128
- .trim();
129
- expect(isBare).toBe("false");
130
- });
131
-
132
- it("bare repo worktree:common-dir basename 是 .bare(非 .git)", () => {
133
- const base = makeTempDir("cw-bare-commondir-");
134
- const worktree = createBareRepoWorkspace(base, "ws");
135
- const commonDir = execSync(
136
- "git -C . rev-parse --path-format=absolute --git-common-dir",
137
- { cwd: worktree },
138
- )
139
- .toString()
140
- .trim();
141
- expect(path.basename(commonDir)).toBe(".bare");
142
- });
143
- });
144
-
145
- // ── buildCwArgs 纯函数(workspace 参数)─────────────────────────
146
-
147
- describe("buildCwArgs(workspace 参数)", () => {
148
- it("workspace + commitHash → --workspace 位于 --commitHash 之后", () => {
149
- expect(buildCwArgs("execute", "u1", { commitHash: "abc" }, "/repo/root")).toEqual([
150
- "execute",
151
- "--unitId",
152
- "u1",
153
- "--commitHash",
154
- "abc",
155
- "--workspace",
156
- "/repo/root",
157
- ]);
158
- });
159
-
160
- it("workspace 为空字符串 → 不追加", () => {
161
- expect(buildCwArgs("status", "u1", {}, "")).toEqual(["status", "--unitId", "u1"]);
162
- });
163
- });