@sema-agent/client-core 0.6.0 → 0.8.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.
Files changed (68) hide show
  1. package/README.md +31 -11
  2. package/dist/adapt.d.ts +4 -2
  3. package/dist/adapt.js +225 -25
  4. package/dist/compensations.d.ts +63 -0
  5. package/dist/compensations.js +138 -0
  6. package/dist/detachWire.d.ts +141 -0
  7. package/dist/detachWire.js +182 -0
  8. package/dist/diff/patch.d.ts +29 -0
  9. package/dist/diff/patch.js +45 -0
  10. package/dist/engineSessionParam.d.ts +11 -0
  11. package/dist/engineSessionParam.js +41 -0
  12. package/dist/engineWireTarget.d.ts +14 -0
  13. package/dist/engineWireTarget.js +53 -0
  14. package/dist/finalVerifyWire.d.ts +74 -0
  15. package/dist/finalVerifyWire.js +63 -0
  16. package/dist/fleet/fleetLedger.d.ts +132 -0
  17. package/dist/fleet/fleetLedger.js +393 -0
  18. package/dist/fleet/fleetProjection.d.ts +181 -0
  19. package/dist/fleet/fleetProjection.js +258 -0
  20. package/dist/headlessPermissionModeWire.d.ts +55 -0
  21. package/dist/headlessPermissionModeWire.js +111 -0
  22. package/dist/headlessReconnectWire.d.ts +96 -0
  23. package/dist/headlessReconnectWire.js +141 -0
  24. package/dist/hooksWireCaps.d.ts +91 -0
  25. package/dist/hooksWireCaps.js +359 -0
  26. package/dist/host.d.ts +34 -2
  27. package/dist/host.js +6 -0
  28. package/dist/index.d.ts +74 -1
  29. package/dist/index.js +104 -1
  30. package/dist/interactiveToolsWire.d.ts +48 -0
  31. package/dist/interactiveToolsWire.js +86 -0
  32. package/dist/limitsWire.d.ts +89 -0
  33. package/dist/limitsWire.js +225 -0
  34. package/dist/liveInitToolFace.d.ts +53 -0
  35. package/dist/liveInitToolFace.js +251 -0
  36. package/dist/model/modelFamilies.json +63 -0
  37. package/dist/model/providerPresets.d.ts +46 -0
  38. package/dist/model/providerPresets.js +160 -0
  39. package/dist/model/providerPresets.json +1179 -0
  40. package/dist/notifications.d.ts +7 -0
  41. package/dist/notifications.js +32 -0
  42. package/dist/sandboxWire.d.ts +75 -0
  43. package/dist/sandboxWire.js +138 -0
  44. package/dist/scenarioWire.d.ts +62 -0
  45. package/dist/scenarioWire.js +115 -0
  46. package/dist/seam.d.ts +52 -5
  47. package/dist/seam.js +15 -2
  48. package/dist/subagent/engineCompactWire.d.ts +12 -0
  49. package/dist/subagent/engineCompactWire.js +176 -0
  50. package/dist/subagent/engineDelegatedPrompt.d.ts +44 -0
  51. package/dist/subagent/engineDelegatedPrompt.js +205 -0
  52. package/dist/subagent/engineRowStopGate.d.ts +18 -0
  53. package/dist/subagent/engineRowStopGate.js +54 -0
  54. package/dist/subagent/engineSubagentOutput.d.ts +15 -0
  55. package/dist/subagent/engineSubagentOutput.js +98 -0
  56. package/dist/subagent/engineSubagentSteer.d.ts +10 -0
  57. package/dist/subagent/engineSubagentSteer.js +68 -0
  58. package/dist/subagent/engineSubagentTail.d.ts +40 -0
  59. package/dist/subagent/engineSubagentTail.js +241 -0
  60. package/dist/subagent/engineTaskHandleWire.d.ts +90 -0
  61. package/dist/subagent/engineTaskHandleWire.js +212 -0
  62. package/dist/toolResult.d.ts +118 -0
  63. package/dist/toolResult.js +774 -0
  64. package/dist/workflowClient.d.ts +42 -0
  65. package/dist/workflowClient.js +467 -0
  66. package/dist/workflowMonitor.d.ts +94 -0
  67. package/dist/workflowMonitor.js +43 -0
  68. package/package.json +5 -3
package/dist/host.d.ts CHANGED
@@ -30,8 +30,13 @@ import { type NotificationQueuePort } from './notifications.js';
30
30
  export interface SettingsPort {
31
31
  /** 按来源取 settings(cli `utils/settings/settings.ts` 的 `getSettingsForSource`)。 */
32
32
  getSettingsForSource(source: string): unknown;
33
- /** 信任门:该 hook 是否因来源不受信而跳过。**返回 true = 跳过**。 */
34
- shouldSkipHookDueToTrust(hook: unknown): boolean;
33
+ /**
34
+ * 信任门:hook 是否因工作区未受信而跳过。**返回 true = 跳过**。
35
+ * 🔴 B6 更正:壳侧真身 `utils/hooks.shouldSkipHookDueToTrust()` 是**零参**的(门是工作区级、
36
+ * 不是逐条 hook 级)。B4 定口时按「逐条判」写了一个必填参,与真身不符 —— 改成可选参:
37
+ * 既容得下零参真身,也不妨碍将来某个端要做逐条判。库内唯一调用点(hooksWireCaps)不传参。
38
+ */
39
+ shouldSkipHookDueToTrust(hook?: unknown): boolean;
35
40
  }
36
41
  /**
37
42
  * fs 口 —— scratchpad 目录族(cli `utils/permissions/filesystem.ts`)。
@@ -49,6 +54,29 @@ export interface TimersPort {
49
54
  setTimer(ms: number, fn: () => void): unknown;
50
55
  clearTimer(handle: unknown): void;
51
56
  }
57
+ /**
58
+ * session 口(**B6 引入**)—— 「现在是哪个会话 / 哪个 run 在飞」。
59
+ *
60
+ * 为什么必须是端给:这两个量在壳里分别住在 `liveSessionStore`(引擎首轮 done 回填的权威值)+
61
+ * `bootstrap/state`(壳 boot 时生成的 uuidv7)与 `engineToolDetach`(pty 绑定的活跃 run),
62
+ * **三个都是宿主生命周期资产**;web 宿主是路由参数 + BFF 会话,桌面是主进程 session-host。
63
+ *
64
+ * 🔴 缺席后果**不是**「少个装饰」:`engineSessionParam()` 恒 undefined ⇒ durable 面
65
+ * (taskOutput/taskStop/subagentOutput)对 session-bound run 一律 **404 fail-closed**
66
+ * ([1501]§三 / [1498]③),整条子代读面静默哑掉。所以本口**计 miss**。
67
+ *
68
+ * 🔴 `currentSessionId()` 绝不返回空串 —— `?session=`(空值)按「带了且不匹配」判 404
69
+ * ([1501] 空串陷阱);端返空串时库当缺席处理(下面 `engineSessionParam` 有归一)。
70
+ */
71
+ export interface SessionPort {
72
+ /** 当前会话 id(壳:引擎捕获值优先、退 boot-time id);两源都缺 ⇒ undefined。 */
73
+ currentSessionId(): string | undefined;
74
+ /**
75
+ * 当前**活跃引擎 run** 的 id(壳 = `engineToolDetach.getActiveEngineTaskId()`,由
76
+ * X-Task-Id 响应头早捕获)。没有在飞的 turn ⇒ undefined/null 都收。
77
+ */
78
+ activeRunId(): string | undefined | null;
79
+ }
52
80
  /** `installHost` 的入参 —— 全部可选,缺席即该能力不启用。 */
53
81
  export interface HostPorts {
54
82
  log?(level: AdapterLogLevel, msg: string, data?: unknown): void;
@@ -58,6 +86,8 @@ export interface HostPorts {
58
86
  timers?: TimersPort;
59
87
  settings?: SettingsPort;
60
88
  fs?: FsPort;
89
+ /** B6:会话/活跃 run 口(缺席 ⇒ durable 子代面对 session-bound run 恒 404,见 SessionPort)。 */
90
+ session?: SessionPort;
61
91
  }
62
92
  /**
63
93
  * 装配宿主口。**可多次调用做增量装配**(只覆盖本次给出的键),便于分模块装。
@@ -76,6 +106,8 @@ export declare function hostSettings(): SettingsPort | undefined;
76
106
  export declare function hostFs(): FsPort | undefined;
77
107
  /** 定时器口(缺席 = undefined,不计 miss:T40 竞速本就允许不启用)。 */
78
108
  export declare function hostTimers(): TimersPort | undefined;
109
+ /** session 口(缺席 = undefined + 计 miss:漏装会让整条 durable 子代读面 404 静默哑掉)。 */
110
+ export declare function hostSession(): SessionPort | undefined;
79
111
  /**
80
112
  * 🔴 宿主自检出口 —— 恒应为空对象。非空 = 有口漏装,**对应的面已经在静默失效**。
81
113
  * 含通知队列的 miss(从 notifications.ts 汇过来,宿主只需看这一个数)。
package/dist/host.js CHANGED
@@ -32,6 +32,8 @@ export function installHost(ports) {
32
32
  host.settings = ports.settings;
33
33
  if ('fs' in ports)
34
34
  host.fs = ports.fs;
35
+ if ('session' in ports)
36
+ host.session = ports.session;
35
37
  if ('queue' in ports)
36
38
  installNotificationQueuePort(ports.queue ?? null);
37
39
  return () => {
@@ -58,6 +60,10 @@ export function hostFs() {
58
60
  export function hostTimers() {
59
61
  return host.timers;
60
62
  }
63
+ /** session 口(缺席 = undefined + 计 miss:漏装会让整条 durable 子代读面 404 静默哑掉)。 */
64
+ export function hostSession() {
65
+ return host.session ?? miss('session');
66
+ }
61
67
  /**
62
68
  * 🔴 宿主自检出口 —— 恒应为空对象。非空 = 有口漏装,**对应的面已经在静默失效**。
63
69
  * 含通知队列的 miss(从 notifications.ts 汇过来,宿主只需看这一个数)。
package/dist/index.d.ts CHANGED
@@ -5,6 +5,32 @@
5
5
  * 沿革:@sema-agent/wire-cc-adapter 0.1.0 = seam 类型 + id 确定性派生 + 首批踩坑纯函数;
6
6
  * 0.1.2(#52a)= adapt() 管线首批(纯投影臂全落 + 壳态耦合臂投影成 ChromeEvent + 差分守卫);
7
7
  * 0.2.0 = 迁入 sema-client-core 独立仓并改名(旧 npm 名 deprecate 指本包);
8
+ * 0.8.0 = **B6 批**(设计稿 §3 B6,分两轮落):
9
+ * ——【前半,fleet/子代身份族】fleetClient 沿 §2.5 拆两半(帧体归库、连接归端):
10
+ * `fleet/fleetProjection` + `fleet/fleetLedger` · 子代 wire 族六件(`subagent/*`)·
11
+ * `engineSessionParam`(走新 `SessionPort`)· `engineWireTarget`(七份手抄 `wireConfig()` 收编
12
+ * 前六份,第七份 `planReviewWire` 属 B7)· G13 taskStop 409 五形 typed · Path B 记号时序修。
13
+ * ——【后半,余项收官】① `detachWire` **拆**搬(判定 + cancel-arm 台账进包,信号路径的裸 fetch
14
+ * 发射留宿主 —— 宪法例外 census C1-4;宿主取件口 `detachCancelArm()`)· `workflowClient` 整搬
15
+ * (投影器 + live 源)· `workflowMonitor` 契约(六个类型 + WPe,此前住在 TUI 渲染件里);
16
+ * ② **P4 残件三**:`hooksWireCaps`(SettingsPort 的第一个真消费者;port 缺席 = 整体 fail-closed)·
17
+ * `liveInitToolFace`(凭证换 §8-2 的 `resolveWireAuth`,三条动态 import 转静态)·
18
+ * **model 数据表**(`model/providerPresets.{ts,json}` + `modelFamilies.json` —— `modelBudgetRule`
19
+ * 封顶① 的 `perModelCap` 的唯一来源;与壳树副本有 byte-identity 漂移锁);
20
+ * ③ **P5**:T32/T34/T47/T48/T49(整条进包)与 T35/T36/T44(拆)逐条核实并配断言,新出
21
+ * `compensations.ts` 登记表(自检口 `compensationSplitViolations()` 恒应为空)+ **P1-2 归属回落
22
+ * 定案**(FIFO 回落**不删** = tolerate-absent 保护臂;typed 双键在场恒赢已成对反钉;退役条件
23
+ * 钉在达标线 ≥ server 1.290)。
24
+ * ⚠️ B6 落码事实更正:P5 那八条的**落码全在 B4**,B6 做的是核实 + 登记 + 定案,不是二次搬迁。
25
+ * 0.7.0 = **B5 批**(设计稿 §3 B5):① **配对台账折回**([1857] —— 0.6.0 把 `notifiedRuns`/
26
+ * `cardEnqueuedRuns` 放适配器实例,与清账/记账的另一半不共享前提 = 双卡/UI 零显示/模型二收,
27
+ * 本批整体折回 notifications.ts 的 module 台账);② **B/D/E 层搬入**(`toolResult.ts`:
28
+ * structuredToToolUseResult 14 case + wireOutputToBody 3 臂 + E 层 4 臂),`adapt()` 从此
29
+ * 自己铸 `tool_result` 卡与两处开卡兜底;③ **structured 白名单吃现货**([1840]§一 30 项 ——
30
+ * 在场则 T11/T14 正则退位、T24 的 B 层惰性退位,缺席保回落,退位由**调用计数器**钉死);
31
+ * ④ **T7 诚实缺席**(§8-4:不搬 mock 合成器,改 `_sema_degraded:'wire_carried_no_output'`)与
32
+ * **T20 diff hunks 进包**(`diff/patch.ts`,本包**第一个** runtime dep `diff`)。
33
+ * 🆕 两个 chrome 臂:`bgshell_register`(#117a 判定在库、执行留宿主)· `task_ledger_sync{source:'structured'}`。
8
34
  * 0.6.0 = **B4 批**(设计稿 §3 B4):A 层帧分派**收官**(第 14 臂 `task_progress` + 行绑定/
9
35
  * inline stats/alias/#6 常驻台账/SubagentStart/workflow lane 三级门 + `settlePanelTasks` 三处 sweep
10
36
  * 全接线)· P0-2 tool label 侧信道补漏(0.5.0 真缺口)· **请求面合一**(`request/taskRequest.ts`:
@@ -41,7 +67,20 @@
41
67
  * 本包放实例级是**有意的**(多 session 宿主上 module 形会让两个会话互吞 SubagentStart,见 DIVERGENCE-6)。
42
68
  * —— B3 新增:adapter/runStream.ts(`inFlightTurns` 计数,读口 `isRunStreamActive()`;
43
69
  * 两份实例 = 引擎滚动升级门恒读 false ⇒ **turn 中途热换引擎**,正是它当初要防的事)。
44
- * 🔴 **宿主装配**——B4 起总入口是 `installHost({log,probe,queue,timers,settings,fs})`
70
+ * —— B6 新增(前半):fleet/fleetLedger.ts(`liveBgViews`;两份 ⇒ 引擎温切门恒读空 ⇒ respawn
71
+ * 静默杀掉在飞 bg 子代)· subagent/engineDelegatedPrompt.ts(`transcriptIdByTask`;两份 ⇒
72
+ * Prompt 段恒留白而两边代码看着都对)· engineWireTarget.ts(`installed`)。
73
+ * —— B6 新增(后半,按「两份实例会怎样」从重到轻排):
74
+ * · **hooksWireCaps.ts**(`wireSessionStopHookPrompt` + `wireSessionStopHookCcSemantics`)——
75
+ * 写方 = `/goal` 命令层,读方 = 每 turn 的请求构造期 `hooksForWire()`。两份 ⇒ 目标设了、
76
+ * 投不出去,**而两边代码看着都对**(与 fleetLedger 同一种静默失效)。
77
+ * · **detachWire.ts**(`cancelArm`)—— 写方 = `-p` 发头那一刻,读方三个:`isDetachArmed`
78
+ * (400 分诊的第一道门)、`detachedTaskId`(分诊文案)、`detachCancelArm`(**宿主发射腿的
79
+ * 取件口**)。两份 ⇒ 头发了但 hint 判不出 + Ctrl+C 取消不掉,两个静默失效各一半。
80
+ * · liveInitToolFace.ts(`cached`)—— 两份只是多探一次 `/v1/capabilities/scenarios/:name`,
81
+ * **不是**静默失效;仍登记,免得下次读表的人以为它没状态。
82
+ * · model/providerPresets.ts(`presetIndexCache`)—— 由不可变 JSON 派生的纯 memo,两份只费内存。
83
+ * 🔴 **宿主装配**——B4 起总入口是 `installHost({log,probe,queue,timers,settings,fs,session})`
45
84
  * (`installNotificationQueuePort()` 仍是队列的真源出口,`installHost({queue})` 直通它,两者不分裂);
46
85
  * 自检口 `hostPortMisses()` 恒应为空对象,非空 = 有口漏装、对应的面已在静默失效。
47
86
  * —— B2 起的既有说明:`installNotificationQueuePort()` ——
@@ -50,6 +89,13 @@
50
89
  * (runStream 的两条切边:statusline 真 usage / plan-review 审批卡)· `ctx.setTimer`
51
90
  * (T40 IDLE-FLUSH,不给 = 长工具参数生成期已生成内容仍押到下一帧才上屏)· `ctx.signal`
52
91
  * (Esc 中断)· `ctx.log` / `ctx.probe`(诊断面)。
92
+ * —— B6 的两个**计 miss** 口(缺席不是「少个装饰」):`session`(缺 ⇒ durable 子代读面对
93
+ * session-bound run 一律 404 fail-closed)· `settings`(缺 ⇒ `hooksForWire()` 整体 fail-closed
94
+ * 返回 undefined —— 信任门是**安全门**,库不会「读不到策略就照投」)。
95
+ *
96
+ * 🔴 **补偿层账本**(B6 引入):`MIGRATED_COMPENSATIONS` + `compensationSplitViolations()` ——
97
+ * 哪条壳侧补偿拆成了「判定归库 / 执行留宿主」、对面挂在哪个 chrome 臂、上游到货后何时退休,
98
+ * 全做成数据。它**不是** `ADAPTER_DIVERGENCES`(那张表说的是 adapt 与 cli 行为**不同**的地方)。
53
99
  */
54
100
  export * from './seam.js';
55
101
  export * from './workflow.js';
@@ -102,3 +148,30 @@ export * from './request/taskRequest.js';
102
148
  export * from './clientSlice.js';
103
149
  export * from './host.js';
104
150
  export * from './scratchpadWireCaps.js';
151
+ export * from './toolResult.js';
152
+ export * from './diff/patch.js';
153
+ export * from './sandboxWire.js';
154
+ export * from './scenarioWire.js';
155
+ export * from './finalVerifyWire.js';
156
+ export * from './limitsWire.js';
157
+ export * from './interactiveToolsWire.js';
158
+ export * from './headlessPermissionModeWire.js';
159
+ export * from './headlessReconnectWire.js';
160
+ export * from './fleet/fleetProjection.js';
161
+ export * from './fleet/fleetLedger.js';
162
+ export * from './subagent/engineDelegatedPrompt.js';
163
+ export * from './subagent/engineRowStopGate.js';
164
+ export * from './subagent/engineSubagentOutput.js';
165
+ export * from './subagent/engineSubagentSteer.js';
166
+ export * from './subagent/engineTaskHandleWire.js';
167
+ export * from './subagent/engineCompactWire.js';
168
+ export * from './subagent/engineSubagentTail.js';
169
+ export * from './engineSessionParam.js';
170
+ export * from './engineWireTarget.js';
171
+ export * from './detachWire.js';
172
+ export * from './workflowMonitor.js';
173
+ export * from './workflowClient.js';
174
+ export * from './hooksWireCaps.js';
175
+ export * from './liveInitToolFace.js';
176
+ export * from './model/providerPresets.js';
177
+ export * from './compensations.js';
package/dist/index.js CHANGED
@@ -5,6 +5,32 @@
5
5
  * 沿革:@sema-agent/wire-cc-adapter 0.1.0 = seam 类型 + id 确定性派生 + 首批踩坑纯函数;
6
6
  * 0.1.2(#52a)= adapt() 管线首批(纯投影臂全落 + 壳态耦合臂投影成 ChromeEvent + 差分守卫);
7
7
  * 0.2.0 = 迁入 sema-client-core 独立仓并改名(旧 npm 名 deprecate 指本包);
8
+ * 0.8.0 = **B6 批**(设计稿 §3 B6,分两轮落):
9
+ * ——【前半,fleet/子代身份族】fleetClient 沿 §2.5 拆两半(帧体归库、连接归端):
10
+ * `fleet/fleetProjection` + `fleet/fleetLedger` · 子代 wire 族六件(`subagent/*`)·
11
+ * `engineSessionParam`(走新 `SessionPort`)· `engineWireTarget`(七份手抄 `wireConfig()` 收编
12
+ * 前六份,第七份 `planReviewWire` 属 B7)· G13 taskStop 409 五形 typed · Path B 记号时序修。
13
+ * ——【后半,余项收官】① `detachWire` **拆**搬(判定 + cancel-arm 台账进包,信号路径的裸 fetch
14
+ * 发射留宿主 —— 宪法例外 census C1-4;宿主取件口 `detachCancelArm()`)· `workflowClient` 整搬
15
+ * (投影器 + live 源)· `workflowMonitor` 契约(六个类型 + WPe,此前住在 TUI 渲染件里);
16
+ * ② **P4 残件三**:`hooksWireCaps`(SettingsPort 的第一个真消费者;port 缺席 = 整体 fail-closed)·
17
+ * `liveInitToolFace`(凭证换 §8-2 的 `resolveWireAuth`,三条动态 import 转静态)·
18
+ * **model 数据表**(`model/providerPresets.{ts,json}` + `modelFamilies.json` —— `modelBudgetRule`
19
+ * 封顶① 的 `perModelCap` 的唯一来源;与壳树副本有 byte-identity 漂移锁);
20
+ * ③ **P5**:T32/T34/T47/T48/T49(整条进包)与 T35/T36/T44(拆)逐条核实并配断言,新出
21
+ * `compensations.ts` 登记表(自检口 `compensationSplitViolations()` 恒应为空)+ **P1-2 归属回落
22
+ * 定案**(FIFO 回落**不删** = tolerate-absent 保护臂;typed 双键在场恒赢已成对反钉;退役条件
23
+ * 钉在达标线 ≥ server 1.290)。
24
+ * ⚠️ B6 落码事实更正:P5 那八条的**落码全在 B4**,B6 做的是核实 + 登记 + 定案,不是二次搬迁。
25
+ * 0.7.0 = **B5 批**(设计稿 §3 B5):① **配对台账折回**([1857] —— 0.6.0 把 `notifiedRuns`/
26
+ * `cardEnqueuedRuns` 放适配器实例,与清账/记账的另一半不共享前提 = 双卡/UI 零显示/模型二收,
27
+ * 本批整体折回 notifications.ts 的 module 台账);② **B/D/E 层搬入**(`toolResult.ts`:
28
+ * structuredToToolUseResult 14 case + wireOutputToBody 3 臂 + E 层 4 臂),`adapt()` 从此
29
+ * 自己铸 `tool_result` 卡与两处开卡兜底;③ **structured 白名单吃现货**([1840]§一 30 项 ——
30
+ * 在场则 T11/T14 正则退位、T24 的 B 层惰性退位,缺席保回落,退位由**调用计数器**钉死);
31
+ * ④ **T7 诚实缺席**(§8-4:不搬 mock 合成器,改 `_sema_degraded:'wire_carried_no_output'`)与
32
+ * **T20 diff hunks 进包**(`diff/patch.ts`,本包**第一个** runtime dep `diff`)。
33
+ * 🆕 两个 chrome 臂:`bgshell_register`(#117a 判定在库、执行留宿主)· `task_ledger_sync{source:'structured'}`。
8
34
  * 0.6.0 = **B4 批**(设计稿 §3 B4):A 层帧分派**收官**(第 14 臂 `task_progress` + 行绑定/
9
35
  * inline stats/alias/#6 常驻台账/SubagentStart/workflow lane 三级门 + `settlePanelTasks` 三处 sweep
10
36
  * 全接线)· P0-2 tool label 侧信道补漏(0.5.0 真缺口)· **请求面合一**(`request/taskRequest.ts`:
@@ -41,7 +67,20 @@
41
67
  * 本包放实例级是**有意的**(多 session 宿主上 module 形会让两个会话互吞 SubagentStart,见 DIVERGENCE-6)。
42
68
  * —— B3 新增:adapter/runStream.ts(`inFlightTurns` 计数,读口 `isRunStreamActive()`;
43
69
  * 两份实例 = 引擎滚动升级门恒读 false ⇒ **turn 中途热换引擎**,正是它当初要防的事)。
44
- * 🔴 **宿主装配**——B4 起总入口是 `installHost({log,probe,queue,timers,settings,fs})`
70
+ * —— B6 新增(前半):fleet/fleetLedger.ts(`liveBgViews`;两份 ⇒ 引擎温切门恒读空 ⇒ respawn
71
+ * 静默杀掉在飞 bg 子代)· subagent/engineDelegatedPrompt.ts(`transcriptIdByTask`;两份 ⇒
72
+ * Prompt 段恒留白而两边代码看着都对)· engineWireTarget.ts(`installed`)。
73
+ * —— B6 新增(后半,按「两份实例会怎样」从重到轻排):
74
+ * · **hooksWireCaps.ts**(`wireSessionStopHookPrompt` + `wireSessionStopHookCcSemantics`)——
75
+ * 写方 = `/goal` 命令层,读方 = 每 turn 的请求构造期 `hooksForWire()`。两份 ⇒ 目标设了、
76
+ * 投不出去,**而两边代码看着都对**(与 fleetLedger 同一种静默失效)。
77
+ * · **detachWire.ts**(`cancelArm`)—— 写方 = `-p` 发头那一刻,读方三个:`isDetachArmed`
78
+ * (400 分诊的第一道门)、`detachedTaskId`(分诊文案)、`detachCancelArm`(**宿主发射腿的
79
+ * 取件口**)。两份 ⇒ 头发了但 hint 判不出 + Ctrl+C 取消不掉,两个静默失效各一半。
80
+ * · liveInitToolFace.ts(`cached`)—— 两份只是多探一次 `/v1/capabilities/scenarios/:name`,
81
+ * **不是**静默失效;仍登记,免得下次读表的人以为它没状态。
82
+ * · model/providerPresets.ts(`presetIndexCache`)—— 由不可变 JSON 派生的纯 memo,两份只费内存。
83
+ * 🔴 **宿主装配**——B4 起总入口是 `installHost({log,probe,queue,timers,settings,fs,session})`
45
84
  * (`installNotificationQueuePort()` 仍是队列的真源出口,`installHost({queue})` 直通它,两者不分裂);
46
85
  * 自检口 `hostPortMisses()` 恒应为空对象,非空 = 有口漏装、对应的面已在静默失效。
47
86
  * —— B2 起的既有说明:`installNotificationQueuePort()` ——
@@ -50,6 +89,13 @@
50
89
  * (runStream 的两条切边:statusline 真 usage / plan-review 审批卡)· `ctx.setTimer`
51
90
  * (T40 IDLE-FLUSH,不给 = 长工具参数生成期已生成内容仍押到下一帧才上屏)· `ctx.signal`
52
91
  * (Esc 中断)· `ctx.log` / `ctx.probe`(诊断面)。
92
+ * —— B6 的两个**计 miss** 口(缺席不是「少个装饰」):`session`(缺 ⇒ durable 子代读面对
93
+ * session-bound run 一律 404 fail-closed)· `settings`(缺 ⇒ `hooksForWire()` 整体 fail-closed
94
+ * 返回 undefined —— 信任门是**安全门**,库不会「读不到策略就照投」)。
95
+ *
96
+ * 🔴 **补偿层账本**(B6 引入):`MIGRATED_COMPENSATIONS` + `compensationSplitViolations()` ——
97
+ * 哪条壳侧补偿拆成了「判定归库 / 执行留宿主」、对面挂在哪个 chrome 臂、上游到货后何时退休,
98
+ * 全做成数据。它**不是** `ADAPTER_DIVERGENCES`(那张表说的是 adapt 与 cli 行为**不同**的地方)。
53
99
  */
54
100
  export * from './seam.js';
55
101
  export * from './workflow.js';
@@ -118,3 +164,60 @@ export * from './clientSlice.js';
118
164
  export * from './host.js';
119
165
  // B2 判给 B4 的宿主耦合件之一(小的那件,同时是 FsPort 的端到端证明)。
120
166
  export * from './scratchpadWireCaps.js';
167
+ // ── B5 批:工具结果卡 B/D/E 层 + T20 客户端 diff(2026-07-27)────────────────────────────────
168
+ export * from './toolResult.js';
169
+ export * from './diff/patch.js';
170
+ // ── B5 批(B4 残项第一批):S/ 七件 headless / 部署旋钮 wire(2026-07-27)──────────────────────
171
+ // 🔴 env 默认值从 `process.env` 换成 `hostEnv()`(本包零 process;Node 下是同一对象,
172
+ // 壳侧「不传 env 参数」的调用点行为一字节不变 —— 等价性记账见 hostEnv.ts 头注)。
173
+ export * from './sandboxWire.js';
174
+ export * from './scenarioWire.js';
175
+ export * from './finalVerifyWire.js';
176
+ export * from './limitsWire.js';
177
+ export * from './interactiveToolsWire.js';
178
+ export * from './headlessPermissionModeWire.js';
179
+ export * from './headlessReconnectWire.js';
180
+ // ── B6 批:fleet/子代身份族(2026-07-27)────────────────────────────────────────────────────────
181
+ // `fleetClient.ts` 沿设计稿 §2.5 的那一刀拆两半:**帧体归库、连接归端**。
182
+ // 🔴 单例清单新增三项(两份实例 = 面静默失效,不是报错):
183
+ // · `fleet/fleetLedger.ts` 的 `liveBgViews` —— 写=每个 createFleetLedger,读=引擎温切门
184
+ // (`readEngineActiveBgTasks`)与代际让位读面(`isFleetSessionScoped`)。两份 ⇒ 温切门恒读空
185
+ // ⇒ respawn 静默杀掉在飞 bg 子代。
186
+ // · `subagent/engineDelegatedPrompt.ts` 的 `transcriptIdByTask` —— 写=本包 fleetLedger 的行帧/
187
+ // 通知帧臂,读=取件腿。两份 ⇒ Prompt 段恒留白而两边代码看着都对。
188
+ // · `engineWireTarget.ts` 的 `installed` —— 非 Node 宿主的显式 wire 目标。
189
+ export * from './fleet/fleetProjection.js';
190
+ export * from './fleet/fleetLedger.js';
191
+ export * from './subagent/engineDelegatedPrompt.js';
192
+ export * from './subagent/engineRowStopGate.js';
193
+ export * from './subagent/engineSubagentOutput.js';
194
+ export * from './subagent/engineSubagentSteer.js';
195
+ export * from './subagent/engineTaskHandleWire.js';
196
+ export * from './subagent/engineCompactWire.js';
197
+ export * from './subagent/engineSubagentTail.js';
198
+ export * from './engineSessionParam.js';
199
+ export * from './engineWireTarget.js';
200
+ // B6 余项①:headless detach wire(**拆**:判定+cancel-arm 台账进包,信号路径裸 fetch 发射留宿主
201
+ // —— 设计稿 §3 表脚注「`:221` 裸 cancel = TUI 留」;宿主取件口 = `detachCancelArm()`)。
202
+ export * from './detachWire.js';
203
+ // B6 余项①:workflow 监视器契约(类型 + WPe 派生)与 MF-W live 源。
204
+ // 🔴 `workflowMonitor.ts` 是 `projectWorkflowRun()` 产物的**类型契约**——它此前住在 TUI 的
205
+ // `overrides/workflow-detail-dialog.tsx` 里,等于「库产出的形状,契约归渲染件所有」。
206
+ export * from './workflowMonitor.js';
207
+ export * from './workflowClient.js';
208
+ // ── B6 余项②(P4 残件三):B2 判给后批的宿主耦合件收官 + model 数据表 ──────────────────────────
209
+ // 🔴 `hooksWireCaps` 是 **SettingsPort 的第一个消费者**(B4 定的口,B6 才接上);port 缺席时它
210
+ // **整体 fail-closed 返回 undefined** —— 信任门是安全门,不是取值。单实例清单新增:
211
+ // `wireSessionStopHookPrompt`/`wireSessionStopHookCcSemantics`(`/goal` 会话级 Stop 钩子锁存)。
212
+ export * from './hooksWireCaps.js';
213
+ // 🔴 `liveInitToolFace` 的三条 fail-soft 动态 import 在包内变成静态 import(三件 B5 已在包内),
214
+ // try/catch 逐条保留(它护的另一半「函数自己抛」在包内照样成立)。单实例:探测缓存 `cached`。
215
+ export * from './liveInitToolFace.js';
216
+ // 🔴 model 数据表 —— `modelBudgetRule.defaultMaxTokensFor()` 的封顶① 参数 `perModelCap` 的**唯一**
217
+ // 来源。表不在包里,那条中央规则在 web/桌面上恒拿不到 cap ⇒ 对 deepseek-chat(8192)这类模型
218
+ // 超发 ⇒ 网关 400。搬迁期与壳树两份 JSON 由 pure 门的 byte-identity 断言锁住。
219
+ export * from './model/providerPresets.js';
220
+ // ── B6 余项③(P5):补偿层登记表 —— 把「哪条补偿拆了、拆缝对面是谁、什么时候能退休」做成数据。
221
+ // 🔴 它**不是** `ADAPTER_DIVERGENCES`(那张表说的是 adapt 与 cli 行为不同的地方;本表里的东西
222
+ // 两侧行为相同)。自检口 `compensationSplitViolations()` 恒应为空。
223
+ export * from './compensations.js';
@@ -0,0 +1,48 @@
1
+ /**
2
+ * src/sema/interactiveToolsWire.ts — headless `-p` 的 TaskRequest.interactiveTools:false stamp
3
+ * ([909]B 件3,采 [911]② core 正解,2026-07-16)。
4
+ *
5
+ * WHY:core 1.296 起 TaskSpec 有 `interactiveTools?: boolean` 三态旋钮(dist/core/types.d.ts:241);
6
+ * prepare-task.js 两处消费:
7
+ * :635 plan 门 `spec.enablePlanMode === true && spec.interactiveTools !== false`
8
+ * :974 AskUserQuestion roster `interactiveTools === true || (interactiveTools !== false &&
9
+ * (onQuestion !== undefined || durableQuestionFace))`
10
+ * ⇒ `-p` 无人值守姿势 stamp `false`,AskUserQuestion/plan 门从 roster【源头】全灭(模型压根看不到
11
+ * 该工具)= [909]A3(headless EnterPlanMode→park 弃 86% 预算)类事故的根治,比 [884]A1 的
12
+ * park→error 终帧防御纵深更靠前(现在根本不 park)。
13
+ *
14
+ * 语义(headlessPermissionModeWire 同点同型 wire):
15
+ * · 仅 headless `-p` 车道(本模块只被 seamQueryEngine.ask import;交互 REPL 一根毛不动);
16
+ * · 显式交互意图恒赢:CLI 无 --interactive-tools 类旗(gap-check 2026-07-16:上游 CC 2.1.207
17
+ * 与本壳 argv 面均无,不发明);既有旗里唯一表达「我要交互门」的是 `--permission-mode plan`
18
+ * (plan 流程本身要 plan-review 交互)——该旗在场时不 stamp(维持引擎缺省判据);
19
+ * · SEMA_HEADLESS_INTERACTIVE_TOOLS 部署旋钮(settings env 车道):true/1 = 不 stamp(回引擎
20
+ * 缺省判据),false/0 = 显式 stamp false(与缺省同效,显式垫);非法值一次性 warn + 回缺省;
21
+ * · 缺省 = stamp false(无人值守正解);
22
+ * · 旧 server 白名单 fail-soft:server resolveSpec 逐字段白名单拼 TaskSpec,未知 body 字段静默
23
+ * 忽略(limits wire 同款勘察结论)——本字段发了白发不炸。gap-check 实拆 server 1.210.0 dist:
24
+ * resolveSpec(main.js:1233-)【不】读 body.interactiveTools ⇒ 需 server 半场补一行白名单,
25
+ * 壳先备(黑板记账)。
26
+ */
27
+ import { type EnvLike } from './hostEnv.js';
28
+ /** 部署旋钮 env 键名(settings.json env 块 → 1a-envseed → process.env 同车道)。 */
29
+ export declare const HEADLESS_INTERACTIVE_TOOLS_ENV = "SEMA_HEADLESS_INTERACTIVE_TOOLS";
30
+ export type InteractiveToolsResolution = {
31
+ /** 直接展开进 TaskRequest 的字段({} = 不 stamp)。 */
32
+ fields: {
33
+ interactiveTools?: false;
34
+ };
35
+ source: 'default' | 'env' | 'plan-flag';
36
+ /** 非法 env 值的告警文案(调用层一次性打 stderr)。 */
37
+ warning?: string;
38
+ };
39
+ /** argv 里是否显式要了 plan 交互意图(`--permission-mode plan` / `--permission-mode=plan`;
40
+ * 后出现者赢,commander 同语义;`--` 之后不是 flag)。 */
41
+ export declare function planModeExplicitlyRequested(argv: readonly string[]): boolean;
42
+ /**
43
+ * 解析 headless `-p` 的 interactiveTools stamp。纯函数除告警 latch。
44
+ * 调用方(seamQueryEngine.ask)live-gated:mock/pty 车道永不经过这里。
45
+ */
46
+ export declare function resolveHeadlessInteractiveTools(argv: readonly string[], env?: EnvLike): InteractiveToolsResolution;
47
+ /** 测试钩子:重置一次性告警 latch。 */
48
+ export declare function _resetInteractiveToolsWireForTest(): void;
@@ -0,0 +1,86 @@
1
+ /**
2
+ * src/sema/interactiveToolsWire.ts — headless `-p` 的 TaskRequest.interactiveTools:false stamp
3
+ * ([909]B 件3,采 [911]② core 正解,2026-07-16)。
4
+ *
5
+ * WHY:core 1.296 起 TaskSpec 有 `interactiveTools?: boolean` 三态旋钮(dist/core/types.d.ts:241);
6
+ * prepare-task.js 两处消费:
7
+ * :635 plan 门 `spec.enablePlanMode === true && spec.interactiveTools !== false`
8
+ * :974 AskUserQuestion roster `interactiveTools === true || (interactiveTools !== false &&
9
+ * (onQuestion !== undefined || durableQuestionFace))`
10
+ * ⇒ `-p` 无人值守姿势 stamp `false`,AskUserQuestion/plan 门从 roster【源头】全灭(模型压根看不到
11
+ * 该工具)= [909]A3(headless EnterPlanMode→park 弃 86% 预算)类事故的根治,比 [884]A1 的
12
+ * park→error 终帧防御纵深更靠前(现在根本不 park)。
13
+ *
14
+ * 语义(headlessPermissionModeWire 同点同型 wire):
15
+ * · 仅 headless `-p` 车道(本模块只被 seamQueryEngine.ask import;交互 REPL 一根毛不动);
16
+ * · 显式交互意图恒赢:CLI 无 --interactive-tools 类旗(gap-check 2026-07-16:上游 CC 2.1.207
17
+ * 与本壳 argv 面均无,不发明);既有旗里唯一表达「我要交互门」的是 `--permission-mode plan`
18
+ * (plan 流程本身要 plan-review 交互)——该旗在场时不 stamp(维持引擎缺省判据);
19
+ * · SEMA_HEADLESS_INTERACTIVE_TOOLS 部署旋钮(settings env 车道):true/1 = 不 stamp(回引擎
20
+ * 缺省判据),false/0 = 显式 stamp false(与缺省同效,显式垫);非法值一次性 warn + 回缺省;
21
+ * · 缺省 = stamp false(无人值守正解);
22
+ * · 旧 server 白名单 fail-soft:server resolveSpec 逐字段白名单拼 TaskSpec,未知 body 字段静默
23
+ * 忽略(limits wire 同款勘察结论)——本字段发了白发不炸。gap-check 实拆 server 1.210.0 dist:
24
+ * resolveSpec(main.js:1233-)【不】读 body.interactiveTools ⇒ 需 server 半场补一行白名单,
25
+ * 壳先备(黑板记账)。
26
+ */
27
+ import { hostEnv } from './hostEnv.js';
28
+ /** 部署旋钮 env 键名(settings.json env 块 → 1a-envseed → process.env 同车道)。 */
29
+ export const HEADLESS_INTERACTIVE_TOOLS_ENV = 'SEMA_HEADLESS_INTERACTIVE_TOOLS';
30
+ /** argv 里是否显式要了 plan 交互意图(`--permission-mode plan` / `--permission-mode=plan`;
31
+ * 后出现者赢,commander 同语义;`--` 之后不是 flag)。 */
32
+ export function planModeExplicitlyRequested(argv) {
33
+ let mode;
34
+ for (let i = 0; i < argv.length; i++) {
35
+ const a = argv[i];
36
+ if (a === '--permission-mode') {
37
+ const v = argv[i + 1];
38
+ if (typeof v === 'string' && !v.startsWith('-')) {
39
+ mode = v;
40
+ i++;
41
+ }
42
+ }
43
+ else if (a?.startsWith('--permission-mode=')) {
44
+ mode = a.slice('--permission-mode='.length);
45
+ }
46
+ else if (a === '--') {
47
+ break;
48
+ }
49
+ }
50
+ return mode === 'plan';
51
+ }
52
+ // 一次性告警 latch(-p 是 one-shot 进程;测试钩子可重置)
53
+ let warnedInvalidEnv = false;
54
+ /**
55
+ * 解析 headless `-p` 的 interactiveTools stamp。纯函数除告警 latch。
56
+ * 调用方(seamQueryEngine.ask)live-gated:mock/pty 车道永不经过这里。
57
+ */
58
+ export function resolveHeadlessInteractiveTools(argv, env = hostEnv()) {
59
+ // 1) 显式交互意图恒赢:--permission-mode plan ⇒ 不 stamp(plan 流程要 plan-review 门)。
60
+ if (planModeExplicitlyRequested(argv)) {
61
+ return { fields: {}, source: 'plan-flag' };
62
+ }
63
+ // 2) 部署旋钮。
64
+ const raw = env[HEADLESS_INTERACTIVE_TOOLS_ENV]?.trim();
65
+ if (raw !== undefined && raw !== '') {
66
+ if (raw === 'true' || raw === '1')
67
+ return { fields: {}, source: 'env' }; // 回引擎缺省判据
68
+ if (raw === 'false' || raw === '0')
69
+ return { fields: { interactiveTools: false }, source: 'env' };
70
+ const resolution = {
71
+ fields: { interactiveTools: false },
72
+ source: 'default',
73
+ };
74
+ if (!warnedInvalidEnv) {
75
+ warnedInvalidEnv = true;
76
+ resolution.warning = `sema: ${HEADLESS_INTERACTIVE_TOOLS_ENV}="${raw}" is not a boolean (expected true/1/false/0) — ignoring it, headless -p keeps interactive tools OFF by default`;
77
+ }
78
+ return resolution;
79
+ }
80
+ // 3) 缺省:无人值守 stamp false(AskUserQuestion/plan 门 roster 源头全灭)。
81
+ return { fields: { interactiveTools: false }, source: 'default' };
82
+ }
83
+ /** 测试钩子:重置一次性告警 latch。 */
84
+ export function _resetInteractiveToolsWireForTest() {
85
+ warnedInvalidEnv = false;
86
+ }
@@ -0,0 +1,89 @@
1
+ /**
2
+ * src/sema/limitsWire.ts — headless `-p` run-limits wire (TB2.0 反馈批 E · P2-3-b, 2026-07-15):
3
+ * expose the engine's REQUEST-LEVEL pacing limits on the headless `-p` path via `TaskRequest.limits`.
4
+ * The server accepts `limits:{timeoutSec?,maxOutputTokens?,maxTurns?}` since 1.196.0 (positive-integer
5
+ * 400 gate, board [857]) and feeds the EXISTING pacing machinery (deadlineNudge / callCapByDeadline /
6
+ * gracefulFinalize) — the shell simply never stamped the field. This module is the CLI face.
7
+ *
8
+ * TWO FLAGS, TWO ALIGNMENT BUCKETS:
9
+ * · `--deadline <sec>` → limits.timeoutSec. Upstream CC 2.1.207 has NO deadline flag (nearest kin:
10
+ * --max-turns / --task-budget / --max-budget-usd) → SUPERSET, help copy says so.
11
+ * · `--max-turns <n>` → limits.maxTurns. Upstream CC 2.1.207 HAS `--max-turns` (source 199676 /
12
+ * 793380) → ALIGNMENT-GAP fill: the flag was already registered (main.tsx CC-inherited surface) and
13
+ * drove the local query loop, but the seam path executes turns ENGINE-side — this wire finally
14
+ * carries the cap to where the turns actually run.
15
+ *
16
+ * PRECEDENCE per knob (flag > settings > none), scenarioWire 三件套同款:
17
+ * a) explicit flag → strict validation, FAIL-LOUD on an invalid
18
+ * value (integer domain below; a mis-typed pacing bound must not quietly run unbounded).
19
+ * b) settings env lane (settings.json `env` block → 1a-envseed → process.env):
20
+ * `SEMA_HEADLESS_DEADLINE_SEC` / `SEMA_HEADLESS_MAX_TURNS` → SILENT degrade on an invalid value
21
+ * (spec'd 静默降级 — a settings typo must never brick every headless run; unlike scenarioWire we
22
+ * don't even warn, per the batch-E triage shape. SEMA_DEBUG surfaces the drop for diagnosis).
23
+ * c) neither → NO stamp = today's behaviour, verbatim.
24
+ *
25
+ * DOMAINS (integer, inclusive): timeoutSec 30..86400 · maxTurns 1..1000.
26
+ *
27
+ * VERSION GATE (triage risk ③ — an OLD server SILENTLY SWALLOWS unknown body fields, worse than not
28
+ * shipping): the self-spawned engine is release-pinned ≥1.197.0 so the dev/release lanes are safe by
29
+ * construction; but a user-supplied SEMA_ENGINE_URL may point at an older engine. When the user
30
+ * EXPLICITLY passed a flag (env-lane defaults stay quiet) and SEMA_ENGINE_URL is in play, the caller
31
+ * probes `${baseUrl}/health` (the engine self-describes `version` since 1.96) and prints ONE honest
32
+ * stderr line when version <1.196.0 — the request still goes out unchanged (warn, don't block).
33
+ * Unreachable /health or an unparsable version stays silent (can't confirm staleness — fail-soft).
34
+ */
35
+ import { type EnvLike } from './hostEnv.js';
36
+ /** Settings-lane env knobs (settings.json `env` block → 1a-envseed → process.env). */
37
+ export declare const HEADLESS_DEADLINE_ENV = "SEMA_HEADLESS_DEADLINE_SEC";
38
+ export declare const HEADLESS_MAX_TURNS_ENV = "SEMA_HEADLESS_MAX_TURNS";
39
+ /** Integer domains (inclusive). timeoutSec: 30s..24h; maxTurns: 1..1000. */
40
+ export declare const DEADLINE_SEC_MIN = 30;
41
+ export declare const DEADLINE_SEC_MAX = 86400;
42
+ export declare const MAX_TURNS_MIN = 1;
43
+ export declare const MAX_TURNS_MAX = 1000;
44
+ /** First server version whose /v1/tasks|/v1/tasks/stream accept body.limits (board [857]). */
45
+ export declare const LIMITS_WIRE_MIN_ENGINE: readonly [number, number, number];
46
+ export interface HeadlessLimits {
47
+ timeoutSec?: number;
48
+ maxTurns?: number;
49
+ }
50
+ export type LimitsParseResult = {
51
+ ok: true;
52
+ limits?: HeadlessLimits;
53
+ flaggedFlags: string[];
54
+ } | {
55
+ ok: false;
56
+ error: string;
57
+ };
58
+ /**
59
+ * Parse `--deadline` + `--max-turns` out of an argv slice. No flags ⇒ `{ok:true}` with no limits.
60
+ * Repeated flag ⇒ LAST wins (commander convention). Missing value / non-integer / out-of-domain ⇒
61
+ * fail-LOUD parse error (never a silent default — same stance as `--scenario`/`--sandbox`).
62
+ * `flaggedFlags` names the flags that EXPLICITLY contributed (the version-gate probe trigger).
63
+ */
64
+ export declare function parseLimitsArgv(argv: string[]): LimitsParseResult;
65
+ /**
66
+ * The settings-lane defaults. SILENT degrade on a bad value (batch-E triage shape — stricter than
67
+ * scenarioWire's warn-and-ignore: these are pacing hints, and a settings typo must neither brick nor
68
+ * spam every headless run). SEMA_DEBUG surfaces the drop.
69
+ */
70
+ export declare function headlessLimitsFromEnv(env?: EnvLike): HeadlessLimits | undefined;
71
+ /**
72
+ * Resolve the limits for a headless `-p` submit: explicit flags > settings env defaults > none
73
+ * (= no stamp, today's behaviour). Merge is PER-KNOB: `--deadline 300` + SEMA_HEADLESS_MAX_TURNS=50
74
+ * yields {timeoutSec:300, maxTurns:50}. Flag parse errors propagate fail-loud; the caller exits.
75
+ */
76
+ export declare function limitsForPrint(argv: string[], env?: EnvLike): LimitsParseResult;
77
+ /** True when the engine version string satisfies the limits-wire minimum (≥1.196.0). Unparsable ⇒ false. */
78
+ export declare function versionSupportsLimits(v: string | undefined): boolean;
79
+ /**
80
+ * Version-gate probe (triage risk ③): GET `${baseUrl}/health`, read `version`, and return ONE honest
81
+ * stderr line when the engine is confirmed <1.196.0 — the caller prints it and SENDS ANYWAY (the old
82
+ * server drops the field server-side; warn, don't block). Returns undefined when the engine is new
83
+ * enough, unreachable, or self-describes no parsable version (can't confirm staleness — fail-soft
84
+ * silent; the release-pinned self-spawn lane never even reaches this probe).
85
+ */
86
+ export declare function engineLimitsSupportWarning(baseUrl: string, flaggedFlags: string[], opts?: {
87
+ fetchImpl?: typeof fetch;
88
+ timeoutMs?: number;
89
+ }): Promise<string | undefined>;