@bolloon/bolloon-agent 0.4.33 → 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.
- package/dist/agents/contacts/chain.js +27 -7
- package/dist/agents/execution-supervisor.js +493 -35
- package/dist/agents/external-events.js +35 -6
- package/dist/agents/gateway-group.js +100 -12
- package/dist/agents/goal-criteria.js +10 -3
- package/dist/agents/goal-flywheel/block-executor.js +346 -0
- package/dist/agents/goal-flywheel/continuation-decision.js +592 -0
- package/dist/agents/goal-flywheel/goal-change.js +754 -0
- package/dist/agents/goal-flywheel/index.js +26 -0
- package/dist/agents/goal-flywheel/memory-layers.js +227 -0
- package/dist/agents/goal-flywheel/run-closure.js +809 -0
- package/dist/agents/goal-flywheel/skill-candidate.js +628 -0
- package/dist/agents/goal-flywheel/types.js +329 -0
- package/dist/agents/goal-flywheel/wiring/change.js +288 -0
- package/dist/agents/goal-flywheel/wiring/closure.js +697 -0
- package/dist/agents/goal-flywheel/wiring/continuation.js +432 -0
- package/dist/agents/goal-flywheel/wiring/contract.js +270 -0
- package/dist/agents/goal-flywheel/wiring/index.js +26 -0
- package/dist/agents/goal-flywheel/wiring/monitor.js +254 -0
- package/dist/agents/goal-flywheel/wiring/seams.js +592 -0
- package/dist/agents/goal-flywheel/work-contract.js +478 -0
- package/dist/agents/goal-flywheel/work-monitor.js +488 -0
- package/dist/agents/goal-flywheel-wiring.js +1870 -0
- package/dist/agents/goal-state-reducer.js +406 -0
- package/dist/agents/goal-store.js +35 -1
- package/dist/agents/mobile-flywheel-view.js +144 -0
- package/dist/agents/mobile-task-actions-verify.js +74 -0
- package/dist/agents/mobile-task-actions.js +178 -0
- package/dist/agents/mobile-task-views.js +199 -0
- package/dist/agents/network-pulse.js +304 -18
- package/dist/agents/pi-sdk.js +75 -20
- package/dist/agents/run-store.js +18 -5
- package/dist/agents/skill-readiness.js +52 -10
- package/dist/agents/subagent-manager.js +209 -3
- package/dist/agents/task/task-runner.js +9 -3
- package/dist/agents/task-group.js +8 -51
- package/dist/agents/task-public-text.js +89 -0
- package/dist/cli/commands/index.js +1 -0
- package/dist/cli/commands/tasks.js +350 -2
- package/dist/cli/identity-command.js +177 -0
- package/dist/cli/setup-wizard.js +71 -0
- package/dist/cli/update-commands.js +150 -24
- package/dist/cli-entry.js +12 -2
- package/dist/electron-build/agents/contacts/chain.js +26 -6
- package/dist/electron-build/agents/contacts/chain.js.map +1 -1
- package/dist/electron-build/agents/execution-supervisor.js +492 -34
- package/dist/electron-build/agents/execution-supervisor.js.map +1 -1
- package/dist/electron-build/agents/external-events.js +34 -5
- package/dist/electron-build/agents/external-events.js.map +1 -1
- package/dist/electron-build/agents/goal-criteria.js +10 -3
- package/dist/electron-build/agents/goal-criteria.js.map +1 -1
- package/dist/electron-build/agents/goal-flywheel/continuation-decision.js +598 -0
- package/dist/electron-build/agents/goal-flywheel/continuation-decision.js.map +1 -0
- package/dist/electron-build/agents/goal-flywheel/goal-change.js +773 -0
- package/dist/electron-build/agents/goal-flywheel/goal-change.js.map +1 -0
- package/dist/electron-build/agents/goal-flywheel/memory-layers.js +269 -0
- package/dist/electron-build/agents/goal-flywheel/memory-layers.js.map +1 -0
- package/dist/electron-build/agents/goal-flywheel/run-closure.js +818 -0
- package/dist/electron-build/agents/goal-flywheel/run-closure.js.map +1 -0
- package/dist/electron-build/agents/goal-flywheel/skill-candidate.js +642 -0
- package/dist/electron-build/agents/goal-flywheel/skill-candidate.js.map +1 -0
- package/dist/electron-build/agents/goal-flywheel/types.js +333 -0
- package/dist/electron-build/agents/goal-flywheel/types.js.map +1 -0
- package/dist/electron-build/agents/goal-flywheel/wiring/change.js +294 -0
- package/dist/electron-build/agents/goal-flywheel/wiring/change.js.map +1 -0
- package/dist/electron-build/agents/goal-flywheel/wiring/closure.js +742 -0
- package/dist/electron-build/agents/goal-flywheel/wiring/closure.js.map +1 -0
- package/dist/electron-build/agents/goal-flywheel/wiring/continuation.js +444 -0
- package/dist/electron-build/agents/goal-flywheel/wiring/continuation.js.map +1 -0
- package/dist/electron-build/agents/goal-flywheel/wiring/contract.js +279 -0
- package/dist/electron-build/agents/goal-flywheel/wiring/contract.js.map +1 -0
- package/dist/electron-build/agents/goal-flywheel/wiring/index.js +111 -0
- package/dist/electron-build/agents/goal-flywheel/wiring/index.js.map +1 -0
- package/dist/electron-build/agents/goal-flywheel/wiring/monitor.js +264 -0
- package/dist/electron-build/agents/goal-flywheel/wiring/monitor.js.map +1 -0
- package/dist/electron-build/agents/goal-flywheel/wiring/seams.js +612 -0
- package/dist/electron-build/agents/goal-flywheel/wiring/seams.js.map +1 -0
- package/dist/electron-build/agents/goal-flywheel/work-contract.js +488 -0
- package/dist/electron-build/agents/goal-flywheel/work-contract.js.map +1 -0
- package/dist/electron-build/agents/goal-flywheel/work-monitor.js +501 -0
- package/dist/electron-build/agents/goal-flywheel/work-monitor.js.map +1 -0
- package/dist/electron-build/agents/goal-flywheel-wiring.js +1962 -0
- package/dist/electron-build/agents/goal-flywheel-wiring.js.map +1 -0
- package/dist/electron-build/agents/goal-state-reducer.js +414 -0
- package/dist/electron-build/agents/goal-state-reducer.js.map +1 -0
- package/dist/electron-build/agents/goal-store.js +35 -1
- package/dist/electron-build/agents/goal-store.js.map +1 -1
- package/dist/electron-build/agents/network-pulse.js +307 -19
- package/dist/electron-build/agents/network-pulse.js.map +1 -1
- package/dist/electron-build/agents/pi-sdk.js +74 -19
- package/dist/electron-build/agents/pi-sdk.js.map +1 -1
- package/dist/electron-build/agents/run-store.js +20 -5
- package/dist/electron-build/agents/run-store.js.map +1 -1
- package/dist/electron-build/agents/skill-readiness.js +52 -9
- package/dist/electron-build/agents/skill-readiness.js.map +1 -1
- package/dist/electron-build/agents/task/task-runner.js +8 -2
- package/dist/electron-build/agents/task/task-runner.js.map +1 -1
- package/dist/electron-build/orbitdb/cid-database.js +83 -17
- package/dist/electron-build/orbitdb/cid-database.js.map +1 -1
- package/dist/electron-build/orbitdb/ipfs-node.js +31 -2
- package/dist/electron-build/orbitdb/ipfs-node.js.map +1 -1
- package/dist/electron-build/utils/dual-source.js +471 -0
- package/dist/electron-build/utils/dual-source.js.map +1 -0
- package/dist/electron-build/utils/update-manager.js +331 -57
- package/dist/electron-build/utils/update-manager.js.map +1 -1
- package/dist/electron-build/utils/update-state.js +16 -1
- package/dist/electron-build/utils/update-state.js.map +1 -1
- package/dist/electron-build/utils/version-info.js +82 -2
- package/dist/electron-build/utils/version-info.js.map +1 -1
- package/dist/index.js +103 -12
- package/dist/ios/chain-explorer.js +617 -0
- package/dist/ios/explorer.html +163 -0
- package/dist/ios/index.html +96 -0
- package/dist/ios/mobile-agent.js +2 -2
- package/dist/ios/mobile-contacts.js +329 -0
- package/dist/ios/mobile-core.js +1379 -226
- package/dist/ios/mobile-privacy.js +185 -0
- package/dist/ios/mobile.css +19 -0
- package/dist/ios/mobile.html +96 -0
- package/dist/ios/mobile.js +706 -7
- package/dist/ios/routes-chain-index.js +108 -0
- package/dist/ios/routes-contacts.js +420 -0
- package/dist/ios/routes-onchain-trade.js +99 -0
- package/dist/ios/routes-x402-info.js +1 -0
- package/dist/ios/server.js +762 -0
- package/dist/ios/task-frame-server.js +211 -0
- package/dist/orbitdb/cid-database.js +81 -16
- package/dist/orbitdb/ipfs-node.js +31 -2
- package/dist/utils/dual-source.js +426 -0
- package/dist/utils/update-cli.js +16 -21
- package/dist/utils/update-health.js +35 -5
- package/dist/utils/update-manager.js +329 -57
- package/dist/utils/update-state.js +16 -1
- package/dist/utils/version-info.js +75 -1
- package/dist/web/mobile-contacts.js +44 -11
- package/dist/web/mobile-core.js +1197 -513
- package/dist/web/mobile-tasks.js +339 -0
- package/dist/web/mobile.css +19 -0
- package/dist/web/mobile.html +64 -0
- package/dist/web/mobile.js +531 -1
- package/dist/web/routes-mobile-tasks.js +353 -0
- package/dist/web/server.js +163 -4
- package/package.json +3 -1
|
@@ -0,0 +1,592 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* goal-flywheel/wiring/seams.ts — 「唯一责任链」的**接线接缝注册表** (M0 冻结, 2026-09-25)
|
|
3
|
+
*
|
|
4
|
+
* ## 为什么要有这一层
|
|
5
|
+
*
|
|
6
|
+
* P0–P4 的七个模块 (continuation-decision / run-closure / memory-layers / skill-candidate /
|
|
7
|
+
* work-contract / work-monitor / goal-change) 已经实现并接进了真实执行路径
|
|
8
|
+
* (`src/agents/goal-flywheel-wiring.ts`)。但"接进去了"和"只有那么一条链"是两件事:
|
|
9
|
+
* 只要还有第二个地方能结束 Run、能改 Goal 状态、能决定是否继续, 就会出现**两套事实**。
|
|
10
|
+
*
|
|
11
|
+
* 本文件把那条链**切成五个接缝** (seam), 每个接缝只回答一个问题, 并**声明自己归哪个阶段独占**:
|
|
12
|
+
*
|
|
13
|
+
* ```
|
|
14
|
+
* Supervisor → Goal continuation → Runner/子 Agent → Run → closeRun → Memory + Skill 候选 → 下一次 continuation
|
|
15
|
+
* ↑ continuation ↑ contract ↑ closure ↑ closure
|
|
16
|
+
* ↑ monitor (阻塞)
|
|
17
|
+
* ↑ change (新要求注入 + 用户可见态)
|
|
18
|
+
* ```
|
|
19
|
+
*
|
|
20
|
+
* ## 这个文件归 M0 独占 (接线阶段); M1–M4 只读不改
|
|
21
|
+
*
|
|
22
|
+
* M0 之后 M1–M4 **全部并行**。并发安全靠一条硬规则:
|
|
23
|
+
* **每个阶段只准改 `owns` 与 `wiringPoints` 列出的那些文件, 且两份清单不许有交集。**
|
|
24
|
+
* 这条规则不是写在文档里让人自觉遵守 —— `seamRosterViolations()` 就是它的可执行判据,
|
|
25
|
+
* 由 `src/test/goal-flywheel-wiring-freeze.test.ts` 真跑; 一旦两个阶段声明同一个文件, 门立刻判红。
|
|
26
|
+
*
|
|
27
|
+
* ## 每个接缝长什么样
|
|
28
|
+
*
|
|
29
|
+
* 接缝实现放在同目录的**一个文件**里 (`module` 字段), 只依赖三样东西:
|
|
30
|
+
* ① 本目录 `seams.ts` 里的**接口** (M0 冻结);
|
|
31
|
+
* ② `../types.js` 的冻结类型;
|
|
32
|
+
* ③ **自己那个阶段**的实现模块 (例如 closure 接缝 → `../run-closure.js`)。
|
|
33
|
+
* 其余一切 (Goal/Run 的事实读取、落盘、决策函数的实例) 全部**按参数注入** ——
|
|
34
|
+
* 因此没有任何两个阶段会 import 到同一个实现文件, 也就不会有 merge 冲突。
|
|
35
|
+
*/
|
|
36
|
+
// ============================================================================
|
|
37
|
+
// §1. 阶段与接缝的名册 (并行划分的**唯一事实来源**)
|
|
38
|
+
// ============================================================================
|
|
39
|
+
/** M0 = 接线冻结 (本文件); M1–M4 = 之后的四个并行阶段 */
|
|
40
|
+
export const WIRING_STAGES = ['M1', 'M2', 'M3', 'M4'];
|
|
41
|
+
export const SEAM_IDS = ['continuation', 'closure', 'contract', 'monitor', 'change'];
|
|
42
|
+
/**
|
|
43
|
+
* 名册。`owns` / `wiringPoints` 的**不相交**由 `seamRosterViolations()` 强制。
|
|
44
|
+
*
|
|
45
|
+
* 划分依据 (与设计稿 §13 的所有权表同源):
|
|
46
|
+
* · M1 = P0 (节奏由进展决定) 的接线深化;
|
|
47
|
+
* · M2 = P1 + P1b (强制收尾 + Memory 分层 + Skill 候选通道) 的接线深化 ——
|
|
48
|
+
* **`closeRun` 只属于这一条接缝**, 因此 M2 是"所有终止路径"的唯一收口;
|
|
49
|
+
* · M3 = P2 + P3 (子 Agent 合同 + 阻塞监控) —— 两个接缝同属一个阶段, 因为它们改的是同一批事实
|
|
50
|
+
* (工作合同 / 心跳 / 回报 / 阻塞), 并行拆到两个阶段只会互相踩;
|
|
51
|
+
* · M4 = P4 (新要求注入 + 用户可见态)。
|
|
52
|
+
*/
|
|
53
|
+
export const SEAM_ROSTER = [
|
|
54
|
+
{
|
|
55
|
+
id: 'continuation',
|
|
56
|
+
stage: 'M1',
|
|
57
|
+
question: '这个 Goal 现在该不该开下一轮, 为什么?',
|
|
58
|
+
module: 'continuation.ts',
|
|
59
|
+
owns: [
|
|
60
|
+
'src/agents/goal-flywheel/wiring/continuation.ts',
|
|
61
|
+
'src/test/goal-flywheel-wiring-continuation.test.ts',
|
|
62
|
+
],
|
|
63
|
+
wiringPoints: [
|
|
64
|
+
'src/agents/goal-flywheel/continuation-decision.ts',
|
|
65
|
+
],
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
id: 'closure',
|
|
69
|
+
stage: 'M2',
|
|
70
|
+
question: '这一条 Run 收尾了吗, 收尾产物落在哪里?',
|
|
71
|
+
module: 'closure.ts',
|
|
72
|
+
owns: [
|
|
73
|
+
'src/agents/goal-flywheel/wiring/closure.ts',
|
|
74
|
+
'src/test/goal-flywheel-wiring-closure.test.ts',
|
|
75
|
+
],
|
|
76
|
+
wiringPoints: [
|
|
77
|
+
'src/agents/goal-flywheel/run-closure.ts',
|
|
78
|
+
'src/agents/goal-flywheel/memory-layers.ts',
|
|
79
|
+
'src/agents/goal-flywheel/skill-candidate.ts',
|
|
80
|
+
],
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
id: 'contract',
|
|
84
|
+
stage: 'M3',
|
|
85
|
+
question: '这一步该派给谁, 回报算不算完成?',
|
|
86
|
+
module: 'contract.ts',
|
|
87
|
+
owns: [
|
|
88
|
+
'src/agents/goal-flywheel/wiring/contract.ts',
|
|
89
|
+
'src/test/goal-flywheel-wiring-contract.test.ts',
|
|
90
|
+
],
|
|
91
|
+
wiringPoints: [
|
|
92
|
+
'src/agents/goal-flywheel/work-contract.ts',
|
|
93
|
+
'src/agents/subagent-manager.ts',
|
|
94
|
+
],
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
id: 'monitor',
|
|
98
|
+
stage: 'M3',
|
|
99
|
+
question: '有谁卡住了, 该谁动手?',
|
|
100
|
+
module: 'monitor.ts',
|
|
101
|
+
owns: [
|
|
102
|
+
'src/agents/goal-flywheel/wiring/monitor.ts',
|
|
103
|
+
'src/test/goal-flywheel-wiring-monitor.test.ts',
|
|
104
|
+
],
|
|
105
|
+
wiringPoints: [
|
|
106
|
+
'src/agents/goal-flywheel/work-monitor.ts',
|
|
107
|
+
],
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
id: 'change',
|
|
111
|
+
stage: 'M4',
|
|
112
|
+
question: '人中途改了什么要求, 用户该看到哪一类状态?',
|
|
113
|
+
module: 'change.ts',
|
|
114
|
+
owns: [
|
|
115
|
+
'src/agents/goal-flywheel/wiring/change.ts',
|
|
116
|
+
'src/test/goal-flywheel-wiring-change.test.ts',
|
|
117
|
+
],
|
|
118
|
+
wiringPoints: [
|
|
119
|
+
'src/agents/goal-flywheel/goal-change.ts',
|
|
120
|
+
'src/web/server.ts',
|
|
121
|
+
],
|
|
122
|
+
},
|
|
123
|
+
];
|
|
124
|
+
export const SEAM_MODULES = SEAM_ROSTER.map((s) => s.module);
|
|
125
|
+
export function seamOf(id) {
|
|
126
|
+
const found = SEAM_ROSTER.find((s) => s.id === id);
|
|
127
|
+
if (!found)
|
|
128
|
+
throw new Error(`未知接缝: ${String(id)}`);
|
|
129
|
+
return found;
|
|
130
|
+
}
|
|
131
|
+
export function seamModuleOf(id) {
|
|
132
|
+
return seamOf(id).module;
|
|
133
|
+
}
|
|
134
|
+
export function stageOf(id) {
|
|
135
|
+
return seamOf(id).stage;
|
|
136
|
+
}
|
|
137
|
+
/** 某阶段独占的全部文件 (owns + wiringPoints) */
|
|
138
|
+
export function filesOfStage(stage) {
|
|
139
|
+
const out = [];
|
|
140
|
+
for (const s of SEAM_ROSTER.filter((x) => x.stage === stage)) {
|
|
141
|
+
out.push(...s.owns, ...s.wiringPoints);
|
|
142
|
+
}
|
|
143
|
+
return out;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* 名册的自检: **两个阶段不许声明同一个文件**。
|
|
147
|
+
*
|
|
148
|
+
* 阴性对照: 把 `monitor.ts` 的 `wiringPoints` 里加上 `src/agents/goal-flywheel/work-contract.ts`
|
|
149
|
+
* (M3 的 contract 接缝也声明了它) → 立刻返回一条 `stage_overlap`。
|
|
150
|
+
* 返回空数组 = 并行划分成立; 非空 = **不许开并行**, 必须改成串行顺序。
|
|
151
|
+
*/
|
|
152
|
+
export function seamRosterViolations(roster = SEAM_ROSTER) {
|
|
153
|
+
const out = [];
|
|
154
|
+
const byFile = new Map();
|
|
155
|
+
const seenSeam = new Set();
|
|
156
|
+
for (const seam of roster) {
|
|
157
|
+
if (seenSeam.has(seam.id)) {
|
|
158
|
+
out.push({ kind: 'unowned_seam', file: seam.id, stages: [seam.stage], reason: `接缝 ${seam.id} 被声明了两次` });
|
|
159
|
+
}
|
|
160
|
+
seenSeam.add(seam.id);
|
|
161
|
+
const claims = [...seam.owns, ...seam.wiringPoints];
|
|
162
|
+
if (claims.length === 0) {
|
|
163
|
+
out.push({ kind: 'empty_claim', file: seam.id, stages: [seam.stage], reason: `接缝 ${seam.id} 没有声明任何文件 (等于没划分)` });
|
|
164
|
+
}
|
|
165
|
+
if (!seam.module || !seam.owns.some((f) => f.endsWith(`/${seam.module}`) || f.endsWith(seam.module))) {
|
|
166
|
+
out.push({ kind: 'missing_owner', file: seam.module || seam.id, stages: [seam.stage], reason: `接缝 ${seam.id} 的实现文件 ${seam.module} 不在自己的 owns 清单里` });
|
|
167
|
+
}
|
|
168
|
+
for (const f of claims) {
|
|
169
|
+
const set = byFile.get(f) ?? new Set();
|
|
170
|
+
set.add(seam.stage);
|
|
171
|
+
byFile.set(f, set);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
for (const [file, stages] of byFile) {
|
|
175
|
+
if (stages.size > 1) {
|
|
176
|
+
out.push({
|
|
177
|
+
kind: 'stage_overlap',
|
|
178
|
+
file,
|
|
179
|
+
stages: [...stages].sort(),
|
|
180
|
+
reason: `${file} 被 ${[...stages].sort().join(' 与 ')} 同时声明 → 并行会撞车`,
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
return out;
|
|
185
|
+
}
|
|
186
|
+
/** 并行划分是否成立 (门用的布尔出口; 非空即判红)。可传入候选名册做**变异验证**。 */
|
|
187
|
+
export function canRunStagesInParallel(roster = SEAM_ROSTER) {
|
|
188
|
+
const violations = seamRosterViolations(roster);
|
|
189
|
+
return { ok: violations.length === 0, violations };
|
|
190
|
+
}
|
|
191
|
+
// ============================================================================
|
|
192
|
+
// §3. 六个接缝的共同形态 (接口在 M0 冻结; 实现按阶段各自落)
|
|
193
|
+
// ============================================================================
|
|
194
|
+
/** 调用方身份: 只有 Supervisor 能决定"是否继续", 因此必须**显式声明**是谁在问 */
|
|
195
|
+
export const WIRING_CALLERS = ['supervisor', 'runner', 'child_agent', 'human', 'system'];
|
|
196
|
+
export const FROZEN_RULES = [
|
|
197
|
+
'only_supervisor_decides_continuation',
|
|
198
|
+
'only_goal_reducer_changes_goal_state',
|
|
199
|
+
'only_close_run_closes_run',
|
|
200
|
+
'all_terminal_paths_pass_close_run',
|
|
201
|
+
'child_cannot_mutate_goal',
|
|
202
|
+
'skill_cannot_bypass_promotion_channel',
|
|
203
|
+
];
|
|
204
|
+
export const FROZEN_RULE_TEXT = {
|
|
205
|
+
only_supervisor_decides_continuation: '只有 Supervisor 能决定是否继续',
|
|
206
|
+
only_goal_reducer_changes_goal_state: '只有 Goal reducer 能改 Goal 状态',
|
|
207
|
+
only_close_run_closes_run: '只有 closeRun 能关闭 Run',
|
|
208
|
+
all_terminal_paths_pass_close_run: '所有终止路径必须经过 closeRun',
|
|
209
|
+
child_cannot_mutate_goal: '子 Agent 不能直接改 Goal',
|
|
210
|
+
skill_cannot_bypass_promotion_channel: 'Skill 不得绕过验证+快照+可回退通道 (M6 允许自动晋升, 但不许绕过通道)',
|
|
211
|
+
};
|
|
212
|
+
export function refuse(rule, reason) {
|
|
213
|
+
return { ok: false, reason, rule };
|
|
214
|
+
}
|
|
215
|
+
export function isRefusal(x) {
|
|
216
|
+
return !!x && typeof x === 'object' && x.ok === false && typeof x.reason === 'string';
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* 去掉块注释, 但**保留行号** (用等量换行填空)。
|
|
220
|
+
*
|
|
221
|
+
* 为什么必须做: 门自己的文档里就有"真实绕过长什么样"的代码样例 (`patch.status = ...` +
|
|
222
|
+
* `await updateGoal(...)`)。不剥块注释的话, **门的文档会被门自己判红**, 于是只能把门本身
|
|
223
|
+
* 加进白名单 —— 白名单一多, 真信号就淹了。剥掉注释 = 只看代码, 白名单才能保持最小。
|
|
224
|
+
*/
|
|
225
|
+
export function stripBlockComments(text) {
|
|
226
|
+
return text.replace(/\/\*[\s\S]*?\*\//g, (m) => m.replace(/[^\n]/g, ' '));
|
|
227
|
+
}
|
|
228
|
+
/** 逐行扫描: 返回 (行号, 文本)。只扫**代码** (块注释 + 行内注释都去掉) */
|
|
229
|
+
function lines(text) {
|
|
230
|
+
return stripBlockComments(text).split(/\r?\n/).map((s, i) => ({ n: i + 1, s }));
|
|
231
|
+
}
|
|
232
|
+
/** 去掉行内注释与字符串里的假阳性 (只做保守处理: 不改变行号) */
|
|
233
|
+
function stripLineComment(s) {
|
|
234
|
+
const i = s.indexOf('//');
|
|
235
|
+
return i >= 0 ? s.slice(0, i) : s;
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* 规则 ①: 只有 Supervisor 能决定是否继续。
|
|
239
|
+
* 判据: 调用「下一步该不该跑」那条判定链 (`decideGoalStep` / `decideContinuation`) 的文件
|
|
240
|
+
* 必须在允许清单里 (Supervisor 本体 + continuation 接缝 + 判定模块自身与它的测试)。
|
|
241
|
+
*/
|
|
242
|
+
export function scanOnlySupervisorDecides(files, allowed = DEFAULT_ALLOW.onlySupervisorDecides) {
|
|
243
|
+
const out = [];
|
|
244
|
+
for (const f of files) {
|
|
245
|
+
if (allowed.includes(f.path))
|
|
246
|
+
continue;
|
|
247
|
+
for (const { n, s } of lines(f.text)) {
|
|
248
|
+
const code = stripLineComment(s);
|
|
249
|
+
if (/\bdecideGoalStep\s*\(/.test(code) || /\bdecideContinuation\s*\(/.test(code)) {
|
|
250
|
+
out.push({
|
|
251
|
+
rule: 'only_supervisor_decides_continuation',
|
|
252
|
+
path: f.path,
|
|
253
|
+
line: n,
|
|
254
|
+
snippet: s.trim().slice(0, 140),
|
|
255
|
+
reason: `${f.path} 调用了继续判定 —— 只有 Supervisor 能决定是否继续 (或经 continuation 接缝)`,
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
return out;
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* 规则 ②: 只有 Goal reducer 能改 Goal 状态。
|
|
264
|
+
*
|
|
265
|
+
* 判据刻意**按文件**判而不是按行判: 真实绕过长这样 ——
|
|
266
|
+
* ```ts
|
|
267
|
+
* const patch = { goalChanges: changes };
|
|
268
|
+
* patch.status = 'abandoned'; // ← 这一行没有 updateGoal
|
|
269
|
+
* await updateGoal(goalId, patch); // ← 这一行没有 status
|
|
270
|
+
* ```
|
|
271
|
+
* 按行判会同时漏掉这两行。所以判据 = **同一个文件里同时出现"写 Goal 的调用"与"状态赋值信号"**,
|
|
272
|
+
* 行号只用于报告 (指向那条 `updateGoal`)。允许清单只有两处: Goal 存储本体 (定义 + 完成门 + lease)
|
|
273
|
+
* 与 Goal reducer (唯一漏斗)。
|
|
274
|
+
*/
|
|
275
|
+
export function scanOnlyGoalReducerWritesState(files, allowed = DEFAULT_ALLOW.onlyGoalReducerWritesState) {
|
|
276
|
+
const out = [];
|
|
277
|
+
// 只盯**能写 status 的原语** `updateGoal`。刻意不含 setUnresolved / setCriteria / markCriterion ——
|
|
278
|
+
// 那些写的是未解决项与判据 (不是状态), 把它们也算进来只会在无关文件上刷假阳性 (例如
|
|
279
|
+
// task-runner 写判据 + 恰好有个 `status: '已完成'` 的业务字面量), 而门一旦有假阳性就会被
|
|
280
|
+
// 加白名单"解决", 于是真信号也被顺手埋掉。
|
|
281
|
+
const CALL = /\bupdateGoal\s*\(/;
|
|
282
|
+
// `(?!=)` 排除 `x.status === 'done'` 这种**比较** (它不是赋值); `status:` 字面量才是指针。
|
|
283
|
+
//
|
|
284
|
+
// 这道判据**故意偏严**: `.status =` 不区分"这是 Goal 还是 Run 的状态"。代价是某个只写 Run 状态
|
|
285
|
+
// 的文件一旦也开始写 Goal (哪怕是写证据), 就会被要求改道 —— 而"改道到 reducer"正是我们要的结果。
|
|
286
|
+
// 宽松的版本 (只认 goal 前缀的变量名) 会放过 `const p = {...}; p.status = 'failed'` 这种真绕过,
|
|
287
|
+
// 那个代价比"多走一次 reducer"大得多。这条取舍写在这里, 是为了下一个人不必再猜。
|
|
288
|
+
const STATUS_SIGNAL = /\.status\s*=(?!=)|\bstatus\s*:\s*['"]/;
|
|
289
|
+
for (const f of files) {
|
|
290
|
+
if (allowed.includes(f.path))
|
|
291
|
+
continue;
|
|
292
|
+
const ls = lines(f.text);
|
|
293
|
+
const callLines = ls.filter(({ s }) => CALL.test(stripLineComment(s)));
|
|
294
|
+
if (callLines.length === 0)
|
|
295
|
+
continue;
|
|
296
|
+
const statusLines = ls.filter(({ s }) => STATUS_SIGNAL.test(stripLineComment(s)));
|
|
297
|
+
if (statusLines.length === 0)
|
|
298
|
+
continue;
|
|
299
|
+
out.push({
|
|
300
|
+
rule: 'only_goal_reducer_changes_goal_state',
|
|
301
|
+
path: f.path,
|
|
302
|
+
line: statusLines[0].n,
|
|
303
|
+
snippet: statusLines[0].s.trim().slice(0, 140),
|
|
304
|
+
reason: `${f.path} 同时写了 Goal (${callLines.length} 处调用, 首处 :${callLines[0].n}) 与 Goal 状态 `
|
|
305
|
+
+ `(:${statusLines.map((x) => x.n).join(',')}) —— 状态变更必须经 Goal reducer (唯一漏斗)`,
|
|
306
|
+
});
|
|
307
|
+
}
|
|
308
|
+
return out;
|
|
309
|
+
}
|
|
310
|
+
/**
|
|
311
|
+
* 规则 ③: 只有 closeRun 能关闭 Run。
|
|
312
|
+
* 判据: `closeRun(` 只许出现在收尾模块本体 (定义) 与接线适配层 (它注入真依赖)。
|
|
313
|
+
*/
|
|
314
|
+
export function scanOnlyCloseRunCloses(files, allowed = DEFAULT_ALLOW.onlyCloseRunCloses) {
|
|
315
|
+
const out = [];
|
|
316
|
+
for (const f of files) {
|
|
317
|
+
if (allowed.includes(f.path))
|
|
318
|
+
continue;
|
|
319
|
+
for (const { n, s } of lines(f.text)) {
|
|
320
|
+
const code = stripLineComment(s);
|
|
321
|
+
if (/(?<![A-Za-z0-9_])closeRun\s*\(/.test(code) || /\bimport\s*\{[^}]*\bcloseRun\b/.test(code)) {
|
|
322
|
+
out.push({
|
|
323
|
+
rule: 'only_close_run_closes_run',
|
|
324
|
+
path: f.path,
|
|
325
|
+
line: n,
|
|
326
|
+
snippet: s.trim().slice(0, 140),
|
|
327
|
+
reason: `${f.path} 触碰了 closeRun —— 关闭 Run 只有一条路 (closeRun, 经接线层的 closeRunOnce)`,
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
return out;
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* 收尾漏斗的**唯一入口名字**。
|
|
336
|
+
*
|
|
337
|
+
* 所有终止路径必须在这里出现"经过收尾漏斗"的调用。为了不让"改个名字"变成第三条路,
|
|
338
|
+
* 允许的名字是一个**封闭集合** (本体 + 经审计的薄壳别名), 且别名必须真的调本体
|
|
339
|
+
* (由 `scanFunnelAliases` 每次跑测试时检查 —— 别名不许长成第二个漏斗)。
|
|
340
|
+
*/
|
|
341
|
+
export const FUNNEL_ENTRY = 'closeRunOnce';
|
|
342
|
+
export const FUNNEL_ALIASES = ['closeTaskRun'];
|
|
343
|
+
/** 匹配"经过收尾漏斗"的调用 (带词界, 避免 `__removed_closeRunOnce(` 这种假命中) */
|
|
344
|
+
export const FUNNEL_CALL_RE = /(?<![A-Za-z0-9_])(?:closeRunOnce|closeGoalRun|closeTaskRun)\s*\(/;
|
|
345
|
+
export const TERMINAL_PATHS = [
|
|
346
|
+
{
|
|
347
|
+
path: '成功 (Run 正常完成)',
|
|
348
|
+
file: 'src/agents/execution-supervisor.ts',
|
|
349
|
+
marker: /await\s+runner\s*\(/,
|
|
350
|
+
via: FUNNEL_CALL_RE,
|
|
351
|
+
},
|
|
352
|
+
{
|
|
353
|
+
path: '失败 / 中断恢复 (Runner 内 finishRun)',
|
|
354
|
+
file: 'src/agents/pi-sdk.ts',
|
|
355
|
+
marker: /await\s+finishRun\s*\(/,
|
|
356
|
+
via: FUNNEL_CALL_RE,
|
|
357
|
+
},
|
|
358
|
+
{
|
|
359
|
+
path: '超时 / 预算耗尽 (收尾即放弃)',
|
|
360
|
+
file: 'src/agents/task/task-runner.ts',
|
|
361
|
+
marker: /await\s+finishRun\s*\(/,
|
|
362
|
+
via: FUNNEL_CALL_RE,
|
|
363
|
+
},
|
|
364
|
+
{
|
|
365
|
+
path: '崩溃恢复 (孤儿对账 → interrupted) / 失速 (stalled)',
|
|
366
|
+
file: 'src/agents/run-store.ts',
|
|
367
|
+
marker: /await\s+finishRun\s*\(/,
|
|
368
|
+
via: /(?<![A-Za-z0-9_])onRunTerminal\s*\(/,
|
|
369
|
+
},
|
|
370
|
+
{
|
|
371
|
+
path: '人工暂停 / 中止 (外部控制面)',
|
|
372
|
+
file: 'src/agents/execution-supervisor.ts',
|
|
373
|
+
marker: /runExternallyPaused|applyFlywheelStop/,
|
|
374
|
+
via: FUNNEL_CALL_RE,
|
|
375
|
+
},
|
|
376
|
+
{
|
|
377
|
+
path: '子 Agent 被阻塞 (升级 / 接管)',
|
|
378
|
+
// ★ 2026-09-25 (串行收口) 归属修正: 这条路径的终止动作原来是 Supervisor 自己拼的一条
|
|
379
|
+
// `listGoalsWithPendingWork → collectWorkBlocks → applyBlockHandling` 循环 —— 那是第二套巡检
|
|
380
|
+
// 实现 (M3 的门面是 `sweepAll`)。现在统一巡检 (`flywheelSeams().monitor.sweepAll`) 在 Supervisor
|
|
381
|
+
// 的 tick 里被调用, 而**处置动作本体** (`applyBlockHandling`: 升级 → 交人 / 接管) 由接线层作为
|
|
382
|
+
// 接缝的 `handle` 端口注入执行 —— 所以这条路径的归属跟着动作走, 落在接线层。
|
|
383
|
+
// marker/via 都没放松: 动作还是那个动作, 漏斗还是那个漏斗 (closeRunOnce 就定义在同一个文件里)。
|
|
384
|
+
file: 'src/agents/goal-flywheel-wiring.ts',
|
|
385
|
+
marker: /applyBlockHandling\s*\(/,
|
|
386
|
+
via: FUNNEL_CALL_RE,
|
|
387
|
+
},
|
|
388
|
+
];
|
|
389
|
+
/**
|
|
390
|
+
* 别名不许长成第二个漏斗: 每个 `FUNNEL_ALIASES` 里的函数, 函数体里必须真的调 `closeRunOnce(`。
|
|
391
|
+
* (别名存在的唯一理由是"非 Supervisor 宿主也要用同一条链", 不是"给某条路径开个后门"。)
|
|
392
|
+
*/
|
|
393
|
+
export function scanFunnelAliases(files, aliases = FUNNEL_ALIASES) {
|
|
394
|
+
const out = [];
|
|
395
|
+
for (const alias of aliases) {
|
|
396
|
+
const owner = files.find((f) => new RegExp(`(?:function|const)\\s+${alias}\\s*[(<=]`).test(f.text));
|
|
397
|
+
if (!owner) {
|
|
398
|
+
out.push({
|
|
399
|
+
rule: 'all_terminal_paths_pass_close_run',
|
|
400
|
+
path: alias,
|
|
401
|
+
line: 0,
|
|
402
|
+
snippet: '',
|
|
403
|
+
reason: `收尾漏斗的别名 ${alias} 在整个扫描面里都找不到定义 —— 登记过时了`,
|
|
404
|
+
});
|
|
405
|
+
continue;
|
|
406
|
+
}
|
|
407
|
+
const at = owner.text.search(new RegExp(`(?:function|const)\\s+${alias}\\s*[(<=]`));
|
|
408
|
+
const body = owner.text.slice(at, at + 2000);
|
|
409
|
+
if (!new RegExp(`(?<![A-Za-z0-9_])${FUNNEL_ENTRY}\\s*\\(`).test(body)) {
|
|
410
|
+
out.push({
|
|
411
|
+
rule: 'all_terminal_paths_pass_close_run',
|
|
412
|
+
path: owner.path,
|
|
413
|
+
line: owner.text.slice(0, at).split('\n').length,
|
|
414
|
+
snippet: body.split('\n')[0].trim().slice(0, 140),
|
|
415
|
+
reason: `${owner.path} 的 ${alias} 没有在函数体里调 ${FUNNEL_ENTRY} —— 别名长成了第二个漏斗 (两条链 = 两套事实)`,
|
|
416
|
+
});
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
return out;
|
|
420
|
+
}
|
|
421
|
+
export function scanTerminalPaths(files, paths = TERMINAL_PATHS) {
|
|
422
|
+
const out = [];
|
|
423
|
+
const byPath = new Map(files.map((f) => [f.path, f.text]));
|
|
424
|
+
for (const p of paths) {
|
|
425
|
+
const text = byPath.get(p.file);
|
|
426
|
+
if (text === undefined) {
|
|
427
|
+
out.push({
|
|
428
|
+
rule: 'all_terminal_paths_pass_close_run',
|
|
429
|
+
path: p.file,
|
|
430
|
+
line: 0,
|
|
431
|
+
snippet: '',
|
|
432
|
+
reason: `终止路径「${p.path}」登记在 ${p.file}, 但这个文件不存在或没被扫描到 (门自身不能空转)`,
|
|
433
|
+
});
|
|
434
|
+
continue;
|
|
435
|
+
}
|
|
436
|
+
const ls = lines(text);
|
|
437
|
+
const hit = ls.find(({ s }) => p.marker.test(stripLineComment(s)));
|
|
438
|
+
if (!hit) {
|
|
439
|
+
out.push({
|
|
440
|
+
rule: 'all_terminal_paths_pass_close_run',
|
|
441
|
+
path: p.file,
|
|
442
|
+
line: 0,
|
|
443
|
+
snippet: '',
|
|
444
|
+
reason: `终止路径「${p.path}」的终止动作 (${p.marker}) 在 ${p.file} 里找不到 —— 登记过时了, 门必须跟着改`,
|
|
445
|
+
});
|
|
446
|
+
continue;
|
|
447
|
+
}
|
|
448
|
+
if (!p.via.test(text)) {
|
|
449
|
+
out.push({
|
|
450
|
+
rule: 'all_terminal_paths_pass_close_run',
|
|
451
|
+
path: p.file,
|
|
452
|
+
line: hit.n,
|
|
453
|
+
snippet: hit.s.trim().slice(0, 140),
|
|
454
|
+
reason: `终止路径「${p.path}」在 ${p.file}:${hit.n} 终结, 但该文件没有经过收尾漏斗 (${p.via}) → 这条路径绕过了唯一责任链`,
|
|
455
|
+
});
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
return out;
|
|
459
|
+
}
|
|
460
|
+
/**
|
|
461
|
+
* 规则 ⑤: 子 Agent 不能直接改 Goal。
|
|
462
|
+
* 判据: 子 Agent 侧的任何模块都不许触碰 Goal 状态写入面或 continuation 写入面。
|
|
463
|
+
*/
|
|
464
|
+
export function scanChildCannotMutateGoal(files, allowed = DEFAULT_ALLOW.childCannotMutateGoal) {
|
|
465
|
+
const out = [];
|
|
466
|
+
const CHILD_SIDE = /(subagent|child-agent|child_agent|delegate)/i;
|
|
467
|
+
for (const f of files) {
|
|
468
|
+
if (allowed.includes(f.path))
|
|
469
|
+
continue;
|
|
470
|
+
if (!CHILD_SIDE.test(f.path))
|
|
471
|
+
continue;
|
|
472
|
+
for (const { n, s } of lines(f.text)) {
|
|
473
|
+
const code = stripLineComment(s);
|
|
474
|
+
if (/\bupdateGoal\s*\(/.test(code) || /\bsetContinuation\s*\(/.test(code)) {
|
|
475
|
+
out.push({
|
|
476
|
+
rule: 'child_cannot_mutate_goal',
|
|
477
|
+
path: f.path,
|
|
478
|
+
line: n,
|
|
479
|
+
snippet: s.trim().slice(0, 140),
|
|
480
|
+
reason: `${f.path} 是子 Agent 侧, 却直接写 Goal 状态/continuation → 越界 (CHILD_PROHIBITIONS.mutate_parent_goal_state)`,
|
|
481
|
+
});
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
return out;
|
|
486
|
+
}
|
|
487
|
+
/**
|
|
488
|
+
* 规则 ⑥: Skill 不得绕过**验证 + 快照 + 可回退**通道。
|
|
489
|
+
*
|
|
490
|
+
* 注意措辞: M6 之后会允许**自动**晋升, 所以判据**不是**"不许自动",
|
|
491
|
+
* 而是"不许**绕过通道**": 任何把 Skill 写进正式 skills/ 的动作都必须同时有
|
|
492
|
+
* ① 验证 (validate/验收) ② 快照 (snapshotScope / contentHash) ③ 可回退 (fromVersion / 变更原因)。
|
|
493
|
+
* 判据 = 出现"写正式 Skill 目录"的模块必须在通道白名单里, 且白名单里的模块必须真的带这三样。
|
|
494
|
+
*/
|
|
495
|
+
export const SKILL_CHANNEL_EVIDENCE = [
|
|
496
|
+
'/.bolloon/skills/',
|
|
497
|
+
];
|
|
498
|
+
export function scanSkillChannel(files, allowed = DEFAULT_ALLOW.skillChannel) {
|
|
499
|
+
const out = [];
|
|
500
|
+
for (const f of files) {
|
|
501
|
+
if (allowed.includes(f.path))
|
|
502
|
+
continue;
|
|
503
|
+
for (const { n, s } of lines(f.text)) {
|
|
504
|
+
const code = stripLineComment(s);
|
|
505
|
+
// 写正式 Skill 目录 (skills/<name>/SKILL.md) 的路径形态
|
|
506
|
+
if (/['"`][^'"`]*\.bolloon\/skills\//.test(code) && /\bwriteFile\s*\(|\bwrite\b|\bcopyFile\s*\(/.test(code)) {
|
|
507
|
+
out.push({
|
|
508
|
+
rule: 'skill_cannot_bypass_promotion_channel',
|
|
509
|
+
path: f.path,
|
|
510
|
+
line: n,
|
|
511
|
+
snippet: s.trim().slice(0, 140),
|
|
512
|
+
reason: `${f.path} 直接写正式 Skill 目录 → 必须走 验证+快照+可回退 通道`,
|
|
513
|
+
});
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
return out;
|
|
518
|
+
}
|
|
519
|
+
// ============================================================================
|
|
520
|
+
// §4. 允许清单 (每条规则一份; 改这里 = 改冻结面, 必须单独提交并说明为什么)
|
|
521
|
+
// ============================================================================
|
|
522
|
+
export const DEFAULT_ALLOW = {
|
|
523
|
+
/** 规则 ①: 谁能做"继续/不继续"的判定 */
|
|
524
|
+
onlySupervisorDecides: [
|
|
525
|
+
'src/agents/execution-supervisor.ts',
|
|
526
|
+
'src/agents/goal-flywheel-wiring.ts',
|
|
527
|
+
'src/agents/goal-flywheel/wiring/continuation.ts',
|
|
528
|
+
'src/agents/goal-flywheel/continuation-decision.ts',
|
|
529
|
+
'src/agents/mobile-flywheel-view.ts',
|
|
530
|
+
],
|
|
531
|
+
/**
|
|
532
|
+
* 规则 ②: 谁能写 Goal 状态。
|
|
533
|
+
*
|
|
534
|
+
* 只有三处 (每一处都有"为什么绕不过去"的理由):
|
|
535
|
+
* · `goal-store.ts` —— 原语本体 (它定义 `updateGoal`; 门不可能把一个函数挡在它自己外面);
|
|
536
|
+
* · `goal-state-reducer.ts` —— **唯一漏斗** (intent → plan → apply);
|
|
537
|
+
* · `goal-flywheel-wiring.ts` —— M0 组合层: 它的职责就是"把飞轮结论落进 Goal", 且**只经 reducer**
|
|
538
|
+
* (下面 `REDUCER_DELEGATES` 那条断言会检查它真的调了 `reduceGoalState`, 所以这个白名单
|
|
539
|
+
* 不能用来越过漏斗 —— 它是"允许改自己的非状态字段 (goalChanges/证据) 并把状态改道 reducer")。
|
|
540
|
+
* 除此之外任何文件同时出现 updateGoal + 状态信号 = 判红。
|
|
541
|
+
*/
|
|
542
|
+
onlyGoalReducerWritesState: [
|
|
543
|
+
'src/agents/goal-store.ts',
|
|
544
|
+
'src/agents/goal-state-reducer.ts',
|
|
545
|
+
'src/agents/goal-flywheel-wiring.ts',
|
|
546
|
+
],
|
|
547
|
+
/** 规则 ③: 谁能碰 closeRun */
|
|
548
|
+
onlyCloseRunCloses: [
|
|
549
|
+
'src/agents/goal-flywheel/run-closure.ts',
|
|
550
|
+
'src/agents/goal-flywheel-wiring.ts',
|
|
551
|
+
'src/agents/goal-flywheel/wiring/closure.ts',
|
|
552
|
+
// 门的本体: 它里面**写着** `closeRun(` 这个正则字面量 (用来找绕过), 不是真的调用它
|
|
553
|
+
'src/agents/goal-flywheel/wiring/seams.ts',
|
|
554
|
+
],
|
|
555
|
+
/** 规则 ⑤: 子 Agent 侧 (除此之外的子 Agent 文件不许出现写 Goal 的调用) */
|
|
556
|
+
childCannotMutateGoal: [
|
|
557
|
+
'src/agents/goal-flywheel-wiring.ts',
|
|
558
|
+
'src/agents/goal-flywheel/wiring/contract.ts',
|
|
559
|
+
'src/agents/goal-flywheel/work-contract.ts',
|
|
560
|
+
'src/agents/agent-delegate-server.ts',
|
|
561
|
+
],
|
|
562
|
+
/** 规则 ⑥: 谁能写正式 Skill 目录 (通道本身) */
|
|
563
|
+
skillChannel: [
|
|
564
|
+
'src/agents/skills-manager.ts',
|
|
565
|
+
'src/agents/skill-writer.ts',
|
|
566
|
+
'src/agents/goal-flywheel-wiring.ts',
|
|
567
|
+
'src/agents/skill-readiness.ts',
|
|
568
|
+
],
|
|
569
|
+
};
|
|
570
|
+
// ============================================================================
|
|
571
|
+
// §5. 扫描面 (哪些文件进门的视野)
|
|
572
|
+
// ============================================================================
|
|
573
|
+
/** 门上要扫的源文件 (相对仓库根)。门自己会断言每个路径都真的存在 (不许拿空集糊过去)。 */
|
|
574
|
+
export const SCANNED_SOURCES = [
|
|
575
|
+
'src/agents/execution-supervisor.ts',
|
|
576
|
+
'src/agents/pi-sdk.ts',
|
|
577
|
+
'src/agents/goal-store.ts',
|
|
578
|
+
'src/agents/goal-state-reducer.ts',
|
|
579
|
+
'src/agents/run-store.ts',
|
|
580
|
+
'src/agents/skills-manager.ts',
|
|
581
|
+
'src/agents/skill-readiness.ts',
|
|
582
|
+
'src/agents/subagent-manager.ts',
|
|
583
|
+
'src/agents/goal-criteria.ts',
|
|
584
|
+
'src/agents/external-events.ts',
|
|
585
|
+
'src/agents/contacts/chain.ts',
|
|
586
|
+
'src/agents/task/task-runner.ts',
|
|
587
|
+
'src/agents/goal-flywheel-wiring.ts',
|
|
588
|
+
'src/agents/mobile-flywheel-view.ts',
|
|
589
|
+
'src/web/server.ts',
|
|
590
|
+
...SEAM_ROSTER.map((s) => `src/agents/goal-flywheel/wiring/${s.module}`),
|
|
591
|
+
'src/agents/goal-flywheel/wiring/seams.ts',
|
|
592
|
+
];
|