@sema-agent/client-core 0.12.1 → 0.13.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 (127) 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 +58 -0
  5. package/dist/adapt/arms.js +613 -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 +54 -0
  11. package/dist/adapt/panelTasks.js +193 -0
  12. package/dist/adapt/textStream.d.ts +49 -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 +33 -0
  17. package/dist/adapt/turnFlags.js +55 -0
  18. package/dist/adapt/wireShapes.d.ts +93 -0
  19. package/dist/adapt/wireShapes.js +167 -0
  20. package/dist/adapt.d.ts +32 -59
  21. package/dist/adapt.js +78 -1206
  22. package/dist/adapter/downstream/eventToSdkMessage.d.ts +55 -13
  23. package/dist/adapter/downstream/eventToSdkMessage.js +166 -106
  24. package/dist/adapter/downstream/terminalToSdkResult.js +149 -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 +29 -4
  28. package/dist/adapter/runStream.js +129 -13
  29. package/dist/adapter/types.d.ts +2 -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.js +31 -8
  69. package/dist/hitl/askGateWire.d.ts +27 -96
  70. package/dist/hitl/askGateWire.js +69 -546
  71. package/dist/hitl/frameRouter.d.ts +86 -0
  72. package/dist/hitl/frameRouter.js +342 -0
  73. package/dist/hitl/gateLedger.d.ts +107 -0
  74. package/dist/hitl/gateLedger.js +113 -0
  75. package/dist/hitl/hitlBridge.d.ts +75 -15
  76. package/dist/hitl/hitlBridge.js +94 -22
  77. package/dist/hitl/hitlHostSurface.d.ts +49 -0
  78. package/dist/hitl/hitlHostSurface.js +155 -0
  79. package/dist/hitl/parkResolver.d.ts +74 -0
  80. package/dist/hitl/parkResolver.js +241 -0
  81. package/dist/hitl/planReviewWire.d.ts +60 -2
  82. package/dist/hitl/planReviewWire.js +152 -74
  83. package/dist/hitl/toolApprovalWire.d.ts +67 -4
  84. package/dist/hitl/toolApprovalWire.js +119 -31
  85. package/dist/hooksWireCaps.d.ts +1 -82
  86. package/dist/hooksWireCaps.js +34 -235
  87. package/dist/host.d.ts +16 -5
  88. package/dist/index.d.ts +2 -0
  89. package/dist/index.js +15 -1
  90. package/dist/interactiveToolsWire.d.ts +15 -4
  91. package/dist/interactiveToolsWire.js +24 -26
  92. package/dist/limitsWire.js +7 -40
  93. package/dist/liveInitToolFace.d.ts +51 -6
  94. package/dist/liveQuestionStore.d.ts +5 -6
  95. package/dist/model/providerPresets.js +11 -1
  96. package/dist/notifications.d.ts +48 -2
  97. package/dist/notifications.js +223 -46
  98. package/dist/retainBackgroundWireCaps.d.ts +3 -2
  99. package/dist/retainBackgroundWireCaps.js +5 -9
  100. package/dist/sandboxWire.d.ts +9 -31
  101. package/dist/sandboxWire.js +51 -50
  102. package/dist/scenarioWire.d.ts +1 -1
  103. package/dist/scenarioWire.js +25 -36
  104. package/dist/seam.d.ts +23 -6
  105. package/dist/seam.js +40 -30
  106. package/dist/seatContract.d.ts +369 -83
  107. package/dist/seatContract.js +585 -198
  108. package/dist/selfOrchestrationWireCaps.d.ts +6 -5
  109. package/dist/selfOrchestrationWireCaps.js +8 -12
  110. package/dist/sessionSlot.d.ts +8 -0
  111. package/dist/sessionSlot.js +1 -0
  112. package/dist/steering.js +2 -2
  113. package/dist/subagent/engineTaskHandleWire.d.ts +3 -0
  114. package/dist/subagent/engineTaskHandleWire.js +17 -2
  115. package/dist/subagentContentStore.d.ts +5 -5
  116. package/dist/toolResult.d.ts +89 -8
  117. package/dist/toolResult.js +99 -30
  118. package/dist/typePins.d.ts +17 -0
  119. package/dist/typePins.js +1 -0
  120. package/dist/ultracodeWireCaps.js +5 -6
  121. package/dist/unrefTimer.d.ts +19 -0
  122. package/dist/unrefTimer.js +5 -0
  123. package/dist/workflow.d.ts +3 -2
  124. package/dist/workflow.js +3 -2
  125. package/dist/workflowClient.d.ts +7 -0
  126. package/dist/workflowClient.js +47 -12
  127. package/package.json +3 -3
@@ -12,10 +12,11 @@
12
12
  * 落点为什么是本包:desktop 与 web 都已经依赖 `@sema-agent/client-core`(0.11.5),而本文件是
13
13
  * **纯类型 + 常量 + 纯谓词**,零值级 import、零 Node 内建 ⇒ 不动本包的可移植闭包(portability 门的
14
14
  * `EXPECTED_PACKAGES_INDEX` 一个字不变)。
15
- * ⚠️ 唯一一条 `import type`(`./effortWire.js` 的 `ReasoningEffort`)是**类型边**:portability 门
16
- * 走值级传递闭包时按规则剥掉 type-only import(门里 `/^\s*type\b/` 那一跳),bundle 里一个字节都
17
- * 不多。写成 import 而不是就地复刻那七档,是因为「座位闭集」与「wire 投影闭集」必须是**同一套词**
18
- * ——复刻一份就等于埋一条只有真用户能发现的漂移(拨盘上的档在座位 lane 上静默到不了引擎)。
15
+ * ⚠️ 两条 `import type`(`./effortWire.js` 的 `ReasoningEffort`、`./seam.js` 的 `LaneProof`)都是
16
+ * **类型边**:portability 门走值级传递闭包时按规则剥掉 type-only import(门里 `/^\s*type\b/` 那一跳),
17
+ * bundle 里一个字节都不多。写成 import 而不是就地复刻,是因为「座位闭集」与「wire 投影闭集」必须是
18
+ * **同一套词**——复刻一份就等于埋一条只有真用户能发现的漂移(拨盘上的档在座位 lane 上静默到不了引擎;
19
+ * 车道证明在座位面变成一个「有位无证」的空对象)。
19
20
  *
20
21
  * ── 搬迁时按「真源为准」收敛的漂移(逐条,web 侧镜像 → 本文件)────────────────────────────
21
22
  * 🔴 D1 `LocalSessionEvent.outcome` —— web 镜像整位缺席 ⇒ `tool_permission_resolved` 只会清面,
@@ -24,7 +25,7 @@
24
25
  * 而宿主入站门 `requireOptionalPermissionMode` 是**会抛的闭集门**。今日两边词表逐字相等
25
26
  * (web `ComposerMode` 五档 ≡ `PERMISSION_MODE_INTENTS` 五档,已核),所以是**潜伏**不是现症:
26
27
  * ComposerMode 哪天加一档,裸 string 一路放行到宿主门口才抛。收敛成闭集后当天编译红。
27
- * D3 `AttachmentUploadReceipt.sha256` / `ToolPermissionRequest.createdAt` / `StartSessionOptions.cwd`
28
+ * D3 `AttachmentUploadReceipt.sha256` / `ToolPermissionRequest.createdAtMs` / `StartSessionOptions.cwd`
28
29
  * / `.excludeTools` / `LocalSessionRecord.queuedMessages`·`model`·`engineSessionId` ——
29
30
  * web 镜像缺位。都是「没接线」不是「接错线」(web 侧今日无消费点,已核),收敛后位在、待接。
30
31
  * D4 `LocalSessionEvent.request` —— 真源有这个位,**宿主从不发**(session-host 零处写 `request:`);
@@ -37,6 +38,23 @@
37
38
  * focusedSessionState / settingsState / `CHROME_EVENT_KINDS` / `ATTACHMENT_IDS_PER_TASK_CAP`。
38
39
  * 本文件导出后它们对 web 首次可见(接不接线是渲染面的决定)。
39
40
  *
41
+ * ── 🔴 wave2 卡E-seat 的**破坏性契约变更**(2026-08-02,REF-CC-064~070/072~074;发包说明点名)──
42
+ * ① `EipcMethodSpec.validate` / `EipcStoreSpec.validate` → **改名 `check`**,返回形从 `boolean`
43
+ * 升成 `true | SeatValidationFailure`(REF-CC-069)。改名是**安全机制不是洁癖**:老消费点写的是
44
+ * `if (m.validate && !m.validate(v))`,而失败**对象是真值** ⇒ 那一行会把「不合格」读成「合格」,
45
+ * 门从 fail-closed 静默变成 fail-open。改名让每个旧调用点在编译期红,而不是在运行期悄悄放行。
46
+ * ② `ToolPermissionRequest.createdAt: number` → **`createdAtMs`**(REF-CC-067):同一文件里
47
+ * `LocalSessionRecord.createdAt` 是 ISO 串,两个同名位两种域两种类型;epoch 单位入名(A4)。
48
+ * ③ `ToolPermissionRequest.boundCallId` + `.boundInputHash` → **合成 `toctouBinding`**
49
+ * (REF-CC-070):注释一直把它称作 pair,而类型/门此前各查各的,半个 pair 照样过门。
50
+ * ④ `LocalSessionEvent.chrome.laneProof` **可选 → 必填**且升成命名类型 `LaneProof`(REF-CC-064)——
51
+ * 出站门本来就要求它在场,类型却说可以缺席:一个照着这份「单一真源」写的宿主编译全绿、
52
+ * 事件被整条丢掉、而门只回 boolean 说不出为什么。这条是本卡的 bug 修复位。
53
+ * ⑤ `LocalSessionEvent.type` / `.chrome.kind` / `.permissionMode` 三个位闭集化(REF-CC-065)。
54
+ * ⑥ `uploadAttachment` 入参、`getTranscript`/`searchSessions` 返回形、三个 store 状态形全部提成
55
+ * 具名 interface(REF-CC-072/073/074),SPEC 里 13 个内联匿名 validator 收成具名 `check*`。
56
+ * 三端消费坐标见本批 commit message 的「候提货单」节。
57
+ *
40
58
  * ── 沿革(以下正文自 sema-desktop/src/shared/localSessions.ts 逐字迁入)──────────────────────
41
59
  * LocalSessions — the desktop host's session service contract, FORM-ported from the CC desktop
42
60
  * app's `claude.web / LocalSessions` eipc interface (212 methods there; FIRST BATCH here = the four
@@ -55,6 +73,28 @@
55
73
  * @sema-agent/client-core), the contract shape does not.
56
74
  */
57
75
  import type { ReasoningEffort } from "./effortWire.js";
76
+ import type { LaneProof } from "./seam.js";
77
+ import type { QuestionAnswer } from "./liveQuestionStore.js";
78
+ /** 一次门校验的失败说明。 */
79
+ export interface SeatValidationFailure {
80
+ /** 人可读的失败原因,恒在场且非空(宿主日志里那一行的正文)。 */
81
+ reason: string;
82
+ /** 出错的那个键名(嵌套位用点号,如 `chrome.laneProof`)。
83
+ * 缺席 = 这次失败**不归属某一个字段**(整体不是对象 / 是跨字段的联合判据)⇒ 宿主日志只打
84
+ * `service.method` + `reason`,**绝不**回落成 `"unknown"` 或空串当字段名 —— 编出来的字段名会把
85
+ * 排查引到一个根本没出问题的位上(§B10 同族:缺席要如实渲缺席,不是造一个值)。 */
86
+ field?: string;
87
+ }
88
+ /**
89
+ * 门的返回形:成功恰是 `true`(**只有一种写法**,消费端 `=== true` 判定即可),失败带原因。
90
+ *
91
+ * 🔴 为什么不是 `boolean`:这一族门是 fail-closed 的(见 `EipcMethodSpec.check` 的头注),false 时
92
+ * 整条事件/结果都不发。而 boolean 里没有任何位能说出是哪个字段哪条规则不过 —— 渲染端的现象是
93
+ * 「这个面偶尔什么都不来」,宿主端的现象是零日志,两端都无从下手(REF-CC-064 就是这么被埋住的)。
94
+ * 🔴 为什么消费端必须写 `=== true` 而不是 `if (!check(v))`:失败是**对象**(真值)。老写法会把
95
+ * 不合格读成合格 —— 这正是本批把位名从 `validate` 改成 `check` 的原因:让老写法编译期就红。
96
+ */
97
+ export type SeatValidation = true | SeatValidationFailure;
58
98
  export type EipcMethodKind = "invoke" | "event";
59
99
  export interface EipcMethodSpec {
60
100
  kind: EipcMethodKind;
@@ -62,13 +102,15 @@ export interface EipcMethodSpec {
62
102
  * schema gate — `Result from method "<m>" in interface "<S>" failed to pass validation`).
63
103
  * event: validates the PAYLOAD before `webContents.send` (CC's dispatcher-side validator, the
64
104
  * `fQe` position for `LocalSessions.onEvent`). Absent = any result/payload passes (CC has
65
- * `void`-returning methods with trivially-true validators). */
66
- validate?: (value: unknown) => boolean;
105
+ * `void`-returning methods with trivially-true validators).
106
+ * 🔴 位名 `check`(REF-CC-069,原 `validate`):返回 `true | SeatValidationFailure`,消费端必须
107
+ * 写 `if (verdict !== true)` 并把 `reason`/`field` 打进宿主日志 —— 一条被门吃掉的事件从此可诊断。 */
108
+ check?: (value: unknown) => SeatValidation;
67
109
  }
68
110
  export interface EipcStoreSpec {
69
111
  /** Validates the STATE payload both on read replies and on update pushes (fail-closed like the
70
- * method gates). Absent = any state passes. */
71
- validate?: (state: unknown) => boolean;
112
+ * method gates). Absent = any state passes. 位名与返回形同 `EipcMethodSpec.check`。 */
113
+ check?: (state: unknown) => SeatValidation;
72
114
  }
73
115
  export interface EipcServiceSpec {
74
116
  ns: string;
@@ -83,10 +125,17 @@ export interface LocalSessionRecord {
83
125
  sessionId: string;
84
126
  /** Engine (service)-minted session id, known after the first reply; absent before it. */
85
127
  engineSessionId?: string;
128
+ /** 这条会话钉住的模型 id。缺席 = 宿主没为它钉模型 ⇒ 每轮走部署默认(`SeatModelCatalog.defaultId`);
129
+ * 消费端渲那个默认名,**不要**渲空串或「未知模型」(部署默认是一个真实存在的答案)。 */
86
130
  model?: string;
131
+ /** 会话标题。缺席 = 还没有标题(首轮之前 / 摘要未回)⇒ 消费端渲「新会话」占位,不要渲空行。 */
87
132
  title?: string;
88
133
  isRunning: boolean;
134
+ /** ISO-8601 串(host clock)。与 `ToolPermissionRequest.createdAtMs` **不同域**:那一位是 epoch 毫秒数
135
+ * (REF-CC-067 给它加了单位后缀,免得渲染端写出跨两种行复用的 `formatCreatedAt`)。 */
89
136
  createdAt: string;
137
+ /** 最近一次活动时刻(ISO-8601)。缺席 = 自建起没有任何活动 ⇒ 列表按 `createdAt` 排序,
138
+ * **不要**把缺席当成 0 时刻(那会把新会话排到列表最底)。 */
90
139
  lastActivityAt?: string;
91
140
  /** Host-side deferred queue (CC `deferredSends` seat, in submit order — drives the queued-message
92
141
  * bar). Present (possibly empty) whenever the host projects the record during a running turn. */
@@ -95,6 +144,13 @@ export interface LocalSessionRecord {
95
144
  text: string;
96
145
  }>;
97
146
  }
147
+ /** design/80 D-1 的 TOCTOU 绑定**对**(REF-CC-070:此前是两个互不相干的 optional,半个 pair 照样过门)。
148
+ * 一位承载整对 ⇒「只有 callId 没有 inputHash」在类型层不可表达,门里也不用再补联合判据。 */
149
+ export interface ToctouBinding {
150
+ callId: string;
151
+ inputHash: string;
152
+ }
153
+ export declare const TOCTOU_BINDING_KEYS: readonly ["callId", "inputHash"];
98
154
  /** HITL request row (CC's `request` position is schema-gated by `S1`; ours is this shape, projected
99
155
  * from the sema wire's PendingCheckpoint — see session-host). */
100
156
  export interface ToolPermissionRequest {
@@ -114,47 +170,117 @@ export interface ToolPermissionRequest {
114
170
  requestId: string;
115
171
  sessionId: string;
116
172
  /** For the two ask families this is the CC tool vocabulary name the renderer branches on:
117
- * `AskUserQuestion` (question domain) / `McpElicitation` (elicit domain). */
173
+ * `AskUserQuestion` (question domain) / `McpElicitation` (elicit domain).
174
+ * 缺席或 `null` = wire 没给工具名(旧 server / 通用审批行)⇒ 消费端走**通用**审批卡,
175
+ * 绝不猜工具名(猜错就是把 Bash 的确认框渲成别的工具的)。 */
118
176
  toolName?: string | null;
119
177
  /** The ENGINE's tool-call id (`call_…`) — the SAME id the assistant message's `tool_use` block
120
178
  * carries, so a renderer can key the approval onto the tool card that actually raised it.
121
179
  * Present on tool-approval rows from server ≥1.307; `null` when the wire did not offer one
122
180
  * (old server, or the ask families, which have no tool call of their own). NEVER synthesized. */
123
181
  toolCallId?: string | null;
124
- /** UNTRUSTED, service-redacted tool args / question payload (render-only, never re-fed). */
182
+ /** UNTRUSTED, service-redacted tool args / question payload (render-only, never re-fed).
183
+ * 🔴 缺席语义(REF-CC-066):门**刻意不校验**这一位(见 SEAT_VALIDATOR_KEY_COVERAGE 的豁免登记),
184
+ * 所以消费端拿到的可能是 undefined、也可能是任意形状。`question:` 域的整张卡押在 `input.questions`
185
+ * 上 ⇒ 缺席/畸形时渲染端必须显式渲「问题内容不可用」并把决断按钮留给 deny 侧,
186
+ * **绝不**渲一张空卡(空卡看起来像「没有问题要问」,而真相是「问题丢了」)。 */
125
187
  input?: unknown;
126
- /** UNTRUSTED, service-redacted engine ask text (live face only) — display only. */
188
+ /** UNTRUSTED, service-redacted engine ask text (live face only) — display only.
189
+ * 缺席 = 这一族(durable 行)本来就没有引擎问句 ⇒ 渲染端用工具名 + 参数摘要成句,不要留空。 */
127
190
  message?: string;
128
191
  /** design/80 D-1 TOCTOU binding pair (durable face only) — echo VERBATIM into the decision.
129
192
  * 🔴 出站**只读**位:回程的 verbatim 回显由宿主自己的登记表做(session-host 的
130
193
  * `row.boundCallId/boundInputHash`),`ToolPermissionDecision` 因此没有对应席位 —— 渲染端
131
- * 拿到它只为展示,绝不需要(也不该)自己回传。 */
132
- boundCallId?: string;
133
- boundInputHash?: string;
134
- createdAt?: number;
194
+ * 拿到它只为展示,绝不需要(也不该)自己回传。
195
+ * 缺席 = 这一行不是 durable 域(live/question/elicit 三域没有绑定对)⇒ 消费端不渲绑定摘要。 */
196
+ toctouBinding?: ToctouBinding;
197
+ /** 行的诞生时刻,**epoch 毫秒**(单位入名,A4;时钟来源 = 宿主本地 `Date.now()`,不是引擎时钟 ⇒
198
+ * 与转录里的引擎时间戳不可直接相减)。缺席 = wire 那一行没带时间(旧 server 的 durable 行)⇒
199
+ * 消费端渲「刚刚」或不渲时间,**绝不**回落成 0(那会渲成 1970)。 */
200
+ createdAtMs?: number;
135
201
  }
202
+ /**
203
+ * 座位事件名的**闭集**(REF-CC-065):这是三端唯一的事件名真源。
204
+ *
205
+ * 方向判据(本文件 `PERMISSION_MODE_INTENTS` 头注立的那条):词由**我们自己的宿主**铸出、发往渲染端,
206
+ * 因此闭集 —— 拼错一个字母在编译期红,而不是变成一条谁也不认识、被 switch 默默丢掉的事件。
207
+ * 与 `outcome`(wire 铸词,开集)的区别正是「谁铸的词」,不是「字段像不像枚举」。
208
+ * 词表 = sema-desktop `session-host` 的 emit 面实测八词。
209
+ */
210
+ declare const SEAT_EVENT_TYPE_TUPLE: readonly ["start", "close", "session_updated", "message", "stream_event", "chrome_event", "error", "tool_permission_resolved"];
211
+ export type SeatEventType = (typeof SEAT_EVENT_TYPE_TUPLE)[number];
212
+ export declare const SEAT_EVENT_TYPES: readonly SeatEventType[];
213
+ /** Chrome arms wired to the renderer position (batch 4); other arms stay host-side on the ring. */
214
+ declare const CHROME_EVENT_KIND_TUPLE: readonly ["panel_task", "notification_terminal", "prompt_suggestions", "subagent_lifecycle"];
215
+ export type ChromeEventKind = (typeof CHROME_EVENT_KIND_TUPLE)[number];
216
+ /**
217
+ * 🔴 BREAKING(REF-CC-065,2026-08-02):公开面类型从 `readonly string[]` **收窄**成
218
+ * `readonly ChromeEventKind[]`。与 `PERMISSION_MODE_INTENTS` / `SEAT_REASONING_EFFORTS` 那两条
219
+ * **不同**:那两个本来就已经是闭集类型,加元组只是补「类型→常量」那半边、公开面一个字没变;
220
+ * 这一个的公开面**真的变了**,所以它是本批第四处破坏性契约变更,不是「同上理由」的搭车项。
221
+ *
222
+ * 谁受影响(实测消费坐标,提货单同条):`sema-desktop/src/main/session-host.ts:1752`
223
+ * `CHROME_EVENT_KINDS.includes(event.kind)` —— 那里的 `event: ChromeEvent` 是 seam.ts 的 17 词
224
+ * 判别式联合,收窄后 `includes()` 的入参类型只认这 4 个词 ⇒ TS2345,提货当天编译红。
225
+ * 迁移形:`(CHROME_EVENT_KINDS as readonly string[]).includes(event.kind)`,或先按 `ChromeEventKind`
226
+ * 做一次显式收窄再进这一支。sema-web-client / sema-cli 实测零命中。
227
+ */
228
+ export declare const CHROME_EVENT_KINDS: readonly ChromeEventKind[];
229
+ /** chrome 信封的**必填**键(REF-CC-064:`laneProof` 此前类型可选、门必填,两边说的不是一句话)。 */
230
+ export interface SeatChromeEnvelopeBase {
231
+ kind: ChromeEventKind;
232
+ /** 车道证明([1617] 家族一等公民)。**必填**:出站门本来就要求它在场,类型说可选 = 一个合规的
233
+ * 生产者编译全绿、事件被整条静默丢弃。缺席在这条 lane 上不是「降级」,是「这帧不该发出来」。 */
234
+ laneProof: LaneProof;
235
+ }
236
+ /** 臂自身的载荷键随 `kind` 变(client-core `ChromeEvent` 的判别式联合),故留 index 位;
237
+ * 必填两位由 `SeatChromeEnvelopeBase` 承载,键集钉也钉在它上面。 */
238
+ export interface SeatChromeEnvelope extends SeatChromeEnvelopeBase {
239
+ [k: string]: unknown;
240
+ }
241
+ export declare const SEAT_CHROME_ENVELOPE_KEYS: readonly ["kind", "laneProof"];
136
242
  export interface LocalSessionEvent {
137
- type: string;
243
+ /** 事件名(闭集 `SEAT_EVENT_TYPES`)—— 消费端的判别位,switch 可穷举。 */
244
+ type: SeatEventType;
138
245
  sessionId: string;
139
246
  /** 🔴 transcript-plane passthrough (SDKMessage body) — deliberately UNVALIDATED (fQe posture). */
140
247
  message?: unknown;
141
248
  /** 🔴 transcript-plane passthrough batch — array-checked only, elements unvalidated (fQe posture). */
142
249
  messages?: unknown[];
250
+ /** 人可读的失败说明(仅 `error` 事件)。缺席 = 这条事件不是失败事件 ⇒ 渲染端不要因为「没有 error」
251
+ * 就把一次真失败渲成成功;判失败看的是 `type === "error"`,不是这一位在不在。 */
143
252
  error?: string;
253
+ /** 失败的**类别**(宿主自铸:`turn_failed` / `plan_review_failed` …)。缺席 = 宿主没有给这次失败分类
254
+ * ⇒ 渲染端只渲 `error` 文本,不要猜类别、也不要按文案分类(§B8)。 */
144
255
  errorCategory?: string;
256
+ /** 引擎/传输层状态码(有则透传)。缺席 = 这次失败没有码可报(本地异常)⇒ 不渲码位,**绝不**渲 0。 */
145
257
  code?: number;
146
258
  /** CC `fQe` 的 form 位。🔴 **本宿主从不发这个位**(session-host 零处写 `request:`;HITL 行走
147
259
  * 独立的 `onToolPermissionRequest` 通道)—— 位保留是为了与 CC 的 fQe 逐位同形,消费端不该
148
260
  * 为它写分支(见文件头 D4)。 */
149
261
  request?: ToolPermissionRequest;
262
+ /** 自由文本载荷(CC fQe 的 `data` 位,本宿主目前不发)。缺席 = 没有附带文本,消费端不渲这一行。 */
150
263
  data?: string;
264
+ /** 引用来源列表(CC fQe 的 `sources` 位,本宿主目前不发)。缺席 = 没有来源可标 ⇒ 不渲来源脚注;
265
+ * 空数组与缺席同义(都表示「没有来源」),渲染端不必区分。 */
151
266
  sources?: string[];
152
- permissionMode?: string;
267
+ /** 本轮生效的权限模式回显(闭集,与入站 `SendMessageRequest.permissionMode` 同一套词)。
268
+ * 缺席 = 宿主没有回显模式(今日常态:session-host 零处发这一位)⇒ 渲染端继续显示 composer 自己的
269
+ * 模式徽标,**不要**因为缺席就把徽标降回 `default`(那是把「没说」渲成「说了 default」)。
270
+ * 🔴 闭集的前提是「词由我们自己铸」:哪天改成回显**引擎的** effective mode(wire 铸的词),
271
+ * 必须同批把这一位降级成开集,理由与 `outcome` 逐字相同。 */
272
+ permissionMode?: PermissionModeIntent;
273
+ /** 会话行快照(`start`/`close`/`session_updated` 带)。缺席 = 这条事件不携带会话态 ⇒ 消费端
274
+ * 沿用 store 里的现有行,**不要**当成「会话没了」。 */
153
275
  session?: LocalSessionRecord;
276
+ /** 触发这条事件的用户消息 uuid(`message` 事件带)。缺席 = 这条事件不属于某条用户消息(引擎侧自发)
277
+ * ⇒ 渲染端把它挂在当前 turn 上,不要另开一条用户气泡。 */
154
278
  userMessageUuid?: string;
279
+ /** CC form:本条 `message` 之前宿主已清过屏(`/clear` 语义)。缺席 ≡ false(没清过)——
280
+ * 这一位只在为真时出现,消费端按「缺席 = 不清屏」处理即可。 */
155
281
  hasPreClearSession?: boolean;
156
282
  /** On `tool_permission_resolved`: which request settled (so a native notification for it can be
157
- * dismissed — CC `closePermissionNotification(requestId)`). */
283
+ * dismissed — CC `closePermissionNotification(requestId)`). 缺席 = 这条不是审批收面事件。 */
158
284
  requestId?: string;
159
285
  /**
160
286
  * On `tool_permission_resolved`: HOW it settled ([1947] 红③). Without this the renderer only ever
@@ -175,12 +301,9 @@ export interface LocalSessionEvent {
175
301
  outcome?: string;
176
302
  /** On `chrome_event`: one client-core ChromeEvent arm (the NEUTRAL typed chrome vocabulary —
177
303
  * [1832] axiom 2's non-transcript half). Only the renderer-wired arm kinds cross the wire
178
- * (see CHROME_EVENT_KINDS); the outbound gate checks kind membership + the laneProof discipline. */
179
- chrome?: {
180
- kind: string;
181
- laneProof?: unknown;
182
- [k: string]: unknown;
183
- };
304
+ * (see CHROME_EVENT_KINDS); the outbound gate checks kind membership + the laneProof discipline.
305
+ * 缺席 = 这条不是 chrome 事件(按 `type` 判别,不要按这一位在不在判别)。 */
306
+ chrome?: SeatChromeEnvelope;
184
307
  }
185
308
  /**
186
309
  * The resolution words the host currently puts on `tool_permission_resolved.outcome` ([1947] 红③).
@@ -226,10 +349,10 @@ export declare const HITL_RESOLUTION_OUTCOMES: readonly string[];
226
349
  * ignores `remember` here rather than pretend, so the renderer should hide that control for
227
350
  * `elicit:` rows (a button that changes nothing is the false-affordance family again).
228
351
  */
229
- /** Chrome arms wired to the renderer position (batch 4); other arms stay host-side on the ring. */
230
- export declare const CHROME_EVENT_KINDS: readonly string[];
231
352
  export interface StartSessionOptions {
353
+ /** 起会话时钉的模型 id。缺席 = 用部署默认(`SeatModelCatalog.defaultId`),这是一个真实答案而不是错误。 */
232
354
  model?: string;
355
+ /** 起会话时给的标题。缺席 = 宿主不铸标题(记录里的 `title` 随后也缺席,渲染端渲「新会话」)。 */
233
356
  title?: string;
234
357
  /** Working directory for the session's hand tools (TaskRequest.cwd). Default = a per-session dir
235
358
  * under the host's workspace base. A UI that picks a project directory passes it here — CC desktop
@@ -269,13 +392,15 @@ export interface SeatTurnSettings {
269
392
  /** CC's `settings.ultracode` PRESET boolean (max thinking × workflow orchestration, service ≥1.48.0
270
393
  * reads `body.settings.ultracode` and expands it). NOT a seventh effort tier — the dial separately
271
394
  * coerces the reasoning axis to `xhigh`, and collapsing the two loses the orchestration half
272
- * (`ultracodeWireCaps` in this package records that semantics verbatim). */
395
+ * (`ultracodeWireCaps` in this package records that semantics verbatim).
396
+ * 缺席 = 没开这个预设(≡ false);渲染端按缺席渲「关」,不必区分缺席与显式 false。 */
273
397
  ultracode?: boolean;
274
398
  }
275
399
  export declare const SEAT_TURN_SETTINGS_KEYS: readonly ["ultracode"];
276
400
  export interface SendMessageRequest {
277
401
  sessionId: string;
278
402
  text: string;
403
+ /** 本轮临时换模型。缺席 = 用会话钉住的模型(`LocalSessionRecord.model`),再缺席才是部署默认。 */
279
404
  model?: string;
280
405
  /** Client-supplied echo key for the user message (CC form: userMessageUuid); minted if absent. */
281
406
  userMessageUuid?: string;
@@ -303,6 +428,20 @@ export interface SendMessageRequest {
303
428
  * today's only member is the `ultracode` preset boolean. */
304
429
  settings?: SeatTurnSettings;
305
430
  }
431
+ /** `uploadAttachment` 入参(REF-CC-074:此前是导出方法签名里的 3 成员内联匿名形,直接命中 B4)。 */
432
+ export interface AttachmentUploadRequest {
433
+ /** 本地文件名。服务端会自己 sanitize 出 `AttachmentUploadReceipt.name`,渲染端显示的是**回执**那个。 */
434
+ name: string;
435
+ /** MIME 类型。缺席 = 让服务端自己嗅探(它有权拒 415);消费端不要自己编一个 `application/octet-stream`
436
+ * —— 编出来的类型会让服务端把本可识别的文件当二进制。 */
437
+ mimeType?: string;
438
+ bytes: Uint8Array;
439
+ }
440
+ export declare const ATTACHMENT_UPLOAD_REQUEST_KEYS: readonly ["name", "mimeType", "bytes"];
441
+ /** 只带会话 id 的入参(interrupt/stop 共用;REF-CC-074 同族,1 成员形也统一成具名)。 */
442
+ export interface SessionScopedRequest {
443
+ sessionId: string;
444
+ }
306
445
  /** `uploadAttachment` receipt — the SDK's `AttachmentInfo` verbatim (server POST /v1/attachments 201).
307
446
  * `name` is the SERVER's sanitized basename, not the local filename: it is the name the engine
308
447
  * materializes, so the renderer must display THAT one. */
@@ -317,15 +456,21 @@ export interface AttachmentUploadReceipt {
317
456
  * strips baseUrl/apiKey/headers). `contextWindow`/`maxOutputTokens` are soft-degrade extras. */
318
457
  export interface SeatModelInfo {
319
458
  id: string;
459
+ /** 展示名。缺席 = 部署没给展示名 ⇒ 渲染端显示 `id` 本身(不要显示空串)。 */
320
460
  name?: string;
461
+ /** 供应商名。缺席 = 部署没标供应商 ⇒ 不渲供应商标签,**不要**回落成 "unknown"。 */
321
462
  provider?: string;
463
+ /** 上下文窗口 token 数(statusline 的 Context 环分母)。缺席 = 引擎没报这个量 ⇒ 环渲不确定态,
464
+ * 绝不按某个猜测值算百分比([honest-absence-not-fabricated-zero])。 */
322
465
  contextWindow?: number;
466
+ /** 单次回复上限 token 数。缺席 = 引擎没报 ⇒ 不渲这一行。 */
323
467
  maxOutputTokens?: number;
324
468
  }
325
469
  /** `listModels` envelope. `defaultId` = the deployment's resolved default model id (display only —
326
470
  * the per-turn choice always rides `sendMessage({model})`). */
327
471
  export interface SeatModelCatalog {
328
472
  models: SeatModelInfo[];
473
+ /** 缺席 = 部署没有解析出默认模型 ⇒ 渲染端不要给「默认」打勾,也不要自己挑第一行冒充默认。 */
329
474
  defaultId?: string;
330
475
  }
331
476
  export interface SendMessageAck {
@@ -351,13 +496,17 @@ export interface ToolPermissionDecision {
351
496
  /** AskUserQuestion answer (approve only) — `{answers:[{header, selected: string[], note?}]}`,
352
497
  * keyed by the question's HEADER, `selected` echoing the EXACT option labels the user saw (core
353
498
  * fences `selected ⊆ options`). Malformed shapes are refused at the door, never coerced: a
354
- * silently emptied answer is the user's choice being thrown away without anyone noticing. */
355
- answer?: unknown;
499
+ * silently emptied answer is the user's choice being thrown away without anyone noticing.
500
+ * REF-CC-038(2026-08-02):typed as `QuestionAnswer`(hitlBridge's `AskAnswer` at the entry
501
+ * level) — this was `unknown` before, the 4th of 4 divergent copies of the same shape.
502
+ * 缺席 = 这不是 question 域的决断(或是 deny)⇒ 宿主发 wire 自己的 NO_HUMAN 形(REF-CC-066)。 */
503
+ answer?: QuestionAnswer;
356
504
  /** Approve-with-edit rewritten args (design/37 last-wins). On the `elicit:` domain this position
357
505
  * carries the submitted FORM CONTENT — a flat record of `string|number|boolean|string[]`
358
- * (the only shape the wire accepts; anything else is refused, not filtered). */
506
+ * (the only shape the wire accepts; anything else is refused, not filtered).
507
+ * 缺席 = 原样批准(不改参数);`elicit:` 域缺席 = 没有表单内容,宿主绝不代填。 */
359
508
  updatedInput?: unknown;
360
- /** "Don't ask again this session" (approve only). */
509
+ /** "Don't ask again this session" (approve only). 缺席 = 只批这一次。 */
361
510
  remember?: "session";
362
511
  }
363
512
  /** Renderer-side `$store$` client (CC form: read + subscribe; `update` channel is the push). */
@@ -368,33 +517,59 @@ export interface EipcStoreClient<T> {
368
517
  }
369
518
  export interface SettingsState {
370
519
  defaultModel: string | null;
520
+ /** 引擎版本串。缺席 = 宿主还没连上引擎(启动窗口)⇒ 渲染端渲「连接中」,不要渲空版本号。 */
371
521
  engineVersion?: string;
522
+ /** 引擎数据根目录。缺席 = 同上(还不知道)⇒ 不渲路径行,不要渲 "~" 之类的猜测值。 */
372
523
  dataRoot?: string;
373
524
  }
374
525
  export interface SessionSearchResult {
375
526
  sessionId: string;
527
+ /** 命中会话的标题。缺席 = 该会话没有标题 ⇒ 结果行渲「新会话」+ 片段,不要渲空标题行。 */
376
528
  title?: string;
377
529
  matches: Array<{
378
530
  snippet: string;
379
531
  }>;
380
532
  }
533
+ export declare const SESSION_SEARCH_RESULT_KEYS: readonly ["sessionId", "title", "matches"];
534
+ /** `searchSessions` 返回形(REF-CC-072:此前是 SPEC 里的内联匿名 validator 之一;
535
+ * 它从不校 `title` 那一半归 REF-CC-073,见 `SESSION_SEARCH_RESULT_KEYS`)。 */
536
+ export interface SessionSearchEnvelope {
537
+ results: SessionSearchResult[];
538
+ }
539
+ /** `getTranscript` 返回形(REF-CC-073:此前内联匿名、无 interface、无键集、无钉)。
540
+ * `messages` = transcript 面直通批(fQe 姿态:只校数组形,元素是 CC SDKMessage 体,刻意不校)。 */
541
+ export interface GetTranscriptResult {
542
+ sessionId: string;
543
+ messages: unknown[];
544
+ }
545
+ export declare const GET_TRANSCRIPT_RESULT_KEYS: readonly ["sessionId", "messages"];
546
+ /** interrupt 回执(CC form:true = 真打断了一轮在跑的 turn,false = 当时没有在跑的 turn)。 */
547
+ export interface InterruptAck {
548
+ interrupted: boolean;
549
+ }
550
+ /** stop 回执(false = 会话本来就不在跑,不是错误)。 */
551
+ export interface StopAck {
552
+ stopped: boolean;
553
+ }
554
+ /** 通用「收到了」回执(respondToToolPermission / setFocusedSession)。 */
555
+ export interface OkAck {
556
+ ok: boolean;
557
+ }
558
+ /** `sessionsState` store 的状态形。 */
559
+ export interface SessionsState {
560
+ sessions: LocalSessionRecord[];
561
+ }
562
+ /** `focusedSessionState` store 的状态形(`null` = 没有会话被聚焦,是一个真实状态不是缺席)。 */
563
+ export interface FocusedSessionState {
564
+ sessionId: string | null;
565
+ }
381
566
  /** Renderer-facing surface exposed by the mainView preload as `sema.web.LocalSessions`. */
382
567
  export interface LocalSessionsApi {
383
568
  start(opts?: StartSessionOptions): Promise<LocalSessionRecord>;
384
569
  sendMessage(req: SendMessageRequest): Promise<SendMessageAck>;
385
- interrupt(req: {
386
- sessionId: string;
387
- }): Promise<{
388
- interrupted: boolean;
389
- }>;
390
- stop(req: {
391
- sessionId: string;
392
- }): Promise<{
393
- stopped: boolean;
394
- }>;
395
- respondToToolPermission(req: ToolPermissionDecision): Promise<{
396
- ok: boolean;
397
- }>;
570
+ interrupt(req: SessionScopedRequest): Promise<InterruptAck>;
571
+ stop(req: SessionScopedRequest): Promise<StopAck>;
572
+ respondToToolPermission(req: ToolPermissionDecision): Promise<OkAck>;
398
573
  /** Queue family (CC LocalSessionManager semantics; booleans, false = too-late/no-op form). */
399
574
  cancelQueuedMessage(sessionId: string, userMessageUuid: string): Promise<boolean>;
400
575
  /** CC signature: (sessionId, uuid, TARGET uuid) — position the message relative to the target
@@ -402,58 +577,27 @@ export interface LocalSessionsApi {
402
577
  reorderQueuedMessage(sessionId: string, userMessageUuid: string, targetUserMessageUuid: string): Promise<boolean>;
403
578
  promoteQueuedMessage(sessionId: string, userMessageUuid: string): Promise<boolean>;
404
579
  /** CC census verbs (batch 4). setFocusedSession(null) clears focus. */
405
- setFocusedSession(sessionId: string | null): Promise<{
406
- ok: boolean;
407
- }>;
580
+ setFocusedSession(sessionId: string | null): Promise<OkAck>;
408
581
  setModel(sessionId: string, model: string): Promise<boolean>;
409
- getTranscript(sessionId: string): Promise<{
410
- sessionId: string;
411
- messages: unknown[];
412
- }>;
413
- searchSessions(query: string): Promise<{
414
- results: SessionSearchResult[];
415
- }>;
582
+ getTranscript(sessionId: string): Promise<GetTranscriptResult>;
583
+ searchSessions(query: string): Promise<SessionSearchEnvelope>;
416
584
  /** Attachment BYTE channel (红批注 web#1 的另一半). Upload first, then reference the receipt id
417
585
  * from `sendMessage({attachmentIds})`. Rejects (413/415/501 → thrown typed error) surface to the
418
586
  * renderer as-is: a shelf row that says "ready" for a file the engine never received is the
419
587
  * same lie as a mode badge that never crossed the wire. */
420
- uploadAttachment(req: {
421
- name: string;
422
- mimeType?: string;
423
- bytes: Uint8Array;
424
- }): Promise<AttachmentUploadReceipt>;
588
+ uploadAttachment(req: AttachmentUploadRequest): Promise<AttachmentUploadReceipt>;
425
589
  /** Read-only model catalog (engine `GET /v1/models`). Empty `models` = the deployment offers no
426
590
  * catalog; the renderer must degrade honestly rather than fall back to a fixture list. */
427
591
  listModels(): Promise<SeatModelCatalog>;
428
592
  onEvent(cb: (ev: LocalSessionEvent) => void): () => void;
429
593
  onToolPermissionRequest(cb: (req: ToolPermissionRequest) => void): () => void;
430
594
  /** `$store$` reactive states (read + subscribe; writes go through the verbs above). */
431
- sessionsStateStore: EipcStoreClient<{
432
- sessions: LocalSessionRecord[];
433
- }>;
434
- focusedSessionStateStore: EipcStoreClient<{
435
- sessionId: string | null;
436
- }>;
595
+ sessionsStateStore: EipcStoreClient<SessionsState>;
596
+ focusedSessionStateStore: EipcStoreClient<FocusedSessionState>;
437
597
  settingsStateStore: EipcStoreClient<SettingsState>;
438
598
  }
439
599
  export declare function isLocalSessionRecord(s: unknown): s is LocalSessionRecord;
440
600
  export declare function isToolPermissionRequest(r: unknown): r is ToolPermissionRequest;
441
- /**
442
- * onEvent payload validator — line-for-line FORM port of CC's `fQe`
443
- * (`.vite/build/index.chunk-CnWKsyE_.js:369773`). Field-by-field mapping:
444
- * - `type`/`sessionId`: required strings (same);
445
- * - `message`: CC's minified source reads `typeof e.message<"u"` inside a comma expression whose
446
- * value is discarded — i.e. NO validation, a deliberate transcript-plane passthrough. Same here.
447
- * - `messages`: array-checked, elements `every(t=>!0)` (constant true) — array shape only. Same here.
448
- * - `error`/`errorCategory`: optional strings (same); `code`: optional number (same);
449
- * - `request`: CC gates with `S1` (ToolPermissionRequest schema) → our isToolPermissionRequest;
450
- * - `session`: CC gates with `aM` (SessionRecord schema) → our isLocalSessionRecord;
451
- * - `data`: optional string / `sources`: optional string[] / `permissionMode`: optional string /
452
- * `userMessageUuid`: optional string / `hasPreClearSession`: optional boolean (same);
453
- * - CC fields we do not emit in this batch (`tccFolderKind`/`initializationStatus`/`fsFile`/
454
- * `localMcpServers`/`refusalFallbackPrompt`) are not carried — their positions return when the
455
- * corresponding service families are ported.
456
- */
457
601
  export declare function isLocalSessionEvent(v: unknown): v is LocalSessionEvent;
458
602
  export declare function isAttachmentUploadReceipt(v: unknown): v is AttachmentUploadReceipt;
459
603
  export declare function isSeatModelCatalog(v: unknown): v is SeatModelCatalog;
@@ -466,8 +610,150 @@ export declare const SEAT_STORE_PROPS: readonly ["sessionsStateStore", "focusedS
466
610
  /** 事件式(main→renderer push)的 verb —— SPEC 里 `kind: "event"` 的那一撮,门里逐元素对账。 */
467
611
  export declare const SEAT_EVENT_METHOD_NAMES: readonly ["onEvent", "onToolPermissionRequest"];
468
612
  export declare const LOCAL_SESSION_EVENT_KEYS: readonly ["type", "sessionId", "message", "messages", "error", "errorCategory", "code", "request", "data", "sources", "permissionMode", "session", "userMessageUuid", "hasPreClearSession", "requestId", "outcome", "chrome"];
469
- export declare const TOOL_PERMISSION_REQUEST_KEYS: readonly ["requestId", "sessionId", "toolName", "toolCallId", "input", "message", "boundCallId", "boundInputHash", "createdAt"];
613
+ export declare const TOOL_PERMISSION_REQUEST_KEYS: readonly ["requestId", "sessionId", "toolName", "toolCallId", "input", "message", "toctouBinding", "createdAtMs"];
470
614
  export declare const LOCAL_SESSION_RECORD_KEYS: readonly ["sessionId", "engineSessionId", "model", "title", "isRunning", "createdAt", "lastActivityAt", "queuedMessages"];
471
615
  export declare const SEND_MESSAGE_REQUEST_KEYS: readonly ["sessionId", "text", "model", "userMessageUuid", "permissionMode", "attachmentIds", "reasoningEffort", "retainBackgroundProcesses", "settings"];
472
616
  export declare const TOOL_PERMISSION_DECISION_KEYS: readonly ["sessionId", "requestId", "decision", "answer", "updatedInput", "remember"];
473
617
  export declare const START_SESSION_OPTION_KEYS: readonly ["model", "title", "cwd", "excludeTools"];
618
+ /**
619
+ * 校验器覆盖表(REF-CC-068)—— 每个校验器**逐键**声明:哪些位真被校验、哪些位**刻意**不校验。
620
+ *
621
+ * 为什么需要它:`防再漂钉` 封的是「interface ↔ 名字常量 ↔ SPEC」两跳,**校验器这条链此前没人钉**。
622
+ * 给一个 interface 加一个必填位,门全绿,而新位从此不过校验(fail-closed 面出现缺口)。
623
+ * 正确做法不是「全键必查」—— 本文件有真正**刻意不查**的位(transcript 面直通),所以豁免必须显式登记
624
+ * 并带理由。门里对每个位投毒:说校验的必拒、说豁免的必过 ⇒ 这张表不可能变成一段过期的说明文字。
625
+ *
626
+ * 🔴 覆盖范围(wave2 回炉批 2026-08-02 补齐,首版只登了 6 个而发包说明写的是「每个校验器」——
627
+ * 那 8 个没登的恰好就是 REF-CC-072 本批新提名的那批 `check*`,实测「加一个必填位、全门照绿」在它们
628
+ * 身上仍然全开,即这张表自称堵死的失效形当时并没有被堵死):
629
+ * · **SPEC 面 15 个具名 `check`,14 个对象形在本表登记**,余下 1 个(裸布尔回执)逐形豁免;
630
+ * · 另加 4 个**嵌套**形(SeatModelInfo / SessionSearchResult / ToctouBinding /
631
+ * SeatChromeEnvelopeBase)—— 它们不是 SPEC 面的直接 check,但父校验器的覆盖表只登记得到
632
+ * `models` / `results` / `toctouBinding` / `chrome` 这一个顶层键,给**子形**加必填位同样全绿;
633
+ * · 合计 **18 条**。两个不适用的形逐形写在 `SEAT_VALIDATOR_COVERAGE_EXEMPT` 里。
634
+ * 完备性不靠这段话:门里逐条比对 `LOCAL_SESSIONS_SPEC` 每个 method/store 的 `check` **函数引用**
635
+ * 必须落在「本表 ∪ 豁免表」里 —— 再加一条 verb 而不登记,门当场红。
636
+ *
637
+ * `check` 位存的是**函数引用本身**(不是名字):名字查表要靠一张 guards 映射,而那张映射漏一行
638
+ * 就是又一个没人看见的缺口;引用相等是机械的。`guard` 位只在该形另有公开面 `is*` 谓词时登记,
639
+ * 门里额外校「谓词与 check 判决一致」。
640
+ */
641
+ export declare const SEAT_VALIDATOR_KEY_COVERAGE: {
642
+ readonly LocalSessionRecord: {
643
+ readonly guard: "isLocalSessionRecord";
644
+ readonly check: (s: unknown) => SeatValidation;
645
+ readonly validated: readonly ["sessionId", "engineSessionId", "model", "title", "isRunning", "createdAt", "lastActivityAt", "queuedMessages"];
646
+ readonly unchecked: readonly [];
647
+ };
648
+ readonly ToolPermissionRequest: {
649
+ readonly guard: "isToolPermissionRequest";
650
+ readonly check: (r: unknown) => SeatValidation;
651
+ readonly validated: readonly ["requestId", "sessionId", "toolName", "toolCallId", "message", "toctouBinding", "createdAtMs"];
652
+ readonly unchecked: readonly [{
653
+ readonly key: "input";
654
+ readonly why: "UNTRUSTED service-redacted 工具参数 / 问题载荷:形状由工具自己定(CC request-args 姿态),渲染端只读不回喂;缺席/畸形的渲染义务写在字段注释里。";
655
+ }];
656
+ };
657
+ readonly LocalSessionEvent: {
658
+ readonly guard: "isLocalSessionEvent";
659
+ readonly check: (v: unknown) => SeatValidation;
660
+ readonly validated: readonly ["type", "sessionId", "messages", "error", "errorCategory", "code", "request", "data", "sources", "permissionMode", "session", "userMessageUuid", "hasPreClearSession", "requestId", "outcome", "chrome"];
661
+ readonly unchecked: readonly [{
662
+ readonly key: "message";
663
+ readonly why: "transcript 面直通位(CC fQe 逐字姿态:SDKMessage 体不做 schema 校验)—— 校它 = 引擎加一种消息体的那天整条转录被门吃掉。";
664
+ }];
665
+ };
666
+ readonly AttachmentUploadReceipt: {
667
+ readonly guard: "isAttachmentUploadReceipt";
668
+ readonly check: (v: unknown) => SeatValidation;
669
+ readonly validated: readonly ["id", "name", "mime", "sha256", "sizeBytes"];
670
+ readonly unchecked: readonly [];
671
+ };
672
+ readonly SeatModelCatalog: {
673
+ readonly guard: "isSeatModelCatalog";
674
+ readonly check: (v: unknown) => SeatValidation;
675
+ readonly validated: readonly ["models", "defaultId"];
676
+ readonly unchecked: readonly [];
677
+ };
678
+ readonly SendMessageAck: {
679
+ readonly guard: "isSendMessageAck";
680
+ readonly check: (v: unknown) => SeatValidation;
681
+ readonly validated: readonly ["sessionId", "userMessageUuid", "queued"];
682
+ readonly unchecked: readonly [];
683
+ };
684
+ readonly InterruptAck: {
685
+ readonly check: (v: unknown) => SeatValidation;
686
+ readonly validated: readonly ["interrupted"];
687
+ readonly unchecked: readonly [];
688
+ };
689
+ readonly StopAck: {
690
+ readonly check: (v: unknown) => SeatValidation;
691
+ readonly validated: readonly ["stopped"];
692
+ readonly unchecked: readonly [];
693
+ };
694
+ readonly OkAck: {
695
+ readonly check: (v: unknown) => SeatValidation;
696
+ readonly validated: readonly ["ok"];
697
+ readonly unchecked: readonly [];
698
+ };
699
+ readonly GetTranscriptResult: {
700
+ readonly check: (v: unknown) => SeatValidation;
701
+ readonly validated: readonly ["sessionId", "messages"];
702
+ readonly unchecked: readonly [];
703
+ };
704
+ readonly SessionSearchEnvelope: {
705
+ readonly check: (v: unknown) => SeatValidation;
706
+ readonly validated: readonly ["results"];
707
+ readonly unchecked: readonly [];
708
+ };
709
+ readonly SessionsState: {
710
+ readonly check: (v: unknown) => SeatValidation;
711
+ readonly validated: readonly ["sessions"];
712
+ readonly unchecked: readonly [];
713
+ };
714
+ readonly FocusedSessionState: {
715
+ readonly check: (v: unknown) => SeatValidation;
716
+ readonly validated: readonly ["sessionId"];
717
+ readonly unchecked: readonly [];
718
+ };
719
+ readonly SettingsState: {
720
+ readonly check: (v: unknown) => SeatValidation;
721
+ readonly validated: readonly ["defaultModel", "engineVersion", "dataRoot"];
722
+ readonly unchecked: readonly [];
723
+ };
724
+ readonly SeatModelInfo: {
725
+ readonly check: (v: unknown) => SeatValidation;
726
+ readonly validated: readonly ["id", "name", "provider", "contextWindow", "maxOutputTokens"];
727
+ readonly unchecked: readonly [];
728
+ };
729
+ readonly SessionSearchResult: {
730
+ readonly check: (v: unknown) => SeatValidation;
731
+ readonly validated: readonly ["sessionId", "title", "matches"];
732
+ readonly unchecked: readonly [];
733
+ };
734
+ readonly ToctouBinding: {
735
+ readonly check: (v: unknown) => SeatValidation;
736
+ readonly validated: readonly ["callId", "inputHash"];
737
+ readonly unchecked: readonly [];
738
+ };
739
+ readonly SeatChromeEnvelopeBase: {
740
+ readonly check: (v: unknown) => SeatValidation;
741
+ readonly validated: readonly ["kind", "laneProof"];
742
+ readonly unchecked: readonly [];
743
+ };
744
+ };
745
+ /**
746
+ * 逐形豁免(REF-CC-068 的另一半):**不适用**覆盖表的具名校验器 —— 每条写清为什么,以及它的判别力
747
+ * 由谁承担。这张表存在的唯一理由是让「本表 ∪ 覆盖表 ⊇ SPEC 面全部 check」这条完备性钉能机械成立:
748
+ * 没有它,「某个 check 没登记」和「某个 check 不该登记」在门里长得一模一样。
749
+ */
750
+ export declare const SEAT_VALIDATOR_COVERAGE_EXEMPT: readonly [{
751
+ readonly label: "BooleanAck";
752
+ readonly check: (v: unknown) => SeatValidation;
753
+ readonly why: "载荷是**裸布尔**(queue 三件 + setModel 的 CC 形回执,false = too-late/no-op),没有键面 ⇒ `keyof` 覆盖表在它身上无从谈起。判别力由 J 段承担:认 true/false、拒非布尔(对象 / 字符串 'true' / null / undefined 四形逐一投毒)。";
754
+ }, {
755
+ readonly label: "LaneProof";
756
+ readonly check: (v: unknown) => SeatValidation;
757
+ readonly why: "判别式联合:必填键面随 `lane` 臂而变(subagent 要 parentToolCallId、workflow 要 via+key),而覆盖表的方法是「一个最小合法体 + 逐键投毒」—— 那套方法在它身上没有判别力(main 臂对另外两臂的伴随位本来就不该拒,投毒过了不代表漏校)。判别力由 `LANE_PROOF_LANE_TUPLE` ⇄ seam.ts 车道联合的双向 `Covers` + F 段逐臂投毒(空对象 / 非对象 / 未登记车道词)承担。";
758
+ }];
759
+ export {};