@sema-agent/client-core 0.7.0 → 0.8.1

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.
Files changed (47) hide show
  1. package/README.md +31 -11
  2. package/dist/adapt.js +36 -3
  3. package/dist/compensations.d.ts +63 -0
  4. package/dist/compensations.js +138 -0
  5. package/dist/detachWire.d.ts +141 -0
  6. package/dist/detachWire.js +182 -0
  7. package/dist/engineSessionParam.d.ts +6 -2
  8. package/dist/engineSessionParam.js +24 -18
  9. package/dist/engineWireTarget.d.ts +14 -0
  10. package/dist/engineWireTarget.js +53 -0
  11. package/dist/fleet/fleetLedger.d.ts +132 -0
  12. package/dist/fleet/fleetLedger.js +393 -0
  13. package/dist/fleet/fleetProjection.d.ts +181 -0
  14. package/dist/fleet/fleetProjection.js +258 -0
  15. package/dist/hooksWireCaps.d.ts +91 -0
  16. package/dist/hooksWireCaps.js +359 -0
  17. package/dist/host.d.ts +34 -2
  18. package/dist/host.js +6 -0
  19. package/dist/index.d.ts +56 -1
  20. package/dist/index.js +82 -1
  21. package/dist/liveInitToolFace.d.ts +53 -0
  22. package/dist/liveInitToolFace.js +251 -0
  23. package/dist/model/modelFamilies.json +63 -0
  24. package/dist/model/providerPresets.d.ts +46 -0
  25. package/dist/model/providerPresets.js +160 -0
  26. package/dist/model/providerPresets.json +1179 -0
  27. package/dist/seam.d.ts +19 -3
  28. package/dist/seam.js +14 -2
  29. package/dist/subagent/engineCompactWire.d.ts +12 -0
  30. package/dist/subagent/engineCompactWire.js +176 -0
  31. package/dist/subagent/engineDelegatedPrompt.d.ts +44 -0
  32. package/dist/subagent/engineDelegatedPrompt.js +205 -0
  33. package/dist/subagent/engineRowStopGate.d.ts +18 -0
  34. package/dist/subagent/engineRowStopGate.js +54 -0
  35. package/dist/subagent/engineSubagentOutput.d.ts +15 -0
  36. package/dist/subagent/engineSubagentOutput.js +98 -0
  37. package/dist/subagent/engineSubagentSteer.d.ts +10 -0
  38. package/dist/subagent/engineSubagentSteer.js +68 -0
  39. package/dist/subagent/engineSubagentTail.d.ts +40 -0
  40. package/dist/subagent/engineSubagentTail.js +241 -0
  41. package/dist/subagent/engineTaskHandleWire.d.ts +89 -0
  42. package/dist/subagent/engineTaskHandleWire.js +213 -0
  43. package/dist/workflowClient.d.ts +42 -0
  44. package/dist/workflowClient.js +467 -0
  45. package/dist/workflowMonitor.d.ts +94 -0
  46. package/dist/workflowMonitor.js +43 -0
  47. package/package.json +2 -2
@@ -0,0 +1,258 @@
1
+ import { collapseLabel, taskDescFromName } from '../fleetTaskDesc.js';
2
+ import { rowIdTail } from '../workflow.js';
3
+ /**
4
+ * SDK `FleetTaskStatus` 的终态词汇 —— 非终态即在飞(未知未来值按在飞算,保守)。
5
+ * cli 侧 `engineBgGate.TERMINAL_STATUSES` 是**刻意的第二份**(零模块图污染),drift 由壳的
6
+ * `terminalStatuses.test.ts` 锁定 —— 本批不动那份。
7
+ */
8
+ export const TERMINAL_FLEET_TASK_STATUSES = new Set([
9
+ 'completed',
10
+ 'failed',
11
+ 'killed',
12
+ ]);
13
+ /**
14
+ * 未来/未知 wire 状态 → 渲染词汇(闭集但读侧开集)。
15
+ *
16
+ * ⚠️ **B6 未删 `parked`,与任务书的 G11 指令相反 —— 理由与直证写在这里**:
17
+ * · 直证(server 1.291.0 dist,`fleet/fleet-bus.d.ts` + `fleet-bus.js` 12 处 publishTask):
18
+ * `FleetTaskStatus` 闭集**不含** `parked`,且每处 publishTask 的 status 都出自
19
+ * `completed|failed|killed|running` 四值三元链 ⇒ 今天 `'parked'` 在 fleet 行 wire 上**不可达**,
20
+ * 这一支确实是死分支。
21
+ * · 但**后果方向不对称**([anchor-on-the-deciding-quantity]「先定这个量门控动作的正负号」):
22
+ * 本支是**保护型**映射(把非活非终态的 parked 映到 'awaiting approval');删掉之后
23
+ * 它落 `default` ⇒ 渲成 `running` = **谎报活跃**。core 1.382 已有该状态([1561],
24
+ * design/153 §7.1),server 只是尚未投影 ⇒ 这不是「猜测层」,是**预挂**。
25
+ * 删的收益 = 一行;删的代价 = server 补上透传那天静默说谎。
26
+ * ⇒ 保留 + 把「候 server 预挂」的注释换成上面这条可复核的直证。定谳权交回 PM。
27
+ */
28
+ export function coerceTaskStatus(s) {
29
+ switch (s) {
30
+ case 'queued':
31
+ case 'running':
32
+ case 'waiting':
33
+ case 'stopping':
34
+ case 'awaiting approval':
35
+ case 'idle':
36
+ case 'completed':
37
+ case 'failed':
38
+ case 'killed':
39
+ return s;
40
+ case 'parked':
41
+ return 'awaiting approval';
42
+ default:
43
+ return 'running'; // unknown future status → render as a generic live row (open-set fallback)
44
+ }
45
+ }
46
+ /** 中性 workflow run 状态(running|completed|failed)→ 渲染词汇。 */
47
+ export function coerceWorkflowStatus(s) {
48
+ switch (s) {
49
+ case 'completed':
50
+ return 'completed';
51
+ case 'failed':
52
+ return 'failed';
53
+ case 'killed':
54
+ return 'killed';
55
+ default:
56
+ return 'running';
57
+ }
58
+ }
59
+ /**
60
+ * 187 给 fleet 行命名用的是 agent 的**身份**,从不是它的 objective:
61
+ * `tjl(e) = e.type==="in_process_teammate" ? e.identity.agentName : e.agentType`
62
+ * (ui-modules/0616_053_uiux_ejl.js:20-21)。SDK `FleetTaskRow` 带 `agentType`/`agentName`
63
+ * (§K-7),所以这里**重建** tjl:`agentName`(in-process teammate 实例名)优先,否则 `agentType`
64
+ * (subagent_type/teammate 类型名)。只有引擎还没发身份时才退到 objective 派生的 `name` ——
65
+ * 折成单行、绝不整段多行 prompt、绝不空(187 的显示名恒是非空短身份)。全空 → 短 id 尾。
66
+ */
67
+ export function deriveAgentLabel(agentType, agentName, name, id) {
68
+ const identity = collapseLabel(agentName ?? '') || collapseLabel(agentType ?? '');
69
+ if (identity)
70
+ return identity;
71
+ const collapsed = collapseLabel(name ?? '');
72
+ if (collapsed)
73
+ return collapsed;
74
+ const tail = rowIdTail(id).slice(-8);
75
+ return tail ? `agent ${tail}` : 'agent';
76
+ }
77
+ /**
78
+ * 引擎把 fleet 行的 `description` 设成 agent 的**最后一个工具名**(service fleet-bus
79
+ * `description = ev.toolName`)。187 的行正文是进度摘要、从不是工具动词,所以控制面/合成动词
80
+ * 泄漏进行(clay 见过的 `report_blocked`)是纯分歧。这里压掉**已知**的控制面动词(保守集合),
81
+ * 真实工作工具(Read/Bash/Edit…)原样放行。
82
+ *
83
+ * 集合 = core `RESERVED_AGENT_NAMES`(subagent.ts)的 CC-parity PascalCase 形 + goal 模式的
84
+ * `DeclareDone`。引擎 ≥ core 1.176 经 `canonicalToolName` 发 PascalCase。
85
+ */
86
+ export const CONTROL_TOOL_VERBS = new Set([
87
+ 'Task',
88
+ 'Fork',
89
+ 'StructuredOutput',
90
+ 'ReportBlocked',
91
+ 'ReadToolResult',
92
+ 'ToolSearch',
93
+ 'DeclareDone',
94
+ ]);
95
+ /** 行的活动正文:控制面动词 ⇒ 空(187 从不显示它),否则原样。 */
96
+ export function projectDescription(description) {
97
+ const d = description ?? '';
98
+ return CONTROL_TOOL_VERBS.has(d.trim()) ? '' : d;
99
+ }
100
+ // ── wire 值域过滤器(B6:类型面已到货,这里只剩「脏值不当真」)──────────────────────────────────
101
+ /**
102
+ * `toolUses` —— 子代**累计**工具调用数。语义两条(接错会显示一个「看起来很合理」的错数字):
103
+ * ① **累计不是增量** —— bg 子代 sink 的 usage 是累计口径,与 `turn_end` 的每轮增量相反。直取,绝不累加。
104
+ * ② **缺席 ≠ 0** —— 老 server 不发这个键。有键 ⇒ 真值(含真 0);无键 ⇒ undefined(不知道)。
105
+ */
106
+ export function wireToolUses(r) {
107
+ const v = r.toolUses;
108
+ return typeof v === 'number' && Number.isFinite(v) && v >= 0 ? v : undefined;
109
+ }
110
+ /** `transcriptId` —— 子代转录锚(core 铸的 childSessionId);委派 prompt 凭它去转录读面自取。 */
111
+ export function wireTranscriptId(r) {
112
+ const v = r.transcriptId;
113
+ return typeof v === 'string' && v.length > 0 ? v : undefined;
114
+ }
115
+ /** `currentTool: {toolName, target?}` —— `currentAction` 的结构化同源体(core 1.429 → server 1.288)。 */
116
+ export function wireCurrentTool(r) {
117
+ const v = r.currentTool;
118
+ if (typeof v !== 'object' || v === null)
119
+ return undefined;
120
+ const toolName = v.toolName;
121
+ if (typeof toolName !== 'string' || toolName.length === 0)
122
+ return undefined;
123
+ const target = v.target;
124
+ return {
125
+ toolName,
126
+ ...(typeof target === 'string' && target.length > 0 ? { target } : {}),
127
+ };
128
+ }
129
+ /** `startedCount` —— 「已起过的 agent 数」。🔴 缺席 ≠ 0(见 FleetWorkflowView 键注)。 */
130
+ export function wireStartedCount(r) {
131
+ const v = r.startedCount;
132
+ return typeof v === 'number' && Number.isFinite(v) && v >= 0 ? v : undefined;
133
+ }
134
+ /** `parentToolCallId`(P1-2)—— 归属直读键。空串按缺席处理(引擎不该发,发了也别当真)。 */
135
+ export function wireParentToolCallId(r) {
136
+ const v = r.parentToolCallId;
137
+ return typeof v === 'string' && v.length > 0 ? v : undefined;
138
+ }
139
+ /** 终态四键之 `usage`(数值 verbatim,只挑数字位;全脏 ⇒ 整键缺席,不造空对象)。 */
140
+ export function wireRowUsage(r) {
141
+ const u = r.usage;
142
+ if (typeof u !== 'object' || u === null)
143
+ return undefined;
144
+ const out = {};
145
+ for (const k of ['totalTokens', 'toolUses', 'durationMs', 'tokens', 'turns', 'costMicroUsd']) {
146
+ const v = u[k];
147
+ if (typeof v === 'number' && Number.isFinite(v))
148
+ out[k] = v;
149
+ }
150
+ return Object.keys(out).length > 0 ? out : undefined;
151
+ }
152
+ /** 终态四键之 `editedFiles`(bg 子代专属;脏项逐条丢,不整键丢)。 */
153
+ export function wireEditedFiles(r) {
154
+ const v = r.editedFiles;
155
+ if (!Array.isArray(v))
156
+ return undefined;
157
+ const out = v
158
+ .filter((f) => typeof f === 'object' &&
159
+ f !== null &&
160
+ typeof f.path === 'string' &&
161
+ f.path.length > 0 &&
162
+ typeof f.edits === 'number' &&
163
+ Number.isFinite(f.edits))
164
+ .map(f => ({ path: f.path, edits: f.edits }));
165
+ return out.length > 0 ? out : undefined;
166
+ }
167
+ /** 终态四键之 `stoppedBy`(开放枚举 verbatim:"user"/"parent"/"system"/…)。 */
168
+ export function wireStoppedBy(r) {
169
+ const v = r.stoppedBy;
170
+ return typeof v === 'string' && v.length > 0 ? v : undefined;
171
+ }
172
+ /** 终态四键之 `resumable`(仅 bg 子代有源;非 boolean ⇒ 缺席,**不当 false**)。 */
173
+ export function wireResumable(r) {
174
+ return typeof r.resumable === 'boolean' ? r.resumable : undefined;
175
+ }
176
+ /**
177
+ * wire task 行(Map values)→ 渲染行。树 depth/parentId 来自 wire:无 parentId = 顶层(depth 0),
178
+ * 子行挂在父下面,depth 沿 parent 链算(自引用/环由 `seen` 断)。
179
+ */
180
+ export function projectTasks(allRows, opts) {
181
+ const rows = opts.rowFilter(allRows);
182
+ const viewingTaskId = opts.viewingTaskId;
183
+ const byId = new Map(rows.map(r => [r.id, r]));
184
+ const depthOf = (r) => {
185
+ let d = 0;
186
+ let cur = r;
187
+ const seen = new Set();
188
+ while (cur?.parentId && byId.has(cur.parentId) && !seen.has(cur.id)) {
189
+ seen.add(cur.id);
190
+ d += 1;
191
+ cur = byId.get(cur.parentId);
192
+ }
193
+ return d;
194
+ };
195
+ // descendantCount:有多少行认这一行当爹(行尾的 " (+N)")。
196
+ const childCount = new Map();
197
+ for (const r of rows) {
198
+ if (r.parentId)
199
+ childCount.set(r.parentId, (childCount.get(r.parentId) ?? 0) + 1);
200
+ }
201
+ return rows.map(r => {
202
+ const toolUses = wireToolUses(r);
203
+ const transcriptId = wireTranscriptId(r);
204
+ const currentTool = wireCurrentTool(r);
205
+ const parentToolCallId = wireParentToolCallId(r);
206
+ const stoppedBy = wireStoppedBy(r);
207
+ const usage = wireRowUsage(r);
208
+ const resumable = wireResumable(r);
209
+ const editedFiles = wireEditedFiles(r);
210
+ const task = {
211
+ id: r.id,
212
+ name: deriveAgentLabel(r.agentType, r.agentName, r.name, r.id),
213
+ // 子行帧无 description → 从 name 复原任务描述(CC 锚:行正文恒显 description,不留空列)。
214
+ description: projectDescription(r.description) || taskDescFromName(r.name, r.agentType, r.agentName),
215
+ depth: depthOf(r),
216
+ ...(r.parentId !== undefined ? { parentId: r.parentId } : {}),
217
+ status: coerceTaskStatus(r.status),
218
+ elapsedMs: r.elapsedMs ?? 0,
219
+ tokens: r.tokens ?? 0,
220
+ // 🔴 wire 从无 tokenDir(#50 门禁盘出的真类型错:读点恒 undefined 曾靠 ?? 掩住)——恒壳侧缺省。
221
+ tokenDir: 'down',
222
+ queuedCount: r.queuedCount ?? 0,
223
+ awaitingPlanApproval: r.awaitingPlanApproval ?? false,
224
+ descendantCount: childCount.get(r.id) ?? 0,
225
+ // 198 isViewed:这一行就是被查看的那个 agent(行 id 尾段 = 引擎 taskId)。
226
+ viewed: viewingTaskId !== undefined && rowIdTail(r.id) === viewingTaskId,
227
+ // 🔴 「键缺席」与「值为 0/''」是两件事 —— 只有真给了才落键(下游据「键在不在」判三态)。
228
+ ...(toolUses !== undefined ? { toolUses } : {}),
229
+ ...(transcriptId !== undefined ? { transcriptId } : {}),
230
+ ...(currentTool !== undefined ? { currentTool } : {}),
231
+ ...(parentToolCallId !== undefined ? { parentToolCallId } : {}),
232
+ ...(stoppedBy !== undefined ? { stoppedBy } : {}),
233
+ ...(usage !== undefined ? { usage } : {}),
234
+ ...(resumable !== undefined ? { resumable } : {}),
235
+ ...(editedFiles !== undefined ? { editedFiles } : {}),
236
+ };
237
+ return task;
238
+ });
239
+ }
240
+ /** wire workflow 行 → 渲染行。 */
241
+ export function projectWorkflows(rows) {
242
+ return rows.map(r => {
243
+ const startedCount = wireStartedCount(r);
244
+ return {
245
+ id: r.id,
246
+ // 187 workflow label = `e.summary ?? e.description`(短 label);折成单行,空 → 187 占位符。
247
+ name: collapseLabel(r.name ?? '') || 'Dynamic workflow',
248
+ description: projectDescription(r.description),
249
+ status: coerceWorkflowStatus(r.status),
250
+ doneCount: r.doneCount ?? 0,
251
+ totalCount: r.totalCount ?? 0,
252
+ elapsedMs: r.elapsedMs ?? 0,
253
+ tokens: r.tokens ?? 0,
254
+ failedCount: r.failedCount ?? 0,
255
+ ...(startedCount !== undefined ? { startedCount } : {}),
256
+ };
257
+ });
258
+ }
@@ -0,0 +1,91 @@
1
+ import { type EnvLike } from './hostEnv.js';
2
+ import type { WireHooksConfig } from './finalVerifyWire.js';
3
+ export type { WireHooksConfig };
4
+ /** The env ESCAPE HATCH for the engine leg (see the block comment above). */
5
+ export declare const GOAL_STOP_HOOK_WIRE_ENV = "SEMA_GOAL_STOP_HOOK_WIRE";
6
+ export declare const CC_STOP_SEMANTICS_MIN_SERVER = "1.279.3";
7
+ /**
8
+ * 引擎自报版本是否达到 CC Stop 语义线({@link CC_STOP_SEMANTICS_MIN_SERVER})。
9
+ *
10
+ * 🔴 三条纪律:
11
+ * · **数值比较**,不是字典序(`1.9.0` < `1.279.0`,字符串比较会判反);
12
+ * · **预发版不算达标**(`1.279.0-rc.1` 里那套可能还在改)——正则只认三段纯数字,带 `-` 的直接落
13
+ * null ⇒ false;
14
+ * · 读不出/探不到 ⇒ **false**(降级方向恒安全:老形在新引擎上仍能拦,新形在老引擎上一次都拦不住)。
15
+ */
16
+ export declare function ccStopSemanticsFromVersion(version: string | undefined | null): boolean;
17
+ /**
18
+ * 本会话连着的引擎是否具备 CC Stop 语义?判据 = live 车道的 `/v1/capabilities` 自报 `version`
19
+ * (engineCapsCache 的 boot-kick 缓存,与 `/health.version` 同源)。
20
+ *
21
+ * 🔴 「未判即降级」:caps 探测是构造期 fire-and-forget,`/goal` 真被敲下时通常早已落袋;万一没落袋
22
+ * 就按老引擎走(meta 也同步退档)——**宁可少承诺,不可多承诺**。
23
+ */
24
+ export declare function engineCcStopSemantics(env?: EnvLike): boolean;
25
+ /**
26
+ * Is the `/goal` Stop-hook engine leg armed? **Default ON** since 2026-07-26 — both of the premises
27
+ * that kept it opt-in were disproved by server-side behavior evidence ([1721]) and re-verified against
28
+ * a real engine + real model (cli scripts/run-goal-stop-hook-live-test.mjs). Set
29
+ * `SEMA_GOAL_STOP_HOOK_WIRE=0|false|no|off` to disarm (an operator escape hatch, not a default).
30
+ */
31
+ export declare function isGoalStopHookWireArmed(env?: EnvLike): boolean;
32
+ /**
33
+ * Register (or clear, with `null`) the session-scoped `/goal` Stop prompt hook that rides
34
+ * `settings.hooks.Stop` to the engine. Single-valued: a new goal replaces the previous one,
35
+ * exactly like CC 220's `Xdr` (remove-then-add). Projection is gated by
36
+ * {@link isGoalStopHookWireArmed} — storing is always safe, sending is not (yet).
37
+ */
38
+ export declare function setWireSessionStopHook(prompt: string | null, opts?: {
39
+ /**
40
+ * 这条目标登记时,引擎是否已判定为 CC 语义档({@link engineCcStopSemantics})?
41
+ *
42
+ * 🔴 **为什么要在 set 那一刻锁存,而不是在 {@link hooksForWire} 里现读**:`/goal` 的 meta
43
+ * (对模型讲「会不会拦到条件成立为止」)是在 set 那一刻发出去的,而投影发生在随后每个 turn。
44
+ * 两处各读一次的话,caps 探测中途落袋就会造出「meta 承诺拦到底、投出去的却还是老门」的错配 ——
45
+ * 判据必须锚在**真正决定结果的那个量**上,而它只有一个:**这条目标登记时的档位**。
46
+ * 缺省 false ⇒ 不传就是老引擎档:翻档只能靠证据打开,不能靠默认值。
47
+ */
48
+ ccSemantics?: boolean;
49
+ }): void;
50
+ /** The currently registered `/goal` Stop prompt, or null (registered ≠ projected — see the gate). */
51
+ export declare function getWireSessionStopHook(): string | null;
52
+ /** 当前这条目标登记时锁存的档位(真 = 投裸条件,假 = 投壳自造的门)。 */
53
+ export declare function getWireSessionStopHookCcSemantics(): boolean;
54
+ /**
55
+ * 把 `/goal` 的**原始条件**包成一条对引擎 prompt 载体**可执行**的 Stop 门 prompt。
56
+ *
57
+ * 🔴 适用面(2026-07-26 提货批后):**只用于未达标线的引擎档**(见 {@link CC_STOP_SEMANTICS_MIN_SERVER})。
58
+ * 达标档起引擎自己按 CC
59
+ * 220 逐字组装(系统提示 + 会话转录 + `wrapCondition`),那一档投的是**裸条件** —— 见
60
+ * {@link ccStopSemanticsFromVersion} 与 {@link hooksForWire} 的分道。本函数保留,是 tolerate-absent
61
+ * 的实体:老引擎上退回它,仍能拦一次;删掉它等于在老引擎上静默失效。
62
+ *
63
+ * 🔴 为什么必须包(2026-07-26 live 围栏实测,不是设计偏好):CC 单进程的 prompt 钩子执行器
64
+ * (`src/utils/hooks/execPromptHook.ts`)会给条件**套一层系统提示**(「You are evaluating a hook…
65
+ * 回 `{ok:true}` / `{ok:false,reason}`」)**并把整段会话前置**,所以裸条件在 CC 那边能被真评估。
66
+ * 引擎侧的载体两样都没有:
67
+ * · 无系统提示、无会话历史;
68
+ * · Stop payload 的 `transcript_path` 是**空串**(server basePayload),评估者对本会话是**瞎的**;
69
+ * · 判据 schema 也不同 —— core 只认 stdout JSON 的 `decision:"block"`。
70
+ * 实测(钉版 server 1.277.1 + core 1.416 + 真模型):裸条件 `the project contains a file named
71
+ * DONE.txt` 送过去,载体照样被调用,模型回的是**散文**(「I don't have direct access to your file
72
+ * system…」)⇒ `parseHookStdout` 拿不到 decision ⇒ **一次都不拦**。即:不包 = 每次停机白烧一次
73
+ * 模型调用、零效果。
74
+ *
75
+ * 所以这里把条件包成引擎契约里**能落地**的形状。诚实标注它**够不到 CC 的完整语义**:
76
+ * · 能做到:每个 turn 的**第一次**停机尝试被拦下,目标原文重新注入给模型,逼它自查后再收尾
77
+ * (`stop_hook_active` 为真时门自己收手 ⇒ 不会无限拦停);真正「条件是否成立」的判断交给
78
+ * **有会话、有工具的主模型**,而不是让瞎的评估者假装判断;
79
+ * · 做不到:CC 那种「拦到条件真成立为止」(需要引擎把 transcript 交给载体)、以及「条件满足后
80
+ * 自动清除目标」。这两条是**等件**,meta 文案因此不照抄 CC `Pwo`(见 cmd-goal.tsx)。
81
+ *
82
+ * 台账仍存**原始条件**({@link getWireSessionStopHook}),所以 `/goal clear` 读回的是用户写的那句。
83
+ */
84
+ export declare function buildGoalStopHookPrompt(condition: string): string;
85
+ /**
86
+ * The merged, GOVERNANCE-GATED settings-file hooks for the wire, or undefined when none apply.
87
+ * Per-event arrays concatenate across sources (policy → user → project → local).
88
+ */
89
+ export declare function hooksForWire(): WireHooksConfig | undefined;
90
+ /** 测试钩:清 `/goal` 锁存(壳里靠进程边界隔离;包内同进程多组断言必须能清)。 */
91
+ export declare function __resetHooksWireCapsForTests(): void;