@sema-agent/client-core 0.40.0 → 0.42.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 (36) hide show
  1. package/CHANGELOG.md +450 -0
  2. package/README.md +1 -1
  3. package/dist/adapter/downstream/eventToSdkMessage.js +24 -0
  4. package/dist/attachmentsWireCaps.d.ts +43 -8
  5. package/dist/attachmentsWireCaps.js +64 -14
  6. package/dist/classifierVerdictWire.d.ts +0 -25
  7. package/dist/classifierVerdictWire.js +27 -7
  8. package/dist/engineAgentPanelStore.js +102 -13
  9. package/dist/hitl/approvalsFeed.d.ts +2 -2
  10. package/dist/hitl/approvalsFeed.js +57 -2
  11. package/dist/hitl/askGateWire.d.ts +4 -2
  12. package/dist/hitl/askGateWire.js +2 -0
  13. package/dist/hitl/editedRuleTextPrecheck.d.ts +102 -0
  14. package/dist/hitl/editedRuleTextPrecheck.js +91 -0
  15. package/dist/hitl/frameRouter.d.ts +21 -2
  16. package/dist/hitl/frameRouter.js +114 -12
  17. package/dist/hitl/gateLedger.d.ts +27 -0
  18. package/dist/hitl/gateLedger.js +64 -9
  19. package/dist/hitl/hitlBridge.d.ts +70 -14
  20. package/dist/hitl/hitlBridge.js +117 -34
  21. package/dist/hitl/hitlHostSurface.d.ts +33 -3
  22. package/dist/hitl/hitlHostSurface.js +33 -3
  23. package/dist/hitl/parkResolver.js +39 -13
  24. package/dist/hitl/toolApprovalWire.d.ts +133 -3
  25. package/dist/hitl/toolApprovalWire.js +143 -6
  26. package/dist/index.d.ts +1 -0
  27. package/dist/index.js +7 -0
  28. package/dist/model/catalogLoader.js +151 -45
  29. package/dist/printToolResultFrame.d.ts +19 -0
  30. package/dist/seatContract.d.ts +25 -1
  31. package/dist/seatContract.js +29 -2
  32. package/dist/subagent/engineDelegatedPrompt.js +10 -3
  33. package/dist/systemReminderTag.d.ts +52 -0
  34. package/dist/systemReminderTag.js +73 -0
  35. package/docs/INTEGRATION-CLIENTS.md +123 -7
  36. package/package.json +2 -2
@@ -86,6 +86,25 @@ export interface ToolEndResultArmLike {
86
86
  settledBy?: unknown;
87
87
  /** 见 {@link settledBy} —— 两键同批同源(#263 半场,0.30.8),合读、缺席不反推、转录不是认证。 */
88
88
  approver?: unknown;
89
+ /**
90
+ * 这次 deny **是哪一条拒绝臂**(core ≥5.35 `AskDenyResolution`;A-D2 半场,0.42.0)——
91
+ * `human_refused` / `window_expired` / `no_approver` / `blanket_allow_refused` /
92
+ * `approver_unavailable` / `task_aborted` / `presentation_failed` / `approver_error` /
93
+ * `approver_contract`。
94
+ *
95
+ * 🔴 与 {@link settledBy} **合读而不互替**:settledBy 只说「这次等待是哪一**种**收场」,本位
96
+ * 分类的是**拒绝臂本身**。单锚 settledBy 会把「审批方违约」(approver 回了契约外的东西)
97
+ * 那一臂一起误收进「窗口走完了」。
98
+ * 🔴 **判据用正面匹配,不用「不等于」**(异源复审 [medium] 采纳,0.42.0):要判「审批窗口自己
99
+ * 走完了」,写 `settledBy === 'timeout' && resolution === 'window_expired'`。
100
+ * **绝不**写 `resolution !== 'approver_contract'` —— 那个不等式对**缺席**(旧引擎不发这一位)和
101
+ * 对**任何未来新码**都为真,于是「不知道是怎么拒的」会被折成「窗口自然结束」,正是本位存在要防的
102
+ * 那件事;两条正交轴在那种写法里被一个否定比较替代掉了。缺席与未知值一律进 `default` 分支。
103
+ * 🔴 **缺席不带语义,不许反推**:每一次真执行了的调用、每一次 policy/hook 直拒、以及
104
+ * durable/decide 腿的结算都不带这一位;缺席 ≠「不是拒绝」也 ≠「人拒的」。
105
+ * 🔴 本形同样是**防御性读形**(`unknown`):九词是引擎的闭集,消费方分支已知值 + 永远带 default。
106
+ */
107
+ resolution?: unknown;
89
108
  parentToolCallId?: unknown;
90
109
  uuid?: unknown;
91
110
  session_id?: unknown;
@@ -64,8 +64,32 @@
64
64
  * method exists (`start`/`stop`/`interrupt`/`sendMessage`/`onEvent`/`onToolPermissionRequest`/
65
65
  * `respondToToolPermission` are all real CC LocalSessions methods — see the 854-channel census).
66
66
  *
67
+ * ══ 🔴 证据等级标注:本文件的 CC 断言取自**桌面 unpack**,本地语料库不可复验 ════════════════
68
+ *
69
+ * (test [5087] 提出的「语料**种类**缺口」,cli [5088] 认领三件之①,随 0.42.0 落;判据形见下)
70
+ *
71
+ * 本文件里所有以「CC 如何如何」为形的断言 —— 上面那句「212 methods / 854-channel census /
72
+ * 方法名逐字保留」、下面 `checkLocalSessionEvent` 的「CC 的 `fQe` 逐字段对照」、以及一切引
73
+ * `.vite/build/index.chunk-*.js` 坐标的句子 —— **证据等级 = 桌面 unpack(CC Electron app 的
74
+ * `.vite/build` 产物),本地语料库不可复验**。
75
+ *
76
+ * 为什么这一条必须写在这里(而不是只写进台账):
77
+ * · 本仓手边可复验的参照语料**只覆盖终端 CLI 形态**的静态产物,**没有**桌面壳的 unpack 产物。
78
+ * 这不是「语料版本旧」,是**产物形态不对** —— 拿 CLI 形态的语料去 grep 桌面壳里的符号只会得到
79
+ * 零命中,而零命中在这里**既不能证真也不能证伪**;
80
+ * · 「CC 取证纪律」要求 CC 断言的合法证据只有两种:本机 claude 实测,或语料二进制直证。本文件
81
+ * 的这一批两种都够不着 ⇒ 断言**保留**(它当初是照着真产物写的),但**必须带着这个等级一起读**;
82
+ * · 🔴 **这段注释随 `dist/*.d.ts` 出包**,三端读到的就是它。只把等级写进不进 tarball 的台账,
83
+ * 消费端读到的仍是一句看起来可复验、实际不可复验的断言(与本文件 `workerBadge` 出身订正
84
+ * 同一条理由)。
85
+ *
86
+ * **对下游的判据**:凡要对这些断言做「CC 到底是不是这样」的复核,**别拿终端 CLI 形态的语料当反证**
87
+ * ——零命中是语料形态缺口的必然结果,不是断言错。真正的复核路只有一条:取一份 CC 桌面版
88
+ * unpack 产物再对照(已在册为独立小件,做成后参照语料库增桌面形态子目录)。
89
+ *
67
90
  * Event payload contract: ported in FORM from CC's `onEvent` runtime validator `fQe`
68
- * (unpack `.vite/build/index.chunk-CnWKsyE_.js:369773`). The load-bearing property we keep
91
+ * (unpack `.vite/build/index.chunk-CnWKsyE_.js:369773`;**证据等级:桌面 unpack,本地语料库
92
+ * 不可复验** —— 见上方标注段). The load-bearing property we keep
69
93
  * byte-faithful ([1832] axiom 2, independently proven by CC's own code): on an otherwise
70
94
  * fully-schema'd IPC surface, the `message`/`messages` fields (= CC session-vocabulary SDKMessage
71
95
  * bodies, our transcript plane) are UNVALIDATED passthrough positions, while every other field is a
@@ -64,8 +64,32 @@
64
64
  * method exists (`start`/`stop`/`interrupt`/`sendMessage`/`onEvent`/`onToolPermissionRequest`/
65
65
  * `respondToToolPermission` are all real CC LocalSessions methods — see the 854-channel census).
66
66
  *
67
+ * ══ 🔴 证据等级标注:本文件的 CC 断言取自**桌面 unpack**,本地语料库不可复验 ════════════════
68
+ *
69
+ * (test [5087] 提出的「语料**种类**缺口」,cli [5088] 认领三件之①,随 0.42.0 落;判据形见下)
70
+ *
71
+ * 本文件里所有以「CC 如何如何」为形的断言 —— 上面那句「212 methods / 854-channel census /
72
+ * 方法名逐字保留」、下面 `checkLocalSessionEvent` 的「CC 的 `fQe` 逐字段对照」、以及一切引
73
+ * `.vite/build/index.chunk-*.js` 坐标的句子 —— **证据等级 = 桌面 unpack(CC Electron app 的
74
+ * `.vite/build` 产物),本地语料库不可复验**。
75
+ *
76
+ * 为什么这一条必须写在这里(而不是只写进台账):
77
+ * · 本仓手边可复验的参照语料**只覆盖终端 CLI 形态**的静态产物,**没有**桌面壳的 unpack 产物。
78
+ * 这不是「语料版本旧」,是**产物形态不对** —— 拿 CLI 形态的语料去 grep 桌面壳里的符号只会得到
79
+ * 零命中,而零命中在这里**既不能证真也不能证伪**;
80
+ * · 「CC 取证纪律」要求 CC 断言的合法证据只有两种:本机 claude 实测,或语料二进制直证。本文件
81
+ * 的这一批两种都够不着 ⇒ 断言**保留**(它当初是照着真产物写的),但**必须带着这个等级一起读**;
82
+ * · 🔴 **这段注释随 `dist/*.d.ts` 出包**,三端读到的就是它。只把等级写进不进 tarball 的台账,
83
+ * 消费端读到的仍是一句看起来可复验、实际不可复验的断言(与本文件 `workerBadge` 出身订正
84
+ * 同一条理由)。
85
+ *
86
+ * **对下游的判据**:凡要对这些断言做「CC 到底是不是这样」的复核,**别拿终端 CLI 形态的语料当反证**
87
+ * ——零命中是语料形态缺口的必然结果,不是断言错。真正的复核路只有一条:取一份 CC 桌面版
88
+ * unpack 产物再对照(已在册为独立小件,做成后参照语料库增桌面形态子目录)。
89
+ *
67
90
  * Event payload contract: ported in FORM from CC's `onEvent` runtime validator `fQe`
68
- * (unpack `.vite/build/index.chunk-CnWKsyE_.js:369773`). The load-bearing property we keep
91
+ * (unpack `.vite/build/index.chunk-CnWKsyE_.js:369773`;**证据等级:桌面 unpack,本地语料库
92
+ * 不可复验** —— 见上方标注段). The load-bearing property we keep
69
93
  * byte-faithful ([1832] axiom 2, independently proven by CC's own code): on an otherwise
70
94
  * fully-schema'd IPC surface, the `message`/`messages` fields (= CC session-vocabulary SDKMessage
71
95
  * bodies, our transcript plane) are UNVALIDATED passthrough positions, while every other field is a
@@ -370,7 +394,10 @@ const checkSeatChromeEnvelope = (v, field) => {
370
394
  };
371
395
  /**
372
396
  * onEvent payload validator — line-for-line FORM port of CC's `fQe`
373
- * (`.vite/build/index.chunk-CnWKsyE_.js:369773`). Field-by-field mapping:
397
+ * (`.vite/build/index.chunk-CnWKsyE_.js:369773`)
398
+ * 🔴 **证据等级:桌面 unpack,本地语料库不可复验**(0.42.0 标注件,判据与复核路见文件头注的
399
+ * 「证据等级标注」段;下面每一条 `CC …` 对照句都受该等级约束)。
400
+ * Field-by-field mapping:
374
401
  * - `type`/`sessionId`: required strings (same);`type` 另加闭集成员校验(REF-CC-065,词由本宿主铸);
375
402
  * - `message`: CC's minified source reads `typeof e.message<"u"` inside a comma expression whose
376
403
  * value is discarded — i.e. NO validation, a deliberate transcript-plane passthrough. Same here.
@@ -44,6 +44,7 @@
44
44
  * 绝不用「子代的首条输出」或行描述冒充委派 prompt(那是把一个看起来合理的错答案摆上屏)。
45
45
  * 一切失败 fail-soft,绝不 throw。
46
46
  */
47
+ import { stripSystemReminderBlocks } from '../systemReminderTag.js';
47
48
  import { hostLog } from '../host.js';
48
49
  import { makeEngineWireClient } from '../engineWireSdk.js';
49
50
  import { engineWireTarget } from '../engineWireTarget.js';
@@ -139,10 +140,16 @@ export function delegatedPromptText(content) {
139
140
  *
140
141
  * 信封是**成对标签**,所以用配对正则整段剥;不配对(被截断等)时保守不动,宁可多渲也不吃掉正文。
141
142
  */
142
- const PROMPT_ENVELOPE_TAGS = ['system-reminder', 'fork-boilerplate'];
143
+ // 🔴 件⑦([4974],2026-08-22):`system-reminder` 的**开标签带属性**(core ≥5.46 恒带
144
+ // `mark="<22 位 base64url>"`),精确形 `<system-reminder>` 整段剥不掉 ⇒ 上面那条 2026-08-01
145
+ // 修过的 bug 原样复发(详情页 Prompt 又变回技能清单)。剥壳口径收进包内单一闸口
146
+ // `systemReminderTag`(同根因的另一座位是 `classifierVerdictWire`,见该模块头注)。
147
+ // `fork-boilerplate` 是 core `agents/subagent.js` 里的**裸**标签(dist 直证),保持精确形 ——
148
+ // 没有属性的标签不需要属性容忍,给它加 = 给伪造面白让一寸。
149
+ const PROMPT_ENVELOPE_EXACT_TAGS = ['fork-boilerplate'];
143
150
  function stripEnvelopes(raw) {
144
- let text = raw;
145
- for (const tag of PROMPT_ENVELOPE_TAGS) {
151
+ let text = stripSystemReminderBlocks(raw);
152
+ for (const tag of PROMPT_ENVELOPE_EXACT_TAGS) {
146
153
  text = text.replace(new RegExp(`<${tag}>[\\s\\S]*?</${tag}>`, 'g'), '');
147
154
  }
148
155
  return text.trim() || undefined;
@@ -0,0 +1,52 @@
1
+ /**
2
+ * systemReminderTag — `<system-reminder>` 包裹的**单一识别闸口**(件⑥⑦,2026-08-22,[4974])。
3
+ *
4
+ * ## 为什么要有这个文件
5
+ *
6
+ * core ≥5.46 起,引擎铸的每一个 `<system-reminder>` **开标签**都带一个 `mark` 属性。真字节直证
7
+ * (core 5.52.0 `dist/core/reminder-mint.js`,逐行):
8
+ * ```js
9
+ * const MARK_SHAPE = /^[A-Za-z0-9_-]{22}$/ // randomBytes(16).toString("base64url")
10
+ * export function openSystemReminder(mark) {
11
+ * return mark === undefined ? "<system-reminder>" : `<system-reminder mark="${mark}">`
12
+ * }
13
+ * export function mintSystemReminder(body, mark) {
14
+ * return `${openSystemReminder(mark)}\n${body}\n</system-reminder>`
15
+ * }
16
+ * ```
17
+ * 闭标签**没有**属性,只有开标签变了。而包内两处判定当时都锚着**裸开标签**,于是同一个根因
18
+ * 长出两个座位([4974] 双 CONFIRMED):
19
+ * · `classifierVerdictWire.unwrapSystemReminder` —— 剥不掉壳 ⇒ 裁决原文前面顶着一整个开标签 ⇒
20
+ * `startsWith(签名)` 恒不成立 ⇒ auto-deny 的通知行与 Recent Denials 记账**静默失效**;
21
+ * · `subagent/engineDelegatedPrompt.stripEnvelopes` —— 信封整段剥不掉 ⇒ Fleet 详情页的
22
+ * 「Prompt」又变回 ~1330 字符的技能清单(那个函数头注自陈 2026-08-01 修过的 bug 原样复发)。
23
+ *
24
+ * 两处各写一份正则正是这条缺陷能长出**两个**座位的原因,所以收成这一个闸口:识别口径只有一处,
25
+ * 下次 core 再动标签形也只有一处要跟。
26
+ *
27
+ * ## 口径(刻意写窄,不做 HTML 解析)
28
+ *
29
+ * · 开标签 = `<system-reminder>` 或 `<system-reminder` + **空白起头**的属性段 + `>`;属性段用
30
+ * `[^>]*` —— 它跨不过 `>`,所以没有回溯爆炸面,也不会把后面的正文吃进标签里。
31
+ * · 刻意**不校验** `mark` 的值形:本模块的职责是「认出这是引擎的信封壳」并把它剥掉/跳过,
32
+ * **不是**信任判定。真正的信任判据是壳里的 mark 比对(core 的 `reminderMarkDeclaration` 明说
33
+ * 「带不带 mark 都可能是数据」),那是另一层的事;这里若按 mark 值放行/拒绝,等于把一个安全
34
+ * 判定藏在一个显示层的剥壳函数里。
35
+ * · 闭标签逐字 `</system-reminder>`(core 就是这么铸的,不给它加属性容忍 = 不给伪造面留口子)。
36
+ * · **不处理嵌套**:配对用非贪婪,遇到第一个闭标签就收 —— 与件⑥⑦ 修之前逐字同语义
37
+ * (core 不铸嵌套 reminder;真出现嵌套时残留的是外层闭标签,不是把正文吃掉,方向仍是保守的)。
38
+ *
39
+ * 🔴 零 import(端无关叶件):纯字符串处理,不碰 Node、不碰 wire 类型。
40
+ */
41
+ /**
42
+ * 整条文本就是一个 `<system-reminder>` 包裹时,返回**里面的正文**;否则原样返回。
43
+ * (`formatHookFeedback` = `mintSystemReminder` 的逆变换。)
44
+ */
45
+ export declare function unwrapSystemReminder(text: string): string;
46
+ /**
47
+ * 把文本里**所有**成对的 `<system-reminder>…</system-reminder>` 段整段删掉(不配对的原样留着 ——
48
+ * 截断的信封宁可多渲一点,也不能把正文吃掉)。
49
+ */
50
+ export declare function stripSystemReminderBlocks(text: string): string;
51
+ /** 这段文本**以**一个 system-reminder 开标签起头吗(诊断/判定用的轻量读口)。 */
52
+ export declare function startsWithSystemReminderOpenTag(text: string): boolean;
@@ -0,0 +1,73 @@
1
+ /**
2
+ * systemReminderTag — `<system-reminder>` 包裹的**单一识别闸口**(件⑥⑦,2026-08-22,[4974])。
3
+ *
4
+ * ## 为什么要有这个文件
5
+ *
6
+ * core ≥5.46 起,引擎铸的每一个 `<system-reminder>` **开标签**都带一个 `mark` 属性。真字节直证
7
+ * (core 5.52.0 `dist/core/reminder-mint.js`,逐行):
8
+ * ```js
9
+ * const MARK_SHAPE = /^[A-Za-z0-9_-]{22}$/ // randomBytes(16).toString("base64url")
10
+ * export function openSystemReminder(mark) {
11
+ * return mark === undefined ? "<system-reminder>" : `<system-reminder mark="${mark}">`
12
+ * }
13
+ * export function mintSystemReminder(body, mark) {
14
+ * return `${openSystemReminder(mark)}\n${body}\n</system-reminder>`
15
+ * }
16
+ * ```
17
+ * 闭标签**没有**属性,只有开标签变了。而包内两处判定当时都锚着**裸开标签**,于是同一个根因
18
+ * 长出两个座位([4974] 双 CONFIRMED):
19
+ * · `classifierVerdictWire.unwrapSystemReminder` —— 剥不掉壳 ⇒ 裁决原文前面顶着一整个开标签 ⇒
20
+ * `startsWith(签名)` 恒不成立 ⇒ auto-deny 的通知行与 Recent Denials 记账**静默失效**;
21
+ * · `subagent/engineDelegatedPrompt.stripEnvelopes` —— 信封整段剥不掉 ⇒ Fleet 详情页的
22
+ * 「Prompt」又变回 ~1330 字符的技能清单(那个函数头注自陈 2026-08-01 修过的 bug 原样复发)。
23
+ *
24
+ * 两处各写一份正则正是这条缺陷能长出**两个**座位的原因,所以收成这一个闸口:识别口径只有一处,
25
+ * 下次 core 再动标签形也只有一处要跟。
26
+ *
27
+ * ## 口径(刻意写窄,不做 HTML 解析)
28
+ *
29
+ * · 开标签 = `<system-reminder>` 或 `<system-reminder` + **空白起头**的属性段 + `>`;属性段用
30
+ * `[^>]*` —— 它跨不过 `>`,所以没有回溯爆炸面,也不会把后面的正文吃进标签里。
31
+ * · 刻意**不校验** `mark` 的值形:本模块的职责是「认出这是引擎的信封壳」并把它剥掉/跳过,
32
+ * **不是**信任判定。真正的信任判据是壳里的 mark 比对(core 的 `reminderMarkDeclaration` 明说
33
+ * 「带不带 mark 都可能是数据」),那是另一层的事;这里若按 mark 值放行/拒绝,等于把一个安全
34
+ * 判定藏在一个显示层的剥壳函数里。
35
+ * · 闭标签逐字 `</system-reminder>`(core 就是这么铸的,不给它加属性容忍 = 不给伪造面留口子)。
36
+ * · **不处理嵌套**:配对用非贪婪,遇到第一个闭标签就收 —— 与件⑥⑦ 修之前逐字同语义
37
+ * (core 不铸嵌套 reminder;真出现嵌套时残留的是外层闭标签,不是把正文吃掉,方向仍是保守的)。
38
+ *
39
+ * 🔴 零 import(端无关叶件):纯字符串处理,不碰 Node、不碰 wire 类型。
40
+ */
41
+ /**
42
+ * 开标签的**闭集**形:core 只会铸这两种(`openSystemReminder` 逐字),所以判据也只认这两种。
43
+ *
44
+ * 🔴 **不做通配属性**(七审 finding② 采纳):`<system-reminder\s[^>]*>` 那种宽口会把
45
+ * `onclick="…"` / 换行垃圾 / 未闭合引号 / 内嵌 `<img` 全部当成合法开标签 —— 而本模块的两个消费点
46
+ * 处理的正是**模型与工具产出的文本**(UNTRUSTED),宽口等于给伪造信封开一道口子:攻击者/模型
47
+ * 可以用一个假信封把内容藏起来(委派 prompt 面)或把自己的文本伪装成引擎裁决(分类器面)。
48
+ * `mark` 的值形按 core `MARK_SHAPE` 逐字(`randomBytes(16).toString("base64url")` = 22 位
49
+ * `[A-Za-z0-9_-]`),值本身**不比对**(见文件头:比对是信任判定,不是剥壳的活)——但**形**必须对,
50
+ * 形不对的一律不是引擎铸的壳。
51
+ */
52
+ const OPEN_TAG_SOURCE = '<system-reminder(?: mark="[A-Za-z0-9_-]{22}")?>';
53
+ /** 整段配对(开标签 + 正文 + 闭标签)。捕获组 1 = 正文。 */
54
+ const WRAPPED_RE = new RegExp(`^\\s*${OPEN_TAG_SOURCE}\\s*\\n?([\\s\\S]*?)\\n?\\s*<\\/system-reminder>\\s*$`);
55
+ /**
56
+ * 整条文本就是一个 `<system-reminder>` 包裹时,返回**里面的正文**;否则原样返回。
57
+ * (`formatHookFeedback` = `mintSystemReminder` 的逆变换。)
58
+ */
59
+ export function unwrapSystemReminder(text) {
60
+ const m = WRAPPED_RE.exec(text);
61
+ return m ? m[1] : text;
62
+ }
63
+ /**
64
+ * 把文本里**所有**成对的 `<system-reminder>…</system-reminder>` 段整段删掉(不配对的原样留着 ——
65
+ * 截断的信封宁可多渲一点,也不能把正文吃掉)。
66
+ */
67
+ export function stripSystemReminderBlocks(text) {
68
+ return text.replace(new RegExp(`${OPEN_TAG_SOURCE}[\\s\\S]*?<\\/system-reminder>`, 'g'), '');
69
+ }
70
+ /** 这段文本**以**一个 system-reminder 开标签起头吗(诊断/判定用的轻量读口)。 */
71
+ export function startsWithSystemReminderOpenTag(text) {
72
+ return new RegExp(`^\\s*${OPEN_TAG_SOURCE}`).test(text);
73
+ }
@@ -23,7 +23,7 @@
23
23
  | peer:wire 契约 | `@sema-agent/sdk` **>=7.2.0**(value-level,非 type-only) | `package.json` `peerDependencies` |
24
24
  | peer:会话词汇表 | `@sema-agent/agent-types` **>=0.2.0**(type-only,零运行时) | 同上 |
25
25
  | runtime dep | `diff` ^9.0.0(**唯一**一条;portability 门按**等值**钉死) | `package.json` `dependencies` |
26
- | 公开导出面 | **767** 个运行期符号(+ 39 个测试钩;= 未发 `0.40.0` 的值,npm `0.39.0` 是 **766**,`0.38.0` 是 **764**;`0.37.0` 是 **753**,见 `CHANGELOG.md`) | `scripts/public-export-baseline.json` 的 `count` / `testHookCount` —— **别手抄进别处,以该文件为准** |
26
+ | 公开导出面 | **771** 个运行期符号(+ 40 个测试钩;= 未发 `0.42.0` 的值,npm `0.41.0` 是 **767**,`0.39.0` 是 **766**,`0.38.0` 是 **764**;`0.37.0` 是 **753**,见 `CHANGELOG.md`) | `scripts/public-export-baseline.json` 的 `count` / `testHookCount` —— **别手抄进别处,以该文件为准** |
27
27
  | 常驻门 | 以 `scripts/gates-manifest.json` 的 `suites` 长度为准(**本档不抄这个数**) | `scripts/gates-manifest.json`;`npm test` 的名单等值门与它逐名对账 |
28
28
  | 沿革档 | 0.29.0 起建 `CHANGELOG.md`;更早批次记账在 `src/index.ts` 文件头 + `docs/REFACTOR-LEDGER.md` | — |
29
29
 
@@ -101,7 +101,7 @@ SDK 核对「本包 import 的每个值级符号仍然导出」「`TaskStats.cos
101
101
 
102
102
  ## §2 公共导出面地图(按域)
103
103
 
104
- > 全集真源 = `scripts/public-export-baseline.json` 的 `names`(**767** 项)。
104
+ > 全集真源 = `scripts/public-export-baseline.json` 的 `names`(**771** 项)。
105
105
  > 本节**不逐名抄**,只给「域 → 承重导出 → 用途 → 实现锚」。承重导出 = 一个端为了让这个域干活
106
106
  > **必须**直接调到的那几个符号;其余是它们的类型、变体与辅助位。
107
107
  > 单一入口:`import { … } from '@sema-agent/client-core'`(`exports` 只有 `.` 一个;
@@ -111,7 +111,7 @@ SDK 核对「本包 import 的每个值级符号仍然导出」「`TaskStats.cos
111
111
 
112
112
  `public-export-baseline.json` 由 **`dist/index.js` 的运行期导出**生成(生成口径自述见
113
113
  `scripts/run-client-core-typeshape-test.mjs`,双向精确集合门在 `scripts/run-public-surface-test.mjs`)。
114
- 实测:767 项 **100% 是运行期导出,零 type-only**。
114
+ 实测:771 项 **100% 是运行期导出,零 type-only**。
115
115
 
116
116
  **推论(端必须知道)**:
117
117
  - barrel 导出的**类型**面比 707 大得多,且**不被这道门看守** —— `AdapterContext` / `SeamEvent` /
@@ -120,18 +120,18 @@ SDK 核对「本包 import 的每个值级符号仍然导出」「`TaskStats.cos
120
120
  端依赖这些类型是合法的,但**不要**拿基线 diff 当"类型面没变"的证据。
121
121
  - `src/agentSession/contract.ts` 对基线贡献 **0** 项(纯类型模块,`export *` 在 dist 里是空转发)。
122
122
 
123
- 767 项的内部构成(帮助端估读表大小):**227** 项是 `SCREAMING_SNAKE` 常量数据表/词汇表
123
+ 771 项的内部构成(帮助端估读表大小):**227** 项是 `SCREAMING_SNAKE` 常量数据表/词汇表
124
124
  (矩阵、键集、env 名、锚串)而非可调用物;**5** 项是 PascalCase 运行期值
125
125
  (`ControlRouter` / `ControlSafetyError` / `HitlBridge` / `HitlSafetyError` / `DecideTransportRetryExhaustedError`);
126
126
  **39** 项是 `*For(sessionKey, …)` 的 per-session 变体(§6;其中 `engineNamespaceKeyFor` 是命名巧合 —— 参数是 baseUrl 不是 sessionKey,见域 14)。
127
127
 
128
- ### 2b. 域图(16 域,逐域计数之和 = 767)
128
+ ### 2b. 域图(16 域,逐域计数之和 = 771)
129
129
 
130
130
  | # | 域 | 名数 | 承重导出 | 用途 | 实现锚 |
131
131
  |---|---|---|---|---|---|
132
132
  | 1 | **适配内核(下行主链)** | 33 | `adapt` · `createWireToCcAdapter` · `runStream` · `eventToSdkMessage` · `terminalToSdkResult` · `turnUsageToModelUsage` · `isRunStreamActive` · `ADAPTER_DIVERGENCES` | 引擎 SSE `AgentEvent` → 端要渲的**双面输出**:transcript(`SDKMessage`)+ chrome(瞬态 `ChromeEvent`)。**本包存在的理由** | `src/adapt.ts`、`src/adapt/{arms,wireShapes,panelTasks}.ts`(经 `adapt.ts` 再导出)、`src/adapter/runStream.ts`、`src/adapter/downstream/*`、`src/adapter/types.ts` |
133
133
  | 2 | **seam 公共契约** | 2(其余为 type-only) | `CHROME_ARMS` · `deriveTranscriptId` | 公共词汇 + **id 确定性不变量**(同一条流重放 ⇒ 同一串 id)。`CHROME_ARMS` = 端「我要消费哪些 chrome 臂」的对照清单 | `src/seam.ts` |
134
- | 3 | **HITL 决断卡链**(§4/§5 主战场) | 121 | `makeHitlCanUseTool` · `HitlBridge` · `findPendingForTask` · `HitlSafetyError` · `bridgeAskUserQuestionGates` · `surfaceToolApprovalFrameAndRespond` / `surfaceFsApprovalAndDecide` · `readToolApprovalRespondAck` · `installApprovalCardPort(For)` · `installHitlHostSurface(For)` · `armPlanReviewApproval` · `reopenPlanReviewCard` · `decidePlanReview` · `startApprovalsFeed` · `pendingRowIsOwnedByThisSession` · `approvalCallKey`/`liveFrameCallKey`/`planReviewQuestionId` · `registerArmedGateFor`/`wasGateArmedFor`/`clearArmedGateFor` · `waitForGateArmed(For)`/`onGateArmed(For)`/`gateArmedWaitMs`(#244 F1 呈现回执事件源) · `planReviewArmedKey(For)`/`notePlanReviewAnswered(For)`/`notePlanReviewAnsweredIfDecisive(For)`(A-024.4 plan 呈现分代) · `toolEndOutputText` · `isAskTool` · `waitForParkRowBirth` · `classifyAskParkRows` / `askParkRowArm` / `classifyAskParkChainFailure` · `readDecisionNoteAudit` / `decisionNoteAuditLine` · `resumeRunningOptions` / `resumeChoiceFromLabels` · `persistedRulesLaneAvailable`/`persistedRulesGovernanceAvailable` · `classifyRulesFailure` · `listAllPersistedRules` · `classifySkippedReason` · `readRulePersistOutcome`(#244 F2:persist-ack 读口与 `readToolApprovalRespondAck` 合成一处) · `parseLocalAllowRule`(durable 腿本地落规则窄化骨架,谓词经 `LocalAllowRuleDeps` 注入) · `DecideTransportRetryExhaustedError`(Inkglow-1085 P0a:decide 出站瞬断重试耗尽的 typed 判别 —— HitlBridge 内建单次退避重试,耗尽走重呈臂不判死 turn;端一般只消费行为,不需要 instanceof) | suspended→decide→resume 环。🔴 **D-1 两元组 verbatim 回显**是字节级断言的安全不变量,端**不许重实现它的任何一段**。🔴 键空间边界(web [C1] d3 拦截):`gateIdentity` 四常量两函数只覆盖 HITL questionId/callKey 空间;seat 的 `TOOL_PERMISSION_REQUEST_ID_DOMAINS`(`plan:` 等)是另一键空间,**两者绝不合并**(合并=座位校验器静默拒全部 plan-review 卡) | `src/hitl/hitlBridge.ts`、`toolApprovalWire.ts`、`askGateWire.ts`、`planReviewWire.ts`、`hitlHostSurface.ts`、`gateIdentity.ts`、`armedGateRegistry.ts`、`parkOwnership.ts`、`parkResolver.ts`、`approvalsFeed.ts`、`frameRouter.ts`(**只挑名导出** `toolEndOutputText`/`ENGINE_ABORT_TOOL_RESULT`/`isAskTool`/`HITL_REJECT_MESSAGE`)、`parkRowBirthWait.ts`、`approvalDecisionNoteAudit.ts`、`askParkRowRouting.ts`、`resumeRunningCard.ts`(#265 上收的判定层)、`persistedRulesWire.ts`、`localAllowRule.ts`(#244 F2 规则侧) |
134
+ | 3 | **HITL 决断卡链**(§4/§5 主战场) | 125 | `makeHitlCanUseTool` · `HitlBridge` · `findPendingForTask` · `HitlSafetyError` · `bridgeAskUserQuestionGates` · `surfaceToolApprovalFrameAndRespond` / `surfaceFsApprovalAndDecide` · `readToolApprovalRespondAck` · `installApprovalCardPort(For)` · `installHitlHostSurface(For)` · `armPlanReviewApproval` · `reopenPlanReviewCard` · `decidePlanReview` · `startApprovalsFeed` · `pendingRowIsOwnedByThisSession` · `approvalCallKey`/`liveFrameCallKey`/`planReviewQuestionId` · `registerArmedGateFor`/`wasGateArmedFor`/`clearArmedGateFor` · `waitForGateArmed(For)`/`onGateArmed(For)`/`gateArmedWaitMs`(#244 F1 呈现回执事件源) · `planReviewArmedKey(For)`/`notePlanReviewAnswered(For)`/`notePlanReviewAnsweredIfDecisive(For)`(A-024.4 plan 呈现分代) · `toolEndOutputText` · `isAskTool` · `waitForParkRowBirth` · `classifyAskParkRows` / `askParkRowArm` / `classifyAskParkChainFailure` · `readDecisionNoteAudit` / `decisionNoteAuditLine` · `resumeRunningOptions` / `resumeChoiceFromLabels` · `persistedRulesLaneAvailable`/`persistedRulesGovernanceAvailable` · `classifyRulesFailure` · `listAllPersistedRules` · `classifySkippedReason` · `readRulePersistOutcome`(#244 F2:persist-ack 读口与 `readToolApprovalRespondAck` 合成一处) · `parseLocalAllowRule`(durable 腿本地落规则窄化骨架,谓词经 `LocalAllowRuleDeps` 注入) · `readToolApprovalRespondRefusal`(#225 件5,0.42.0:respond 抛错的结构化原文读口 —— 三位各自防御读、各自缺席不铸、**三位皆缺席时整只返 `undefined`**;原样交还零加工,UNTRUSTED-for-display)· `installEditedRuleTextPrechecker` / `hasEditedRuleTextPrechecker` / `precheckEditedRuleText`([5076] 转出口,0.42.0:core 5.57.0 `precheckEditedRuleText` 的**端口注入形** —— 类型面 + 注入口 + 诚实缺席读口。🔴 **不是** value 级 re-export,理由见 §7 缺口 **P-34**;未装 ⇒ 返 `undefined`,绝不编一个 `{ok:true}`)· `DecideTransportRetryExhaustedError`(Inkglow-1085 P0a:decide 出站瞬断重试耗尽的 typed 判别 —— HitlBridge 内建单次退避重试,耗尽走重呈臂不判死 turn;端一般只消费行为,不需要 instanceof) | suspended→decide→resume 环。🔴 **D-1 两元组 verbatim 回显**是字节级断言的安全不变量,端**不许重实现它的任何一段**。🔴 键空间边界(web [C1] d3 拦截):`gateIdentity` 四常量两函数只覆盖 HITL questionId/callKey 空间;seat 的 `TOOL_PERMISSION_REQUEST_ID_DOMAINS`(`plan:` 等)是另一键空间,**两者绝不合并**(合并=座位校验器静默拒全部 plan-review 卡) | `src/hitl/hitlBridge.ts`、`toolApprovalWire.ts`、`askGateWire.ts`、`planReviewWire.ts`、`hitlHostSurface.ts`、`gateIdentity.ts`、`armedGateRegistry.ts`、`parkOwnership.ts`、`parkResolver.ts`、`approvalsFeed.ts`、`frameRouter.ts`(**只挑名导出** `toolEndOutputText`/`ENGINE_ABORT_TOOL_RESULT`/`isAskTool`/`HITL_REJECT_MESSAGE`)、`parkRowBirthWait.ts`、`approvalDecisionNoteAudit.ts`、`askParkRowRouting.ts`、`resumeRunningCard.ts`(#265 上收的判定层)、`persistedRulesWire.ts`、`localAllowRule.ts`(#244 F2 规则侧) |
135
135
  | 4 | **子代 wire + 面板侧信道台账** | 82 | `tailEngineSubagent` · `installSubagentActivitySink` · `installSubagentTailMetaSink`(#280 件2:tail meta 帧发布口,`contentFrames` 判别位载体)· `stopEngineTask` + `classifyTaskStopConflict` · `fetchEngineSubagentReport` · `steerEngineSubagent`(0.32.0 未发布 #280 件A:additive 第三参 `childTaskId` —— 端有行上下文时**应当**传,传了就走「台账优先 / 缺席即诚实缺席 + `noteBgOwnerAbsence` 留痕」的 Q3 口径,与 tail·taskOutput·subagentOutput 三腿同姿势、与孪生 resume 腿共用同一个 `resolveOwnerRunId` 判据;**不传**则逐字维持旧行为=回落在飞 run)· `resumeSettledSubagent` + `resolveSubagentResumeContext` + `resolveOwnerRunId` + `classifySubagentResumeFailure` + `subagentResumeAvailable`(#242 批 2 A-028.7:resume 判定半场上收,与 steer 孪生同居;取址三态 = 台账有行用行值 / 指名了行但台账缺席则**诚实缺席绝不回落在飞 run** / 没指名行才回落。出路文案归端)· `recordSubagentOwnerFromProgress` + `getBgParentRunOwner`(A-028.6:「子代 → 宿主 run」**单表**,宿主 run 必须由持 stream-local 值的调用方显式传入,包内绝不从 `activeEngineRunId()` 推断)· `noteBgOwnerAbsence`(#242 批 3 [4000] Q3=B:tail/taskOutput·taskStop/subagentOutput 三腿台账缺席即诚实缺席**绝不回落在飞 run**,缺席 warn 留痕每 (腿,taskId) 一条)· `clearBgTerminalFacts`(#242 批 3 扫码修:复活=新周期,旧周期终态事实作废——fleetLedger 复活两腿按尾段清账,factsAccepted 方向核不再拿上周期终态当先例)· `auditRetainWithoutWake`([4000] Q5:引擎宣示 `subagentResume` + 本端在付 `retainSubagentSessions` + 端未实现 `wakeSubagent` ⇒ 响亮一条;`CLIENT_VERBS.wakeSubagent` 维持 fail-soft)· `subscribeSubagentContent` · `subscribeEngineAgentPanel` · `publishQuestionFrame` / `respondToQuestion` | 驱动与观测委派子代;经 module 级台账喂活体 agent/task 面板。全部**能力位 gate**(§5b) | `src/subagent/*.ts`、`src/subagentContentStore.ts`、`src/engineAgentPanelStore.ts`、`src/engineInlineTaskStats.ts`、`src/engineToolLabelStore.ts`、`src/liveQuestionStore.ts` |
136
136
  | 5 | **fleet 投影** | 46 | `createFleetLedger` · `projectTasks` · `projectWorkflows` · `projectFleetAgentRows` · `readEngineActiveBgTasks` · `FLEET_TASK_VIEW_KEYS` · `escapeDisplayControlChars`(不可见字符可见化,行标签/描述消毒的共享底座)· `wireCycleSeq` / `wireRetiredBy`(0.38.0 提货补投的 #261 §2 两位:代际号 = SendMessage 复活即 +1,**缺席 ≠ 第一代**;`retiredBy` 在场 = 这条终态是对账腿从 durable run 行投影出来的、**不是**发布方亲报 —— 幽灵行与正常收尾唯一的 wire 判据。两位都只在场才落键) | 老 `fleetClient` 那一刀的成品:**帧体归库、连接归端** —— 端持 SSE 连接,库做行投影 + 保留台账 | `src/fleet/fleetProjection.ts`、`src/fleet/fleetLedger.ts`、`src/fleetAgentPanelProjection.ts`、`src/fleetTaskDesc.ts` |
137
137
  | 6 | **请求装配(上行唯一构造口)** | 8 | `buildTaskRequest` · `REQUEST_FIELD_MATRIX` · `unregisteredRequestKeys` · `applyLiveRequestDefaults` · `taskNotificationToPrintFrame` | 两条车道(`interactive`/`print`)出站请求的**唯一**构造器;`unregisteredRequestKeys` 是可执行门 —— 端偷带一个未登记键上 wire 就红 | `src/request/taskRequest.ts`、`src/request/printNotification.ts` |
@@ -141,7 +141,7 @@ SDK 核对「本包 import 的每个值级符号仍然导出」「`TaskStats.cos
141
141
  | 10 | **headless / 部署旋钮 wire** | 61 | `parseSandboxArgv` / `sandboxRequestFields` · `parseLimitsArgv` / `limitsForPrint` · `resolveHeadlessFinalVerify` · `resolveHeadlessPermissionMode` · `resolveHeadlessInteractiveTools` · `armDetachCancel` + `detachCancelArm` + `isDetachArmed` · `withHeadlessR1Reconnect` | `-p`/headless 车道的 env+argv 旋钮。🔴 `detachWire` 是**拆**的补偿:判定与 cancel-arm 台账在库,信号路径的裸 fetch 留宿主(`detachCancelArm()` 是取件口) | `src/sandboxWire.ts`、`scenarioWire.ts`、`finalVerifyWire.ts`、`limitsWire.ts`、`interactiveToolsWire.ts`、`headlessPermissionModeWire.ts`、`headlessReconnectWire.ts`、`detachWire.ts` |
142
142
  | 11 | **模型目录与预算** | 67 | `resolveModelCatalog` · `loadCatalogWithSources` · `PROVIDER_PRESETS` / `MODEL_FAMILIES` · `defaultMaxTokensFor` · `getLiveModelCatalog` / `setLiveModelCatalogRefresher` · `providerAuthMethods` / `beginDeviceCodeAuth` · `providerCatalogRows` / `providerCatalogRowDetail` / `providerPresetById`(#244 F4 族D A-028.17:46 家表的规范折表层 —— 全表不重排、诚实缺席「model id typed in」,cli 目录/web 向导同一份折表)· `TIER_ORDER` / `CC_TIER_ALIASES` / `isTier` / `resolveTierBinding`(A-028.18:档位词表+校验+fail-open 降档派生单源;settings 存储归宿主)· `resolveEntryVision` / `computeDeleteBlockers` / `computeDeleteWarnings`(0.38.0 #318 件③ 上收:Model Hub 供给面的三端公共判定 —— vision 生效值+来源三态、删除断链核(拒删+指路)、删除降级后果(照删但必说)。**零 IO**,读盘那半场留各端;`doc === null` 的两义在调用方分流) | 三层 provider 目录解析(线上 URL → 包内预设 → 用户覆盖)+ per-model `maxTokens` 封顶。线上腿需注入 `CatalogFetchJson`,缺席 ⇒ 整条不启用(`online.reason='no-fetch-port'`);缓存落盘经 `CatalogCachePort` | `src/model/{catalog,catalogLoader,providerAuth,providerPresets,providerCatalog,tierVocabulary}.ts`、`src/liveModelCatalog.ts`、`src/modelBudgetRule.ts`、`src/sessionModelLatch.ts`、`src/effortWire.ts` |
143
143
  | 12 | **workflow 与后台工作视图** | 19 | `projectWorkflowRun` · `createLiveWorkflowSource` · `ensureWorkflowActivityLedger` · `readWorkflowActivityLedger` · `stopWorkflowActivityLedger` · `resetWorkflowActivityLedgers` · `createBackgroundView` · `projectBackgroundView` · `recordWorkflowAgentTaskId` · `agentDisplayStatus` | 活过一个 turn 的长任务读面:workflow run + 跨 session 后台任务归一表(`assistant.tasks` 与 fleet SSE **两源独立降级**) | `src/workflow.ts`、`src/workflowClient.ts`、`src/workflowMonitor.ts`、`src/agentSession/backgroundView.ts`(+ 纯类型 `src/agentSession/contract.ts`) |
144
- | 13 | **座位 IPC 契约** | 33 | `LOCAL_SESSIONS_SPEC` · `SEAT_METHOD_NAMES` · `SEAT_EVENT_TYPES` · `isLocalSessionEvent` · `isToolPermissionRequest` · `toolPermissionRequestId` · `SEAT_VALIDATOR_KEY_COVERAGE` | desktop↔web 座位 IPC 契约的**单一真源**(此前两边各一份、名字零重合 ⇒ 编译器永远不会告诉你它们漂了)。🔴 加 verb 忘了加 `LOCAL_SESSIONS_SPEC` **不报错**:preload 不注册 channel、渲染端读到 `undefined` | `src/seatContract.ts`(**零 import**,纯类型 + 常量 + 纯谓词) |
144
+ | 13 | **座位 IPC 契约** | 33 | `LOCAL_SESSIONS_SPEC` · `SEAT_METHOD_NAMES` · `SEAT_EVENT_TYPES` · `isLocalSessionEvent` · `isToolPermissionRequest` · `toolPermissionRequestId` · `SEAT_VALIDATOR_KEY_COVERAGE` | desktop↔web 座位 IPC 契约的**单一真源**(此前两边各一份、名字零重合 ⇒ 编译器永远不会告诉你它们漂了)。🔴 加 verb 忘了加 `LOCAL_SESSIONS_SPEC` **不报错**:preload 不注册 channel、渲染端读到 `undefined` | `src/seatContract.ts`(**零 import**,纯类型 + 常量 + 纯谓词)。🔴 **证据等级标注(0.42.0,test [5087] 的「语料**种类**缺口」/ cli [5088] 认领件)**:该文件里所有以「CC 如何如何」为形的断言(`212 methods` / `854-channel census` / 方法名逐字保留 / `fQe` 逐字段对照 / 一切 `.vite/build/index.chunk-*.js` 坐标)**证据等级 = 桌面 unpack,本地语料库不可复验** —— 本仓手边可复验的参照语料**只覆盖终端 CLI 形态**的静态产物,拿它去 grep 桌面壳里的符号只会零命中,而零命中在这里**既不证真也不证伪**。复核这些断言**不得**拿本仓语料当反证 |
145
145
  | 14 | **宿主端口与会话槽** | 26 | `installHost` · `installHostFor` · `hostPortMisses(For)` · `DEFAULT_SESSION_KEY` · `hostEnv` · `unrefTimer` · `parseLocaleTag` / `pickUiLanguage`(#244 F4 族D A-028.20:locale tag 手术单源 + UI 语言判定;与 `resolveRegionHint` 双出口成文 —— 语言偏好域 en/zh ≠ 地址可达域 cn/intl/unknown,`zh-Hant` 前者 zh 后者 intl 是设计)· `engineNamespaceKeyFor` / `mergeSessionMapRecord` / `mergeEngineEntry`(A-028.12:会话 id 映射单一键形 + merge 判定;存储经 `SessionMapStorePort` 归端 —— cli 文件锁/原子写,web localStorage)| 进程/端级装配层(settings/fs/queue/timers/session/log/probe),与 per-turn 的 `AdapterContext` **分层**。头注的判定规则:**这个能力每 turn 都会变吗?** 会 ⇒ `ctx`;不会 ⇒ `installHost` | `src/host.ts`、`src/hostEnv.ts`、`src/sessionSlot.ts`、`src/unrefTimer.ts`、`src/env/{localeGeo,localeTag,uiLanguage}.ts`、`src/sessionMap.ts` |
146
146
  | 15 | **控制面与传输** | 73 | `ControlRouter`(+ `ControlSafetyError`)· `makeEngineWireClient` + `resolveWireAuth` · `installEngineWireTarget` · `diagnoseSseIdleTear` / `isSseIdleError` · `attemptActiveRunSelfHeal` + `activeRunBusySignal` + `activeRunSelfHealRow` / `activeRunBusyHeadlessRow` · `kickEngineCapsProbe` / `engineCapTrue` / `invalidateEngineCaps(baseUrl, probe?)`(#307 S25:引擎温切后的 caps 生产失效口 —— kick 自带幂等闸,同 baseUrl 重启后不显式失效就永远读到旧引擎那一版能力位;调用方 = 壳的 respawn/restartEngine。🔴 **推荐两参形**:第二参给替代探测则「推进代际 + 注册新探测」在同一同步块内完成,失效与下一次 kick 之间那个「等待者读到未判」的窗按构造不存在;单参形保留给「只丢缓存、这一刻没有替代探测」的调用方,那种情形下读到未判是诚实结局) · `mapBrainStatusToRetry` · `waitForClaimRelease` + `CLAIM_RELEASED_STATES` / `CLAIM_HELD_STATES` · `atMostOnceFailureClass` / `readSteerDelivery` · `clearRunningChoiceOffer`(Inkglow-1085 P0b①:「Do nothing」登记的清口 —— 端的「重新打开操作菜单」入口;登记在场时 attemptActiveRunSelfHeal 不整卡重弹,not-parked 结局带 `alreadyOffered: true` 判别位,端据此降级渲一行)· `INTERACTIVE_WAY_OUT`(默认出路串单源)· `normalizeWirePrincipal`(A-028.10:principal 在场性 trim 原语 —— 全空白=缺席不发头,engineWireTarget 两臂/makeEngineWireClient/壳 livePrincipal 同尺)· `classifyTurnWireError` / `isWireTransportError` / `isPreStreamDrainingReject` / `isResumeAtRejection` / `drainingRetryDelayMs` / `scenarioDenyFromError` + `WIRE_NETWORK_ERROR_PATTERN`(A-028.11/.13:turn 错误分型判定半场,人话文案与渲染归端) | 上行通道的**监管**半场(submit / steer / kill / 队列命令定序)+ 传输构造、caps 探测、SSE 断流分诊、**409 active-run 自愈** | `src/controlRouter.ts`、`steering.ts`、`sseIdleTriage.ts`、`retryStatus.ts`、`diagnostics.ts`、`engineWireSdk.ts`、`engineWireTarget.ts`、`src/principalWire.ts`、`src/wireErrorTriage.ts`、`engineSessionParam.ts`、`engineCapsCache.ts`、`liveInitToolFace.ts`、`adapter/activeRunSelfHeal.ts` |
147
147
  | 16 | **引擎词汇表与包自检** | 48 | `CONFIG_REFUSAL_CODES` / `isConfigRefusalCode` · `STOP_CONFLICT_CODES` · `isInterruptedToolEndCode` · `isRewindFamilyCode` · `CLIENT_VERBS` · `compensationSplitViolations` · `DELEGATION_CAP_CODES` / `isDelegationCapCode` / `DELEGATION_CONCURRENCY_CAP` / `DELEGATION_SESSION_CAP`(0.38.0 #318 件④:core 5.48.0 design/323 委派席位到限**两码,处置不对称禁合并** —— 并发帽=**可等**(兄弟结束即有位)/ 会话累计帽=**等也没用**(这条会话的配额用尽))· `CONFIG_DELEGATION_ENTRY_CAPS`(同批入 `CONFIG_REFUSAL_CODES` 识别表)· `delegationCapDispositionOf` / `MCP_SERVER_REVOKED`(0.39.0 载体到货消费件:core 5.50.0 补 `{ error: code, code }` 孪生拼法后两码真上 `tool_end.errorCode`,0.38.0「先立词不落消费分支」的已知局限自此解除;处置轴 `wait-for-slot` / `reuse-existing-or-await-reap` 机器可读(累计帽=retained-window 帐,行回收配额即回,处置=SendMessage 复用,**非**「换会话/永久耗尽」——0.38.0 段该句系勘误),未知 `delegation.*` 码 ⇒ `undefined`;`mcp.server_revoked` = 操作员 mid-session 吊销 server 后的工具面本地闸(被吊销的 server **名**今天不过 wire 境:detail.server 是进程内位,抬升腿只 lift code——归因渲染候 core 补 typed detail,已点名);载体门 = engine-vocab G3 腿锚 core dist 铸点) | 三端分臂共用的**去字面化** `errorCode` 词表(病根正是三端各抄一份字面);编译期 verb 闭合门;搬迁补偿登记表 | `src/engineErrorCodes.ts`(计数以 `scripts/public-export-baseline.json` 为准,别手抄;A-028.11/.13 补 `DRAINING_ERROR_CODE`/`SCENARIO_NOT_ALLOWED_ERROR_CODE`/`RESUME_AT_ERROR_CODE_PREFIX`;#318 件④ 补 `delegation.*` 族四位 + `config.delegation_entry_caps`;0.39.0 补三新码消费件三位)、`src/classifierVerdictWire.ts`、`src/compensations.ts`、`src/clientSlice.ts` |
@@ -250,6 +250,34 @@ lane 归属改用 id 形状 / `workflowRunId` 启发式判(`src/adapt/arms.ts`)
250
250
 
251
251
  **实现锚**:`src/adapter/downstream/eventToSdkMessage.ts` 的 `case 'task_progress'`。
252
252
 
253
+ #### 3d-2. `tool_end` 臂的键级剥离账(**已清**,0.42.0 A-D2)
254
+
255
+ `case 'tool_end'` 曾是同一个病形的连续实例 —— 臂是**闭形白名单**,于是一条**已经在 wire 上**的
256
+ 事实到不了宿主,而两边代码看着都对。逐例:`toolCallId`([1947])→ `governanceForced`([2942])→
257
+ `settledBy` / `approver`(#263,0.30.8)→ `_sema_collateral_abort`(#324,0.40.0)→
258
+ **`resolution`(A-D2,0.42.0,本批)**。
259
+
260
+ `resolution` = core ≥5.35 的 `AskDenyResolution` 九词闭集(`human_refused` / `window_expired` /
261
+ `no_approver` / `blanket_allow_refused` / `approver_unavailable` / `task_aborted` /
262
+ `presentation_failed` / `approver_error` / `approver_contract`),**只在这一帧收口的是一次
263
+ in-process ask 拒绝时**在场。
264
+
265
+ 🔴 **端的读法(与 `settledBy` 合读,不互替)**:`settledBy` 说这次等待是哪一**种**收场;
266
+ `resolution` 分类的是**拒绝臂本身**。单锚 `settledBy` 会把「审批方违约」(approver 回了契约外的
267
+ 东西,窗口并没有自然走完)误收进「窗口走完了」。
268
+
269
+ 🔴 **判据用正面匹配,不用「不等于」**(0.42.0 异源复审 [medium] 采纳,**端必读**):
270
+ 判「审批窗口自己走完了」写 `settledBy === 'timeout' && resolution === 'window_expired'`。
271
+ **绝不**写 `resolution !== 'approver_contract'` —— 那个不等式对**缺席**(旧引擎不发这一位)与
272
+ 对**任何未来新码**都为真,于是「不知道是怎么拒的」会被折成「窗口自然结束」,正是本位存在要防的
273
+ 那件事。缺席与未知值一律进 `default` 分支。
274
+ 🔴 **开集读**:九词是引擎的词表,端**必须**分支已知值 + 永远带 `default`,表外词原样呈现。
275
+ 🔴 **缺席不可反推**:每一次真执行了的调用、每一次 policy/hook 直拒、以及 durable/decide 腿的
276
+ 结算(它们带自己的 `settledBy`/reason)都**不带**这一位;缺席 ≠「不是拒绝」也 ≠「人拒的」。
277
+
278
+ **实现锚**:`src/adapter/downstream/eventToSdkMessage.ts` 的 `case 'tool_end'`;
279
+ 防御性读形 `ToolEndResultArmLike.resolution` 在 `src/printToolResultFrame.ts`。
280
+
253
281
  ### 3e. 无臂帧(SDK union 里连成员都没有 ⇒ 穷举保护对它失效)
254
282
 
255
283
  `approval_revoke`(批级撤卡帧)**不是** `AgentEvent` 的成员 —— SDK `events.d.ts` 顶注自记这是刻意的
@@ -463,6 +491,88 @@ pure 门 062⑥/⑦):
463
491
 
464
492
  🔴 **方向纪律**:`reason`/`note` 只做归因,**绝不参与裁决**;带不带、内容是什么,都不改变这次仍是 deny。
465
493
 
494
+ ### 4b-2. 🆕 `#225` 编辑臂:自由文本规则的**发送前置门 + 拒句回传**(0.42.0;server ≥7.44)
495
+
496
+ 上游形见 server `[5071]`(#340 `respondFreeFormRules`)。本包只做**编排与过境**,判官全在引擎侧。
497
+
498
+ #### (a) 卡决断 → respond:两位**扁平兄弟位**,注入面负责合成 wire 形
499
+
500
+ | 位 | 型 | 语义 |
501
+ |---|---|---|
502
+ | `ApprovalCardAllowDecision.persistRule` | `string`(**字节不变**) | 0.26.0 起就有的兑付键 |
503
+ | `ApprovalCardAllowDecision.persistRuleEdited` | `true?` | 🆕 这段文本是**人手改的自由文本**,不是帧候选原文 |
504
+ | `RespondToolApprovalOpts.persistRule` / `.persistRuleEdited` | 同上 | 编排层已做能力位闸与 deny 剥除后交给注入面的形 |
505
+
506
+ 🔴 **注入面的映射义务**(本包只到这一格,wire 体由宿主/SDK 铸):server 的 respond 体形是
507
+ `persistRule: { rule, edited: true }`。本包**刻意保持扁平兄弟位**,由注入面合成那个嵌套形:
508
+
509
+ ```ts
510
+ persistRule !== undefined
511
+ ? { rule: persistRule, ...(persistRuleEdited === true ? { edited: true } : {}) }
512
+ : undefined
513
+ ```
514
+
515
+ 改成嵌套形会是既有 `persistRule: string` 消费者的 **BREAKING**,而这一批的纲领是 additive。
516
+ 🔴 **缺席 = 候选臂**:老 server 收到带 `edited` 的体会**诚实降级** `rule_not_offered`(不是静默
517
+ 200 什么都不落)—— 这正是 `[5071]` 选 `persistRule.edited` 而不是顶层新键的理由。
518
+
519
+ #### (b) 能力位闸:`ToolApprovalFrameLaneOpts.respondFreeFormRulesCapable`
520
+
521
+ 形与判据**逐字照** `approvalDecisionNoteCapable`(§4b 那条,同一条 SDK 6.16 纪律:**位缺席就别发**)。
522
+ 宿主从自己的 caps 缓存供给 `capabilities.respondFreeFormRules`(server ≥7.44 恒真版本位)。
523
+
524
+ - `=== true` ⇒ 编辑臂两位一起上 wire;
525
+ - 缺席 / `false` ⇒ **`persistRule` 整条不发**(fail-closed 到「不发」侧),决断本身照常送达,
526
+ 老引擎**零受迫**、行为逐字节 = 0.41.0;
527
+ - **候选臂不受本位影响**(它是 0.25.0 起就有的既有通道)。
528
+
529
+ #### (c) 运行期候选表核的**让位**判据(端最容易读错的一格)
530
+
531
+ 包内那道「never sending un-offered text to the rule store」的表核,在**且仅在**
532
+ `persistRuleEdited === true` 时让位。
533
+
534
+ 🔴 **让位只认出身声明,绝不认「文本恰好不在候选表里」**。后者会让一个拼错候选原文的坏卡口实现
535
+ **自动升级**成自由文本臂,把这道核对彻底架空。端的义务:卡上「人动过编辑框」这件事必须如实
536
+ 声明,不许拿「反正表核会放行」当捷径。
537
+ 🔴 **端零本地解析器预检**:不许在编辑框里跑 `parseAllowRuleText` —— 那是一个**更严的第二判据**,
538
+ 会当场误杀 `Bash(adb *)` 这类肌肉记忆形(`[5071]` 定界②,core `[5075]` 复核确认)。要边打字边
539
+ 校验,用 §5a 的 `installEditedRuleTextPrechecker` 注入口 —— 那是**引擎自己那只**判官。
540
+
541
+ #### (d) `ToolApprovalFrameOutcome.respondRefusal`:400 / `edit-rejected` 原文**交还调用方**
542
+
543
+ | 位 | 缺席语义 | 消费方义务 |
544
+ |---|---|---|
545
+ | `respondRefusal?.status` | 缺席 = 传输层失败 / 注入面自抛(**不许反推成 0**) | 有值 = 引擎真应答了 |
546
+ | `respondRefusal?.errorCode` | 缺席 = 应答没带码 | 开集,原样呈现 |
547
+ | `respondRefusal.message?` | 缺席 = **这个抛出物上读不出任何可用文本**(占位串 `[object Object]` / `null` / `undefined` / 空串一律当读不出);不再无条件退 `String(err)` | **原样呈现,零加工**;UNTRUSTED-for-display,只渲染,绝不回喂模型/工具入参。🔴 端必须按**可选**读(`refusal.message ?? '…'`),别无保护地渲一个 `undefined` |
548
+
549
+ 🔴 **`decision` 的语义一字未改**:仍是 `'unresolved'`(respond 没落定 = 引擎按 TTL/abort 自决)。
550
+ `respondRefusal` 是**附加**的诊断面,**不是**新的决断态 —— 端不得把它当成第五种 decision。
551
+ 🔴 **`respondRefusal` 整只缺席 = 没有拒绝面可交**(respond 成功 / 抛的东西上**三位皆读不出**),
552
+ 绝不造一句。在场时**三位都可能缺其二** —— 有 `status` 没文本(应答体为空)、有文本没 `status`
553
+ (传输层失败)都是真实形,端逐位判在场,不许「在场就当三位齐」。
554
+ 🔴 **但「在场即至少有一位」是编译期保证**:`ToolApprovalRespondRefusal` 是**三选一联合**
555
+ (`{status} | {errorCode} | {message}`,其余位各自可选),`{}` 在类型上就不可赋值 ⇒ 端可以放心
556
+ 按「对象在场 = 至少有一条诊断信息」写渲染兜底,不必再防一个空壳。
557
+
558
+ **为什么这一格非补不可**:此前本函数的 `catch` 只写一行 `debug` 就返 `{decision:'unresolved'}`,
559
+ 于是 server 的响亮 400(`persistRule.rule` 空/超长、`edited` 非布尔、顶层 `scope`、`edit-rejected`
560
+ 的拒句)在**包边界上被吞掉** —— 宿主的错误反馈面无论怎么写都拿不到那句话,人在卡上改了规则被拒,
561
+ 屏上什么都不会说(`[5111]` 探针在 0.41.0 上实测到的闭集三处之③)。
562
+
563
+ #### (e) UI 文案纪律(core `[5075]` 两点语义预披露,消费侧写文案前必读)
564
+
565
+ - 预检 `ok` = **可提交**,不是「confirm 必成」—— 记录级闸(binding 回声 / 记录 owner 与 state /
566
+ scope 继承 / 部署开关)**不在**预检覆盖面。文案只许写「可提交」,**绝不**写「将被批准」;
567
+ - `canonicalRule` 可能与输入**字节不同**(拼写归一)。内联反馈应显示 **canonical 形**,与落库行一致。
568
+
569
+ **实现锚**:`src/hitl/toolApprovalWire.ts`(`ApprovalCardAllowDecision.persistRuleEdited` /
570
+ `RespondToolApprovalOpts.persistRuleEdited` / `ToolApprovalFrameLaneOpts.respondFreeFormRulesCapable` /
571
+ `ToolApprovalRespondRefusal` / `readToolApprovalRespondRefusal` / `surfaceToolApprovalFrameAndRespond`
572
+ 的兑付段与 catch 段)、`src/hitl/editedRuleTextPrecheck.ts`(预检转出口)。
573
+ **常驻门**:`scripts/run-hitl-gate-honesty-test.mjs` 的 **F12** 三腿(能力位缺席不发 / 表核让位负控 /
574
+ 400 原文可达),各带负控。
575
+
466
576
  ### 4c. `ReopenCardVerdict` 的 `presented` 位契约
467
577
 
468
578
  ```ts
@@ -551,6 +661,7 @@ durable park 腿走 `HitlBridge.decideTool(outcome, toolUseID, opts, preResolved
551
661
  | `installSubagentTailMetaSink` | `src/subagent/engineSubagentTail.ts`(#280 件2,0.30.4) | tail `event: meta` 帧不发布(0.30.3 现状) | 否 | `contentFrames` 供给形判别位(闭集 {on, progress_only, unknown})不达端 ⇒ 端把「结构性无内容(forward 缺席宿主)」误读成「还没来」永远空挂。载荷 = `{taskId, meta}`(meta 为帧**开集原文**,判别位窄读归端);⚠️ 判别位要在子代存活窗内消费(server 侧登记随句柄终态撤销,终态后 tail 读到 `unknown` 不是回归) |
552
662
  | `installWorkflowStatusProbe` | `src/notifications.ts` | watcher 没有带对 baseUrl/token/principal 的 `workflows.get` | — | **workflow 完成通知永远不落地** |
553
663
  | `installBgTaskStatusProbe` | `src/notifications.ts` | bg 状态 watcher 空转 | — | **后台子代完成通知永远不落地**(这个 watcher 存在的理由正是 idle 期推送不可靠) |
664
+ | `installEditedRuleTextPrechecker`(#225 / [5076],0.42.0) | `src/hitl/editedRuleTextPrecheck.ts`;**Node 宿主**装 core 5.57.0 的 `precheckEditedRuleText`,**原样装不许包一层** | `precheckEditedRuleText(text, command)` ⇒ **`undefined`**(诚实缺席);存在性读口 `hasEditedRuleTextPrechecker()` ⇒ `false` | 否(浏览器 lane 结构上装不了,缺席是**合法常态**) | 规则编辑框的**内联即时校验**不启用 ⇒ 退「提交后才知道」的往返形。🔴 缺席**不是**故障态,别据它判部署;🔴 读口返 `undefined` 而不是 `{ok:true}` —— 后者是替一只不在场的判官发言 |
554
665
  | `CatalogFetchJson`(注入,非 install) | `src/model/catalog.ts` | 线上腿**整条不启用**(`online.reason = 'no-fetch-port'`) | — | 目录只走包内兜底(端可据 `source` + `online.reason` 诚实渲「内置版本(离线)」) |
555
666
  | `CatalogCachePort`(注入) | `src/model/catalogLoader.ts` | 缓存不落盘 | — | 每次冷取 |
556
667
  | **`EmitContext.onDroppedFrame`**(🔴 **per-turn `ctx` 注入,不是 `install*` 端口**) | 填在传给 `runStream`/`adapt` 的 `ctx` 上(`src/adapter/types.ts`) | 丢帧只剩包内一行 `console.error` | **否**(可选注入,缺席 = 该宿主不消费) | Ink 类宿主**吞 console** ⇒ 丢帧对用户**零可见**(P-22),而「引擎发了一帧、这个 build 渲不出来」正是最该被看见的一类。三条语义(实现在 `src/adapter/runStream.ts` 的 `reportDroppedFrame`):**每条都发不去重**(替宿主去重 = 替它撒谎,告警面的计数就不是真的)· **装了 sink ⇒ console 让位**(sink 是更强的通道,两条腿同喊会打乱 TUI)· **sink 抛错绝不打断流**且痕迹落回 console(让位的前提是它真接住了) |
@@ -576,6 +687,7 @@ durable park 腿走 `HitlBridge.decideTool(outcome, toolUseID, opts, preResolved
576
687
  | 审批卡口(取值口) | `approvalCardPortFor(sessionKey) !== null` | 哨兵 `null`(`ApprovalCardPort \| null`);`hasApprovalCardPortFor` 就架在它上面 |
577
688
  | HITL 宿主面 | `hitlHostSurfaceFor(sessionKey) !== null` | 🔴 **哨兵是 `null` 不是 `undefined`**(`src/hitl/hitlHostSurface.ts`:`HitlHostSurface \| null`)—— 写成 `!== undefined` 是**恒真**,完全没装也会通过(R5 命中)。漏装 = §4a 两条安全告知 + cancel-by-deny warn + Recent Denials 全丢 |
578
689
  | 问答 overlay | `hasQuestionOverlayFor(sessionKey) === true` | 返回 `boolean`,无哨兵歧义 |
690
+ | 编辑臂预检判官(#225 / [5076],0.42.0) | `hasEditedRuleTextPrechecker() === true` | 返回 `boolean`,无哨兵歧义。🔴 与上面几口**不同**:`false` 是**合法常态**(浏览器 lane 结构上装不了引擎那只纯函数),**不许**把它写进「启动断言恒 true」那一类;它的用途是决定**给不给编辑框的内联反馈**。取值读口 `precheckEditedRuleText(text, command)` 未装时返 `undefined`(诚实缺席,不是 `{ok:true}`)|
579
691
  | settings(默认键) | `hostSettings() !== undefined` | ⚠️ **这一族才是 `undefined`**(`src/host.ts`:`Port \| undefined`),与上面几行的 `null` 不同源 |
580
692
  | settings(会话键) | `hostSettingsFor(sessionKey) !== undefined` | 同上 |
581
693
  | fs(默认键) | `hostFs() !== undefined` | 同上 |
@@ -854,6 +966,10 @@ CHANGELOG 0.29.0「已知局限」段与相应 JSDoc 都有成文。**别在读
854
966
  | **P-8** | med | **plan review 没有 edit 态**:判决只有 `'approve' \| 'reject' \| 'dismissed'`,选项字面就两条(`Yes, approve and run the plan` / `No, reject it (keep planning)`);`dismissed` **不是 wire 上的第三种判决** —— 命中它时 park 原样留着,`deliverDecision`/`decidePlanReview` 根本不可达。包内**任何一层都没有**「编辑 plan」的 affordance | `src/hitl/planReviewWire.ts`(`planReviewDecisionFromAnswer` / `PLAN_REVIEW_APPROVE_LABEL` / `PLAN_REVIEW_REJECT_LABEL` / `dismissed` 早退分支);durable 腿的 `editedPlan?` 位见 `src/hitl/hitlBridge.ts` 头注 | 把「编辑」建模成 **reject → 继续 planning → 新 turn**。🔴 内联 plan 编辑器**不许**经 `planReviewWire` 投递,也**不许自造第三个选项标签**(core 围栏 `selected ⊆ options`,表外标签会落 `dismissed`)。要 edit 态走 C 板提需求,由包补位([C163]-2④「plan edit 三态候包位**不开洞**」) |
855
967
  | **P-9** | low | `wakeSubagent` 在 `CLIENT_VERBS` 里是 `required:false` 的**声明位**,包内无实现编排 | `src/clientSlice.ts`(`CLIENT_VERBS` 的 `wakeSubagent` 行) | 端要这条腿得自己接 `runs.resumeSubagent`;取址口径受 P-1 拖累(`parentToolCallId` 不一定在场,合法退路是 `agentName`,同名多员由 server 409 `steering.ambiguous_target` 兜) |
856
968
 
969
+ | **P-33** | low | **`CANCEL_DENY_BUDGET_MS` 的论证前提已作废,数值未动**(0.42.0 §2.4 撤稿件的如实残余):那 2s 预算的原理由是「DENY-abort 语义上引擎收到即终结 run」,而 server `ASSISTANT-WIRE-CONTRACT.md` §4a 逐字反对(**DENY 是 TOOL 级应答,永远不是 run kill**)。于是「decide 慢」与「deny 丢了」这两件事在 2s 这个刻度上**不可分**,晚到的成功也不会撤回那行 warn(只有 10s 自清) | `src/hitl/hitlHostSurface.ts`(`CANCEL_DENY_BUDGET_MS` 头注的重审段 + `observeCancelByDeny`) | 端**不要**把 `CANCEL_DENY_WARN_TEXT` 那行当成「会话一定锁死了」的判据——它今天只证明「2s 内没收到 settle」。根治要做成两档(软档只记 debug、硬档才上屏),那是**跨仓一批**(包侧改时序 + 壳侧同批换判据与用例),本批**刻意不做单边改动** |
970
+ | **P-35** | low | **`WIRE_NETWORK_ERROR_PATTERN` 与 web 的 `NETWORK_PATTERNS` 存在真实的**大小写敏感度分叉**(0.42.0 [C195] 行为对拍腿实测):本包整条基表带 `i` flag,而 web 的 errno 类 token(`ECONNREFUSED` / `ECONNRESET` / `ETIMEDOUT` / `EAI_AGAIN` / `ENOTFOUND` / `EHOSTUNREACH` / `ENETUNREACH` / `EPIPE` / `UND_ERR`)**逐条无 `i`** ⇒ 同一条小写 errno 文本,本包判 `transport`、web 判 `unknown` | `src/wireErrorTriage.ts`(`WIRE_NETWORK_ERROR_PATTERN`);对拍腿 = `scripts/run-client-core-pure-test.mjs` 的 `F3E-C195-web-parity` 条件腿 | 分叉**已登记并被门钉住**(登记表在对拍腿里,分叉消失即红、未登记的新分歧也红)。端今天照现状读即可;要收敛得两侧同批改 flags —— 这属跨仓一批,已按表态制上 C 板 |
971
+ | **P-34** | low | **编辑臂预检判官在浏览器 lane 结构上装不了**(#225 / [5076],0.42.0):`precheckEditedRuleText` 的唯一合法实参是 core 5.57.0 那只纯函数,而 `@sema-agent/core` 的 barrel 值级拉 `node:crypto`/`node:fs`/`node:path` —— 本包**不能**做 value 级 re-export(portability 门 `EXPECTED_PACKAGES_INDEX` 等值门 + esbuild 浏览器腿双重否决,施工时实打验证) | `src/hitl/editedRuleTextPrecheck.ts`(模块头注的「为什么是端口注入」段) | Node 宿主(TUI / desktop 主进程)装上即得内联即时校验;**浏览器 lane 留缺席走「提交后才知道」的往返形**,这是设计不是漏装。🔴 缺席**不可**据以判断部署形态 |
972
+
857
973
  ### 7c. 多会话(sessionKey)面在册局限 —— 多会话端**接之前必读**
858
974
 
859
975
  | ID | 级别 | 一句话现状 | 实现锚 | 端**今天**必须怎么办 |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sema-agent/client-core",
3
- "version": "0.40.0",
3
+ "version": "0.42.0",
4
4
  "description": "Client-side session runtime shared by every sema human client (TUI / web / desktop): sema wire frames (AgentEvent) -> CC session vocabulary (SDKMessage) with dual-plane output (transcript/chrome), deterministic transcript ids, lane discipline as a type, and the notification/dedup ledgers. Every CC-skin shape is collected here so the wire itself stays neutral. Blackboard [1832] design axioms; [1651]/[1652]/[1653] signed seam design. Renamed from @sema-agent/wire-cc-adapter (0.1.x).",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -35,7 +35,7 @@
35
35
  },
36
36
  "devDependencies": {
37
37
  "@sema-agent/agent-types": "^0.2.0",
38
- "@sema-agent/core": "^5.50.0",
38
+ "@sema-agent/core": "^5.57.0",
39
39
  "@sema-agent/sdk": "^7.2.0",
40
40
  "esbuild": "^0.27.4",
41
41
  "typescript": "^6.0.2"