@sema-agent/client-core 0.12.2 → 0.14.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 (131) hide show
  1. package/README.md +15 -2
  2. package/dist/abortableSleep.d.ts +29 -0
  3. package/dist/abortableSleep.js +43 -0
  4. package/dist/adapt/arms.d.ts +67 -0
  5. package/dist/adapt/arms.js +623 -0
  6. package/dist/adapt/ids.d.ts +22 -0
  7. package/dist/adapt/ids.js +34 -0
  8. package/dist/adapt/instanceLedger.d.ts +36 -0
  9. package/dist/adapt/instanceLedger.js +50 -0
  10. package/dist/adapt/panelTasks.d.ts +59 -0
  11. package/dist/adapt/panelTasks.js +193 -0
  12. package/dist/adapt/textStream.d.ts +63 -0
  13. package/dist/adapt/textStream.js +141 -0
  14. package/dist/adapt/toolCards.d.ts +65 -0
  15. package/dist/adapt/toolCards.js +100 -0
  16. package/dist/adapt/turnFlags.d.ts +37 -0
  17. package/dist/adapt/turnFlags.js +55 -0
  18. package/dist/adapt/wireShapes.d.ts +96 -0
  19. package/dist/adapt/wireShapes.js +167 -0
  20. package/dist/adapt.d.ts +33 -60
  21. package/dist/adapt.js +84 -1207
  22. package/dist/adapter/downstream/eventToSdkMessage.d.ts +57 -13
  23. package/dist/adapter/downstream/eventToSdkMessage.js +174 -106
  24. package/dist/adapter/downstream/terminalToSdkResult.js +151 -160
  25. package/dist/adapter/downstream/turnUsageToModelUsage.d.ts +36 -0
  26. package/dist/adapter/downstream/turnUsageToModelUsage.js +34 -6
  27. package/dist/adapter/runStream.d.ts +36 -4
  28. package/dist/adapter/runStream.js +195 -13
  29. package/dist/adapter/types.d.ts +28 -2
  30. package/dist/agentSession/backgroundView.js +4 -15
  31. package/dist/agentsWireCaps.d.ts +10 -6
  32. package/dist/agentsWireCaps.js +21 -7
  33. package/dist/argvFlagValue.d.ts +41 -0
  34. package/dist/argvFlagValue.js +69 -0
  35. package/dist/attachmentsWireCaps.d.ts +3 -2
  36. package/dist/attachmentsWireCaps.js +5 -3
  37. package/dist/classifierVerdictWire.d.ts +8 -0
  38. package/dist/classifierVerdictWire.js +8 -0
  39. package/dist/cloudConfigWireCaps.d.ts +28 -1
  40. package/dist/cloudConfigWireCaps.js +51 -11
  41. package/dist/controlRouter.d.ts +14 -8
  42. package/dist/controlRouter.js +15 -21
  43. package/dist/detachWire.d.ts +15 -5
  44. package/dist/detachWire.js +17 -7
  45. package/dist/effortWire.d.ts +0 -21
  46. package/dist/effortWire.js +6 -20
  47. package/dist/engineInlineTaskStats.d.ts +12 -6
  48. package/dist/engineWireSdk.d.ts +12 -0
  49. package/dist/env/localeGeo.js +2 -1
  50. package/dist/envFlag.d.ts +39 -0
  51. package/dist/envFlag.js +51 -0
  52. package/dist/finalVerifyWire.d.ts +7 -5
  53. package/dist/finalVerifyWire.js +6 -5
  54. package/dist/fleet/fleetLedger.d.ts +32 -9
  55. package/dist/fleet/fleetLedger.js +119 -34
  56. package/dist/fleet/fleetProjection.d.ts +44 -6
  57. package/dist/fleet/fleetProjection.js +52 -10
  58. package/dist/fleetAgentPanelProjection.d.ts +18 -1
  59. package/dist/fleetAgentPanelProjection.js +61 -14
  60. package/dist/forkWireCaps.d.ts +2 -1
  61. package/dist/forkWireCaps.js +5 -11
  62. package/dist/goalStopHook.d.ts +142 -0
  63. package/dist/goalStopHook.js +258 -0
  64. package/dist/headlessPermissionModeWire.d.ts +10 -0
  65. package/dist/headlessPermissionModeWire.js +24 -21
  66. package/dist/headlessReconnectWire.d.ts +7 -1
  67. package/dist/headlessReconnectWire.js +20 -2
  68. package/dist/hitl/approvalsFeed.d.ts +22 -1
  69. package/dist/hitl/approvalsFeed.js +103 -9
  70. package/dist/hitl/askGateWire.d.ts +27 -96
  71. package/dist/hitl/askGateWire.js +69 -618
  72. package/dist/hitl/frameRouter.d.ts +86 -0
  73. package/dist/hitl/frameRouter.js +383 -0
  74. package/dist/hitl/gateLedger.d.ts +119 -0
  75. package/dist/hitl/gateLedger.js +113 -0
  76. package/dist/hitl/hitlBridge.d.ts +75 -15
  77. package/dist/hitl/hitlBridge.js +94 -22
  78. package/dist/hitl/hitlHostSurface.d.ts +49 -0
  79. package/dist/hitl/hitlHostSurface.js +155 -0
  80. package/dist/hitl/parkResolver.d.ts +74 -0
  81. package/dist/hitl/parkResolver.js +250 -0
  82. package/dist/hitl/planReviewWire.d.ts +60 -2
  83. package/dist/hitl/planReviewWire.js +197 -91
  84. package/dist/hitl/toolApprovalWire.d.ts +67 -4
  85. package/dist/hitl/toolApprovalWire.js +129 -31
  86. package/dist/hooksWireCaps.d.ts +1 -82
  87. package/dist/hooksWireCaps.js +44 -237
  88. package/dist/host.d.ts +16 -5
  89. package/dist/index.d.ts +2 -0
  90. package/dist/index.js +15 -1
  91. package/dist/interactiveToolsWire.d.ts +15 -4
  92. package/dist/interactiveToolsWire.js +24 -26
  93. package/dist/limitsWire.js +7 -40
  94. package/dist/liveInitToolFace.d.ts +51 -6
  95. package/dist/liveQuestionStore.d.ts +18 -6
  96. package/dist/liveQuestionStore.js +15 -0
  97. package/dist/model/providerPresets.js +11 -1
  98. package/dist/notifications.d.ts +62 -2
  99. package/dist/notifications.js +306 -49
  100. package/dist/printToolResultFrame.d.ts +12 -4
  101. package/dist/printToolResultFrame.js +11 -21
  102. package/dist/retainBackgroundWireCaps.d.ts +3 -2
  103. package/dist/retainBackgroundWireCaps.js +5 -9
  104. package/dist/sandboxWire.d.ts +9 -31
  105. package/dist/sandboxWire.js +51 -50
  106. package/dist/scenarioWire.d.ts +1 -1
  107. package/dist/scenarioWire.js +25 -36
  108. package/dist/seam.d.ts +23 -6
  109. package/dist/seam.js +40 -30
  110. package/dist/seatContract.d.ts +369 -83
  111. package/dist/seatContract.js +585 -198
  112. package/dist/selfOrchestrationWireCaps.d.ts +6 -5
  113. package/dist/selfOrchestrationWireCaps.js +8 -12
  114. package/dist/sessionSlot.d.ts +8 -0
  115. package/dist/sessionSlot.js +1 -0
  116. package/dist/steering.js +2 -2
  117. package/dist/subagent/engineTaskHandleWire.d.ts +3 -0
  118. package/dist/subagent/engineTaskHandleWire.js +17 -2
  119. package/dist/subagentContentStore.d.ts +5 -5
  120. package/dist/toolResult.d.ts +89 -8
  121. package/dist/toolResult.js +99 -30
  122. package/dist/typePins.d.ts +17 -0
  123. package/dist/typePins.js +1 -0
  124. package/dist/ultracodeWireCaps.js +5 -6
  125. package/dist/unrefTimer.d.ts +30 -0
  126. package/dist/unrefTimer.js +5 -0
  127. package/dist/workflow.d.ts +3 -2
  128. package/dist/workflow.js +3 -2
  129. package/dist/workflowClient.d.ts +7 -0
  130. package/dist/workflowClient.js +47 -12
  131. package/package.json +3 -3
@@ -1,3 +1,53 @@
1
+ /**
2
+ * ⇄ B6 批搬迁(2026-07-27,设计稿 §3 B6 · B2 判给后批的**宿主耦合六件**之一):cli
3
+ * `src/sema/liveInitToolFace.ts` 整搬。B2 当时不搬的理由 = 它 `await import('./engineTarget.js')`
4
+ * 取凭证,而 engineTarget 是 fs 重图;B4 的 §8-2 收编把凭证解析定到了 `resolveWireAuth`
5
+ * (engineWireSdk,零依赖),那条理由随之消失。
6
+ *
7
+ * 🔴 搬迁三处差分(行为一字节不变):
8
+ * ① 凭证:`engineTarget.resolveLiveAuthToken(baseUrl)`(其 token 缺省 = `process.env.SEMA_LIVE_TOKEN`)
9
+ * → `resolveWireAuth(baseUrl, env.SEMA_LIVE_TOKEN)`。两者是同一套 #118 三态,`resolveWireAuth`
10
+ * 的头注自述就是它的收编口。取值面完全一致:三态里只有**真 token 串**与 `'anon'` 是 string,
11
+ * `{mode:'loopback-unauthed'}` 是对象 ⇒ 原文那句 `typeof t === 'string' ? t : undefined` 语义照搬。
12
+ * ② 三个 `await import('./xxxWire.js')` fail-soft 动态 import → **静态 import**(scenarioWire /
13
+ * interactiveToolsWire / webSearchWireCaps 三件 B5 都已在本包内)。原文那三层 try/catch 的
14
+ * 目的是「模块缺席也别挡首帧」,包内它们不可能缺席;**try/catch 仍逐条保留**——它护的另一半是
15
+ * 「函数自己抛」,那半在包内照样成立。
16
+ * ③ `process.env` → 入参 `EnvLike`(签名本来就显式收 env;缺省值不存在,调用方必传)。
17
+ *
18
+ * 🔴 模块级状态:`cached`(baseUrl+scenario+旋钮 键控的一次性探测缓存)。写读口都在本文件;
19
+ * 两份实例只是多探一次(不是静默失效),但仍登记进单实例清单。
20
+ *
21
+ * ── 以下为原文件的领域说明(逐字保留)────────────────────────────────────────────────────────
22
+ *
23
+ * liveInitToolFace — 件1(core [931] 壳半场):headless `-p` live 车道 `system/init` 首帧的
24
+ * `tools` 自报面,从「壳静态工具表」改为「引擎实挂 wire 词表」生成。
25
+ *
26
+ * 根因(core [931]/CC209 裁决):壳自报静态表(TodoWrite 在、TaskCreate 族不在)而引擎 wire 实挂
27
+ * TaskCreate 族(core 1.296+ 默认)且不挂 TodoWrite ⇒ SDK/自动化消费者照自报面配
28
+ * `--disallowedTools TodoWrite` 之类静默无效(fail-open)。core 1.300 已在引擎侧加名单池审计
29
+ * advisory(config.toolpolicy.unmatched_names)兜观测面;这里是壳半场 = 自报按实挂生成。
30
+ *
31
+ * 真源层级(gap-check 2026-07-16 实测读数,server 1.214.0 / core 1.300.0):
32
+ * 1. server 无全量挂载探测面:GET /v1/capabilities 只有能力布尔;
33
+ * GET /v1/capabilities/scenarios/:name 只含【场景附加】工具(default/code →
34
+ * Now/WebFetch/Agent/TaskCreate 族七具),首方 band(Bash/Read/…)由 core prepare-task
35
+ * 另挂、不进该面 ⇒ 整表无法远端取。
36
+ * 2. 故缺省场景用壳已知 wire 词表(下表):观测 tap 记录壳 `-p` live 车道 LLM 请求体
37
+ * tools[].name(REMOTE_EXEC=host 生产姿势)实测定稿,再按壳自己 stamp 的请求旋钮修正
38
+ * (interactiveTools≠false → AskUserQuestion;settings.webSearch 在 → WebSearch)。
39
+ * 3. per-scenario 差异如实标注:非缺省 scenario(--scenario/SEMA_HEADLESS_SCENARIO)的工具面
40
+ * 由部署定义(scan/oa = repo-readonly 面,首方 band 是否在位壳无法确证)⇒ 尽力探场景详情面
41
+ * GET /v1/capabilities/scenarios/:name 报【场景附加】工具 + runner 恒挂段,并经
42
+ * SEMA_DEBUG 如实标注是探测面而非整表;探测失败回退缺省词表(fail-soft,绝不阻塞首帧)。
43
+ * 4. mock/离线车道(无 SEMA_LIVE_BASEURL)返回 null,调用方保持现状静态表 —— 宪法三问的
44
+ * 补偿轴:离线态回退静态表,行为字节不变。
45
+ *
46
+ * 已知局限(如实):词表按 pin 的 server/core 版本定稿,外接旧引擎或无执行底座的 worker
47
+ * (REMOTE_EXEC 缺省的裸 worker 不挂 hands band)会有偏差 —— 但相比旧静态表(TodoWrite 幻影 +
48
+ * TaskCreate 族缺席)已是严格更准的自报;整表探测面等引擎侧补(见 [931] 报告)。
49
+ */
50
+ import { type EngineProbeOpts } from './engineWireSdk.js';
1
51
  import type { EnvLike } from './hostEnv.js';
2
52
  /** hands band(本地/远程执行底座在位时 prepare-task 挂载;壳自 spawn 恒 REMOTE_EXEC=host ⇒ 在位)。 */
3
53
  export declare const ENGINE_HANDS_BAND: readonly string[];
@@ -30,12 +80,7 @@ export declare function _resetLiveInitToolFaceForTest(): void;
30
80
  * maxRetries=0 单发同原语义);ScenarioDetail 类型面之外仍保留逐字段运行时校验(引擎回什么不轻信)。
31
81
  * 差分:SDK Transport 恒 stamp x-agent-principal(缺省 'anon:shell-live')——原手抄在无 principal
32
82
  * 时省略该头;principal-first 宪法姿势,对 requirePrincipal 部署是 fail-open 改善。 */
33
- export declare function probeScenarioTools(baseUrl: string, scenario: string, opts?: {
34
- fetchImpl?: typeof fetch;
35
- timeoutMs?: number;
36
- authToken?: string;
37
- principal?: string;
38
- }): Promise<{
83
+ export declare function probeScenarioTools(baseUrl: string, scenario: string, opts?: EngineProbeOpts): Promise<{
39
84
  tools: string[];
40
85
  toolset?: string;
41
86
  } | null>;
@@ -1,3 +1,4 @@
1
+ import type { AskAnswer } from './hitl/hitlBridge.js';
1
2
  /**
2
3
  * src/sema/liveQuestionStore.ts — the SIDE-CHANNEL for §4④ live-stream AskUserQuestion (the conversation-seam
3
4
  * twin of liveSessionStore.ts).
@@ -54,13 +55,11 @@ export interface QuestionFrame {
54
55
  }
55
56
  /** The answer the overlay sends back — keyed by HEADER; `selected` echoes exact option labels
56
57
  * (`selected ⊆ options`, core's fence); off-list / free-text input rides `note` (untrusted-fenced).
57
- * Entry shape === hitlBridge's AskAnswer (the T23 ApprovalDecision.answer leg consumes it as-is). */
58
+ * REF-CC-038(2026-08-02):entry 直接是 hitlBridge 的 `AskAnswer`(唯一源),不再各写一份 ——
59
+ * 之前这里是一份内联匿名形的独立声明,只靠注释断言与 hitlBridge 那份「形状相同」,
60
+ * 下游(`askGateWire.ts`)因此要 `as AskAnswer[]` 兜齐两个名不同的等价形状。 */
58
61
  export interface QuestionAnswer {
59
- answers: Array<{
60
- header: string;
61
- selected: string[];
62
- note?: string;
63
- }>;
62
+ answers: AskAnswer[];
64
63
  }
65
64
  type QuestionFrameHandler = (frame: QuestionFrame) => void;
66
65
  type RespondFn = (id: string, answer: QuestionAnswer, opts?: {
@@ -69,6 +68,19 @@ type RespondFn = (id: string, answer: QuestionAnswer, opts?: {
69
68
  /** Register a one-shot local responder for a SYNTHETIC question frame (e.g. `plan-review:<taskId>`).
70
69
  * Returns an unregister fn (dialog dismissed without answering ⇒ caller cleans up). */
71
70
  export declare function registerLocalQuestionResponder(id: string, fn: RespondFn): () => void;
71
+ /**
72
+ * Is a local responder for this synthetic questionId still bound?([2393] hitl-F3,2026-08-02)
73
+ *
74
+ * 🔴 为什么这是**只读探询**而不是「谁注册谁自己记着就行」:上面那条契约把「对话框被 dismiss 却没
75
+ * 作答」的清理责任交给了 caller,而 caller(planReviewWire)自己那份武装态与这张表是**两个**容器 ——
76
+ * 两个容器各自都可能被单方面改动(`respondToQuestion` 的一次性 delete、别的注册把同 id 顶掉后再
77
+ * 注销),于是「我以为还武装着」和「表里还真有人收答」会漂开。漂开的后果不是多弹一张卡,是
78
+ * **一张都不弹**:去重短路认为卡还在,而实际上没有任何 responder 能收答([paired-mechanisms-must-
79
+ * share-premise])。给出这条探询口,让去重臂能问真相而不是问自己的记忆。
80
+ *
81
+ * 🔴 只回答布尔:responder 函数本身绝不出境(它闭包着 caller 的一次性状态,交出去就有第二个调用者)。
82
+ */
83
+ export declare function hasLocalQuestionResponder(id: string): boolean;
72
84
  /**
73
85
  * Publish a demuxed live question frame (called from liveClient's demuxQuestionFrames on each
74
86
  * `question`/`question_complete`). Best-effort: a UI handler error is swallowed so a broken overlay can NEVER
@@ -20,6 +20,21 @@ export function registerLocalQuestionResponder(id, fn) {
20
20
  localResponders.delete(id);
21
21
  };
22
22
  }
23
+ /**
24
+ * Is a local responder for this synthetic questionId still bound?([2393] hitl-F3,2026-08-02)
25
+ *
26
+ * 🔴 为什么这是**只读探询**而不是「谁注册谁自己记着就行」:上面那条契约把「对话框被 dismiss 却没
27
+ * 作答」的清理责任交给了 caller,而 caller(planReviewWire)自己那份武装态与这张表是**两个**容器 ——
28
+ * 两个容器各自都可能被单方面改动(`respondToQuestion` 的一次性 delete、别的注册把同 id 顶掉后再
29
+ * 注销),于是「我以为还武装着」和「表里还真有人收答」会漂开。漂开的后果不是多弹一张卡,是
30
+ * **一张都不弹**:去重短路认为卡还在,而实际上没有任何 responder 能收答([paired-mechanisms-must-
31
+ * share-premise])。给出这条探询口,让去重臂能问真相而不是问自己的记忆。
32
+ *
33
+ * 🔴 只回答布尔:responder 函数本身绝不出境(它闭包着 caller 的一次性状态,交出去就有第二个调用者)。
34
+ */
35
+ export function hasLocalQuestionResponder(id) {
36
+ return localResponders.has(id);
37
+ }
23
38
  /**
24
39
  * Publish a demuxed live question frame (called from liveClient's demuxQuestionFrames on each
25
40
  * `question`/`question_complete`). Best-effort: a UI handler error is swallowed so a broken overlay can NEVER
@@ -85,7 +85,17 @@ export function inferFamily(modelId) {
85
85
  const ctx = capSuffix[2] === 'm' ? n * 1000000 : n * 1024;
86
86
  const base = inferFamily(raw.replace(/\[[0-9]+[km]\]$/, ''));
87
87
  // perModelCap 透传:后缀只声明 ctx,不改该模型的确证输出 cap(deepseek-chat[1m] 仍 cap 8192)
88
- return { id: base?.id ?? 'cap-suffix', name: base?.name ?? 'capacity suffix', match: '', contextWindow: ctx, maxTokens: base?.maxTokens ?? 64000, vision: base?.vision, perModelCap: base?.perModelCap };
88
+ // eopt:vision/perModelCap 是「缺省=未知不 stamp」的条件展开位(与 taskId/status 那种「键恒在」
89
+ // 公面契约不同义——那两位没有「已确认为未知」这个第三态,这两位有),诚实透传 base 的键在场与否。
90
+ return {
91
+ id: base?.id ?? 'cap-suffix',
92
+ name: base?.name ?? 'capacity suffix',
93
+ match: '',
94
+ contextWindow: ctx,
95
+ maxTokens: base?.maxTokens ?? 64000,
96
+ ...(base?.vision !== undefined ? { vision: base.vision } : {}),
97
+ ...(base?.perModelCap !== undefined ? { perModelCap: base.perModelCap } : {}),
98
+ };
89
99
  }
90
100
  const id = normalizeId(raw);
91
101
  // ① preset 大表精确(含剥变体尾巴后再试)——精确命中才带 perModelCap(F2 裁决封顶① 证据位;
@@ -176,6 +176,37 @@ export declare function outstandingWorkflowCount(): number;
176
176
  * 必然送达或 TTL 放弃(2h 上界=run 蒸发极端形,与 CC 等本地 bg 任务的无界形同族)。 */
177
177
  export declare function outstandingDeliverableWorkflowCount(): number;
178
178
  export declare function subscribeOutstandingWorkflows(listener: () => void): () => void;
179
+ /**
180
+ * 🔴 已**停止等待**的 outstanding 条目数(workflow + bg 合计,process-lifetime 只增)。
181
+ * 消费方(footer / headless 退出前的收尾行)据此把「N 个后台任务已停止等待」与「都送达了」
182
+ * 分开渲——H1:排队与放弃对消费方必须可分辨。additive:既有计数口的语义一字节不变。
183
+ */
184
+ export declare function outstandingAbandonedCount(): number;
185
+ /**
186
+ * 观测口:被**静默 return 掉**的投递次数(notif-02)。去重与丢失在行为上都是「不入队」,
187
+ * 不记账就在观测上等价 —— 分成两个键是因为它们的正当性完全不同:
188
+ * · `bgDedupDropped` = 同 (taskId,seq,status) 键重复,**正当**(at-least-once 双投自免),恒可 >0;
189
+ * · `bgCrossChannelDropped` = 首周期已由别的通道送达而被压制,**正当但需可查**(seq 透传一旦
190
+ * 回归,复活周期会伪装成首周期落进这一格 —— 这个数异常增长就是 seq 又丢了的信号);
191
+ * · `stuckTickResets` = 在飞 tick 超过 STUCK_TICK_RESET_MS 被强制复位的次数,**恒应为 0**;
192
+ * >0 = 有 probe 连 PROBE_TIMEOUT_MS 都没能截断它。
193
+ *
194
+ * 🔴 [2393] F-1 补两格 —— 上面三格全是 **enqueue 内部**的记账,而 watcher 收摊臂在到达 enqueue
195
+ * **之前**就把台账条目删掉了:「复活周期被秒删」这条路径对上面三格 100% 不可见(立案时被点名当
196
+ * 信号的 `bgCrossChannelDropped` 正是这样对它零判别力的)。删除动作要挣得,也要看得见:
197
+ * · `bgWatchRevivalPromoted` = 收摊臂靠 probe 实证「任务又在跑」把条目升到新周期的次数
198
+ * —— 正是修前被静默秒删的那一类;>0 说明 wire 的 seq 没到货,壳在自己补周期号;
199
+ * · `bgWatchCollectedUnprobed` = probe 未装(mock/离线)时按裸 id 黑名单**盲摘**的次数,
200
+ * 这是唯一保留的无证据删除;>0 = 有完成周期在这类宿主上恒不可观察。
201
+ */
202
+ export interface NotificationDropCounters {
203
+ bgDedupDropped: number;
204
+ bgCrossChannelDropped: number;
205
+ stuckTickResets: number;
206
+ bgWatchRevivalPromoted: number;
207
+ bgWatchCollectedUnprobed: number;
208
+ }
209
+ export declare function notificationDropCounters(): NotificationDropCounters;
179
210
  /** liveClient 在构造会话 client 时注册(带正确 baseUrl/token/principal 的 workflows.get)。 */
180
211
  export declare function installWorkflowStatusProbe(probe: WorkflowStatusProbe): void;
181
212
  type BgTaskStatusProbe = (taskId: string) => Promise<{
@@ -185,8 +216,22 @@ type BgTaskStatusProbe = (taskId: string) => Promise<{
185
216
  /** 委派 prompt 取件口(行消费端建行/详情页兜底用)。未登记 ⇒ undefined(诚实缺席)。 */
186
217
  export declare function outstandingBgTaskPrompt(taskId: string): string | undefined;
187
218
  export declare function installBgTaskStatusProbe(probe: BgTaskStatusProbe): void;
188
- /** bridge 在 Agent async_launched 回执(structured type:'agent')经过时登记。幂等;已通知不再登记。 */
189
- export declare function registerOutstandingBgTask(taskId: string, description: string, prompt?: string): void;
219
+ /**
220
+ * bridge 在 Agent async_launched 回执(structured type:'agent')经过时登记。按 (taskId,seq) 幂等。
221
+ *
222
+ * 🔴 notif-02(两账分离):登记闸**不再查 `notifiedRunIds`**。那个集合是「模型通知去重」账
223
+ * (哪次完成已经喂给模型了),不是「是否还要观察」账;两账混用的后果是 seq≥2 的复活周期
224
+ * 永远登记不进来(`notifiedRunIds` 全文无 delete 站点,首周期一通知就是终身黑名单)。
225
+ * 首周期若确已送达,由 watcher 的收摊臂在下一拍摘除(见 `tickWatchInner` bg 半场),
226
+ * 代价是一次 no-op 遍历,而不是一整个完成周期的结构性缺席。
227
+ *
228
+ * 🔴 [2393] F-1:`seq` 缺席时这里仍然**按首周期解释,不在登记口猜周期号** —— 猜出来的周期号会
229
+ * 把「已终局任务的回执重放」也升成新周期,方向相反地造出重复通知。周期号只在 watcher 那侧、
230
+ * 拿到 probe 的「它又在跑」这个证据之后才前进(见 `tickWatchInner` 的收摊臂三档)。
231
+ *
232
+ * @param seq bg 子代生命周期号;wire 未带 ⇒ 按首周期(BG_FIRST_SEQ)解释,复活周期由 watcher 补。
233
+ */
234
+ export declare function registerOutstandingBgTask(taskId: string, description: string, prompt?: string, seq?: number): void;
190
235
  export declare function isOwnWorkflowRun(runId: string): boolean;
191
236
  /** 本壳亲手启动过的 workflow run 列表(Set 插入序 = 启动序;/workflows 命令的目标 run 选择用,
192
237
  * cmd-workflows.tsx——fleet source 无行可选时的兜底 id 源)。 */
@@ -211,6 +256,21 @@ export declare function enqueueEngineWorkflowNotification(c: EngineWorkflowCompl
211
256
  /** 测试钩(B2 新增,壳侧原文件没有):清空全部通知台账 + probe 槽 + watcher。
212
257
  * 🔴 生产绝不调用 —— 台账是 process-lifetime 去重的唯一凭据,清了就会双投。 */
213
258
  export declare function _resetEngineTaskNotificationForTest(): void;
259
+ /**
260
+ * 测试钩:**驱动一拍** watcher(生产由 setInterval 驱动,外部无入口 ⇒ 护栏/TTL/deadline
261
+ * 三条链在门里全不可达,notif-01/-02/-03 才会一路活到今天)。
262
+ * @param nowMs TTL 判据的时钟注入(WATCH_TTL_MS 是 2h,不注入时钟就只能真等两小时)。
263
+ * 🔴 生产绝不调用。
264
+ */
265
+ export declare function _tickWatchOnceForTest(nowMs?: number): Promise<void>;
266
+ /**
267
+ * 测试钩:覆写 watcher 时序常量(默认是 10s/60s 量级,门里等不起)。传 null 恢复生产值。
268
+ * 🔴 生产绝不调用;覆写只影响 deadline 与强制复位门,不动 WATCH_INTERVAL_MS/WATCH_TTL_MS。
269
+ */
270
+ export declare function _setWatcherTimingForTest(o: {
271
+ probeTimeoutMs?: number;
272
+ stuckTickResetMs?: number;
273
+ } | null): void;
214
274
  /** 该 objective 是否为 task-notification 自动提交 turn 的注入 XML(整体即通知,非提及)。 */
215
275
  export declare function isTaskNotificationObjective(objective: unknown): boolean;
216
276
  /**