@sema-agent/client-core 0.56.0 → 0.58.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.
@@ -78,7 +78,8 @@
78
78
  * 🔴 方向纪律:reason/note 只做归因,绝不参与裁决;缺席 ⇒ 现状字节不变。
79
79
  */
80
80
  import { type GateCurrentPending, type HitlClientLike } from './hitlBridge.js';
81
- import type { RuleSuggestion, ToolApprovalRespondAck } from '@sema-agent/sdk';
81
+ import { RULE_OFFER_MATCHES, RULE_OFFER_BATCH_MEMBER_KINDS, RULE_OFFER_UNCOVERED_REASONS } from '@sema-agent/sdk';
82
+ import type { RuleSuggestion, ToolApprovalRespondAck, PersistedRuleAnchor as SdkPersistedRuleAnchor, RuleOfferMatch as SdkRuleOfferMatch, RuleOfferBatchMember as SdkRuleOfferBatchMember, RuleOfferUncoveredDetail as SdkRuleOfferUncoveredDetail, RuleOfferUncoveredReason as SdkRuleOfferUncoveredReason } from '@sema-agent/sdk';
82
83
  /** fs 写权限 gate 判定:未来的一等 kind(tool_approval)或按 toolName(server 桥首批=fs 写三件,
83
84
  * [820] 表)。AskUserQuestion 永不进这里(ask 桥先判)。 */
84
85
  export declare function isFsApprovalGate(gate: {
@@ -140,29 +141,68 @@ export interface FsApprovalWireDeps {
140
141
  * 引用比较/JSON.stringify 串比较都会假报「编辑过」。 */
141
142
  export declare function structurallyEqual(a: unknown, b: unknown): boolean;
142
143
  /**
143
- * 一条「不再询问」候选的匹配形(server/core 闭词表,两代同词)。
144
+ * 一条「不再询问」候选的匹配形 —— **sdk 8.2.0 `RULE_OFFER_MATCHES` 派生**(四员闭词表:
145
+ * `exact` / `prefix` / `wildcard` / `subpath`)。
146
+ *
147
+ * 🔴 **B-025 的病形就在这一行**(0.43.0–0.57.0):本包按当时 server 的两员词表**手抄**
148
+ * `'exact' | 'prefix'`,而 core design/382 / #510 把词表扩到四员之后手抄的那份没跟 ⇒
149
+ * 一条合法的 `match:"wildcard"` single 会被 {@link readRuleTriple} 判成坏形**整条丢掉**,
150
+ * 卡上那一格「不再询问」凭空消失。词表属上游,消费端手抄一份就是给自己立第二个判官。
151
+ * 🔴 **比铸点更窄的消费型面就是一句谎**(sdk 8.2.0 头注逐字):server 的 wire 校验器
152
+ * `RuleMatchSchema = z.enum(PERSISTED_RULE_MATCHES)` 对这四个词一律放行 —— 更窄的型面
153
+ * 让 `switch` 在编译期自称穷尽,而运行期真会来第四个词。
154
+ * ⚠️ **端要跟的差分**:本类型从两员变四员是 0.58.0 唯一的非 additive 型面动作。在
155
+ * `RuleOfferMatch` 上写 `switch`/穷举的端会在 `wildcard`/`subpath` 两格上编译红 —— 那正是
156
+ * 要显形的东西(此前那两格在端上是**静默不可达**,因为本包在读器里就丢掉了)。
144
157
  */
145
- export type RuleOfferMatch = 'exact' | 'prefix';
158
+ export type RuleOfferMatch = SdkRuleOfferMatch;
146
159
  /**
147
- * `batch` 臂的一个成员 —— 复合命令**某一段**的规则(core `SegmentRuleSuggestion` 逐字)
160
+ * `batch` 臂的一个成员 —— **sdk 8.2.0 `RuleOfferBatchMember` 判别联合**(core design/382 §2.3 B3):
161
+ * · `kind:'command'` —— 历史形:复合命令某一段的 Bash 规则(四座 + 判别位);
162
+ * · `kind:'directoryRead'` —— `cd <dir>` 段铸的**目录只读授权**(`rule` = 规范
163
+ * `Read(//dir/**)` 文本,`directory` = 词法规范绝对目录;本臂**没有** `match`/`command`)。
164
+ *
148
165
  * `segment` = 这条成员是从哪一段折叠后的命令文本铸出来的:**渲染座,永不参与裁决**;
149
- * 它与 `rule`/`command` 同属 **UNTRUSTED-for-display**(原始 post-rewrite 命令字节)。
150
- * 上游形与本包归一形**共用这一个**(成员上没有下标这回事,两代/两腿逐字相同)。
166
+ * 它与 `rule`/`command`/`directory` 同属 **UNTRUSTED-for-display**。
167
+ *
168
+ * 🔴 **B-025 的第二半**:0.57.0 的成员形只认「三元组 + segment」、**没有** `directoryRead` 臂 ⇒
169
+ * 一只带 `directoryRead` 成员的合法 batch 被**整只丢掉**。本形改由 sdk 派生后该臂被认回。
170
+ * 🔴 **成员 `kind` 不识 ⇒ 丢整只 batch,绝不丢单个成员** —— 这是 core design/382 §2.3 的
171
+ * **规范性降级臂**(逐字:"drops the WHOLE batch offer — never the single member ... and never
172
+ * the whole card"),{@link readRuleOffers} 照此实现,判据钉在 run-rule-offers-reader 门里。
173
+ * ⚠️ **本包窄读器另收一条 pre-B3 兼容臂**:`kind` **缺席**的成员按 `kind:'command'` 归一
174
+ * (server ≥7.46.0 到 B3 落地之间铸的成员没有判别位;窄读域只许等于或宽于铸点域)。
175
+ * 归一形上 `kind` 恒在场 —— 端拿到的成员永远是判别联合,零分支差异。
151
176
  */
152
- export interface RuleOfferBatchMember {
153
- rule: string;
154
- match: RuleOfferMatch;
155
- command: string;
156
- segment: string;
157
- }
177
+ export type RuleOfferBatchMember = SdkRuleOfferBatchMember;
178
+ /**
179
+ * `uncoveredDetail` 的一行 —— **sdk 8.2.0 派生**(design/382 §3.5 additive 明细座)。
180
+ * `segment` = 折叠后的段原字节(UNTRUSTED-for-display,与成员 `segment` 同一条纪律),
181
+ * `reason` = 闭三词集 {@link RuleOfferUncoveredReason}。
182
+ */
183
+ export type RuleOfferUncoveredDetail = SdkRuleOfferUncoveredDetail;
184
+ /** 「为什么这段仍未被覆盖」的闭三词集(server `UNCOVERED_SEGMENT_REASONS`,core 属主)。 */
185
+ export type RuleOfferUncoveredReason = SdkRuleOfferUncoveredReason;
158
186
  /**
159
- * **wire 上的**一条 offer —— 与上游 core `RuleOffer` 逐字同形(**没有** `offerIndex`)。
187
+ * 三张闭词表的**运行期**再导出(sdk 8.2.0 `as const` 单源)。
188
+ *
189
+ * 🔴 **端拿它做判定,别再手抄字面量** —— 本包自己的窄读器就读这两张表(B-025 的根因正是手抄);
190
+ * 再导出让三端与包**共用同一份数组对象**,词表加员时一处改、四处跟。
191
+ */
192
+ export { RULE_OFFER_MATCHES, RULE_OFFER_BATCH_MEMBER_KINDS, RULE_OFFER_UNCOVERED_REASONS };
193
+ /**
194
+ * **wire 上的**一条 offer —— 与上游 sdk/core `RuleOffer` 逐字同形(**没有** `offerIndex`)。
160
195
  *
161
196
  * 🔴 为什么与归一形 {@link RuleOffer} 分开声明(异源对抗复审 [medium] 采纳):`offerIndex` 是
162
197
  * **本包铸的座**(见 {@link RuleOffer} 顶注),把它写进 {@link ToolApprovalFrame.ruleOffers} 的
163
198
  * 入参型 = 要求宿主为一个上游根本不发的字段负责 —— 真实 7.46.0 帧会**类型不合**,宿主只能强转,
164
199
  * 或者自己伪造一个本该由窄读器按**当前这条腿**算出来的下标(而两条腿的下标语义还不一样)。
165
200
  * ⇒ 入参面(帧/行)用本形,出参面(卡入参)用带下标的归一形,两者刻意不互相赋值。
201
+ *
202
+ * 🔴 **0.58.0(B-025)两处补形**,与 sdk 8.2.0 的 `RuleOffer` 逐字对齐:
203
+ * · batch 成员改用判别联合 {@link RuleOfferBatchMember}(`command` | `directoryRead`);
204
+ * · batch 臂补 **additive** `uncoveredDetail?`(缺席合法 —— server 对坏形的座**只丢座不丢批**,
205
+ * 所以缺席**不是**「没有未覆盖段」;真源恒是 `uncoveredSegments` 那个 count)。
166
206
  */
167
207
  export type WireRuleOffer = {
168
208
  kind: 'single';
@@ -173,19 +213,21 @@ export type WireRuleOffer = {
173
213
  kind: 'batch';
174
214
  rules: readonly RuleOfferBatchMember[];
175
215
  uncoveredSegments: number;
216
+ uncoveredDetail?: readonly RuleOfferUncoveredDetail[];
176
217
  };
177
218
  /**
178
219
  * 一张审批卡上的**一个**「不再询问」选项(core 5.58.0 design/375 §3.1 的判别联合,server ≥7.46.0
179
220
  * 起在 `tool_approval` 帧 / `card_json` / durable park 行**三腿同形**发出)。
180
221
  *
181
- * ── 为什么本包自铸这个形(记账,不是偷懒)────────────────────────────────────────────────
182
- * 上游 wire 形的类型供给口是 `@sema-agent/sdk`,而 sdk 7.2.0(今天 npm 上的最新版)的
183
- * `ToolApprovalFrame` / `PendingCheckpoint` 上**只有退役键 `ruleSuggestions`**、没有 `RuleOffer`
184
- * 这个名字 —— `requiresRealApproval`(#283)/ 窗三键([4851])同形:**server 已真发、SDK 锚未跟**。
185
- * 照那两例的先例:先追 server,不等 SDK;键集侧进对账门的 `AHEAD_OF_ANCHOR` 带退出条件登记
186
- * (SDK 补上当天自红逼删)。语义来源锚 = engine 7.46.0 fixture 的
187
- * `@sema-agent/core/dist/core/permission-rule-model.d.ts`(`RuleOffer` 的逐字契约)+
188
- * `@sema-agent/server/dist/approval-card.d.ts`(两臂 zod 形与两条腿的下标语义)
222
+ * ── 为什么本包仍自铸这个形(记账,不是偷懒)──────────────────────────────────────────────
223
+ * **只为了多一位 `offerIndex`**。上游 wire 形的类型供给口 `@sema-agent/sdk` **8.2.0**
224
+ * 已经把 `RuleOffer` / `RuleOfferMatch` / `RuleOfferBatchMember` / `RuleOfferUncoveredDetail`
225
+ * 一起补齐(S-134 锚②)⇒ 本形的**每一个成员类型**都已改由 sdk 派生(见上面四条),本联合
226
+ * 只在两臂上各加一位本包铸的座。0.43.0–0.57.0 那段「先追 server 不等 SDK」的自铸记账随
227
+ * `AHEAD_OF_ANCHOR` `ruleOffers` 登记一起**在 0.58.0 退役**。
228
+ * 语义来源锚 = `@sema-agent/core` `dist/core/permission-rule-model.d.ts`(`RuleOffer` 逐字契约)+
229
+ * `@sema-agent/server` `dist/approval-card.d.ts`(两臂 zod 形与两条腿的下标语义)+
230
+ * sdk 8.2.0 `dist/resources/tool-approvals.d.ts`(同形的类型面锚)。
189
231
  *
190
232
  * ── `offerIndex` 是本包铸的座(上游形上没有这一位)──────────────────────────────────────
191
233
  * core 的契约原话:消费端丢掉不认识的成员时**必须保住每个留下来成员的原始 wire 下标**,做不到就
@@ -193,6 +235,8 @@ export type WireRuleOffer = {
193
235
  * 键就是**下标**(`persistRule.batchOfferIndex`)。本包的窄读器是**逐条丢坏的**(一条坏 offer 不该
194
236
  * 让另一条真 offer 消失,与 server `boundedRuleOffers` 同向),压紧就会让下标前移 ⇒ 人点的第 k 个
195
237
  * 与服务端兑的第 k 个指向两条不同规则。所以窄读时把**原始下标**显式记在这一位上,兑付时按它回报。
238
+ * ⚠️ **「逐条丢坏」是 offer 级的,不是成员级的**:一只 batch 里有一个 `kind` 不识的成员 ⇒ **整只
239
+ * batch 丢**(core design/382 §2.3 规范性降级臂,理由见 {@link RuleOfferBatchMember} 顶注)。
196
240
  * 🔴 `offerIndex` 的定义域 = 「本包在**这条腿上**收到的那个数组里的下标」:
197
241
  * · **活卡帧腿**(`ToolApprovalFrame.ruleOffers`):server 同步腿是纯前缀截、零逐条丢弃 ⇒ 它恒等于
198
242
  * core 的 offer index,**是**合法选择键,`surfaceToolApprovalFrameAndRespond` 按它回兑;
@@ -214,12 +258,19 @@ export type RuleOffer = {
214
258
  /** 见本联合顶注。**batch 臂的兑付就是按这个数**(文本不可抄:合取批没有单条文本)。 */
215
259
  offerIndex: number;
216
260
  /** 1..5 条逐段规则(段序,按规则文本去重)。勾这一项 = 对**全体成员**一次性说是,
217
- * 合取批**没有成员级选中**(要更窄的答案就选 single 臂或只批这一次)。 */
261
+ * 合取批**没有成员级选中**(要更窄的答案就选 single 臂或只批这一次)。
262
+ * 🔴 成员是判别联合({@link RuleOfferBatchMember}):`command` 臂带 `match`/`command`,
263
+ * `directoryRead` 臂带 `directory` 且**没有**那两位 —— 端渲之前先读 `kind`。 */
218
264
  rules: RuleOfferBatchMember[];
219
265
  /** 铸卡时刻的诚实余量披露:这批兑完之后,按当时的覆盖快照仍未被任何规则放行的段数。
220
266
  * 0 = 「兑完这批,这条复合命令在那份快照的口径下就全覆盖了」。它是**对铸卡快照的陈述**,
221
267
  * 不是长期保证(并发删规则会让它过时)。 */
222
268
  uncoveredSegments: number;
269
+ /** design/382 §3.5 **additive** 明细座(0.58.0 起透传)—— 逐段给闭三词集的因由。
270
+ * 🔴 **缺席 ≠ 「没有未覆盖段」**:server 对坏形的座**只丢座不丢批**,老引擎更是压根不铸;
271
+ * 真源恒是 {@link uncoveredSegments} 那个 count。在场时**行数不强制**等于 count
272
+ * (窄读器只丢坏行,不拿它反过来否决整只 batch —— additive 位绝不回头削弱既有位)。 */
273
+ uncoveredDetail?: readonly RuleOfferUncoveredDetail[];
223
274
  };
224
275
  /** 三选卡的原始决断(vendor 卡的三个选项 + abort + 表面失败)。allow_session=第 2 项
225
276
  * (vendor 产出非空 permissionUpdates:setMode acceptEdits / cwd 外 addDirectories)。 */
@@ -627,8 +678,8 @@ export interface ToolApprovalFrame {
627
678
  * 7.44 及更旧的引擎今天仍在场(pin 未抬的部署、混舰队)。新键在场时**本键整条不看**。
628
679
  * 包内出口只有 {@link ApprovalCardRequest.ruleOffers} 一个,消费端不感知这次换键。
629
680
  * 🔴 本键留在 interface 与 {@link TOOL_APPROVAL_FRAME_KEYS_MIRROR} 里**不是**遗留包袱:
630
- * SDK 7.2.0 的运行期锚 `TOOL_APPROVAL_FRAME_KEYS` 仍含它,删掉会让对账门的
631
- * SDK 锚的每个键本仓都有」当场红 —— 退役登记要等 SDK 跟着 server 一起退。
681
+ * SDK **8.2.0** 的运行期锚 `TOOL_APPROVAL_FRAME_KEYS` 仍含它(node 直读实证),删掉会让
682
+ * 对账门的「SDK 锚的每个键本仓都有」当场红 —— 退役登记要等 SDK 跟着 server 一起退。
632
683
  */
633
684
  ruleSuggestions?: RuleSuggestion[];
634
685
  /**
@@ -646,8 +697,10 @@ export interface ToolApprovalFrame {
646
697
  * 🔴 文本由 ENGINE 铸,不由客户端拼:single 臂回决只能把 `rule` **原样**报回
647
698
  * (`respond` 体 `persistRule.rule`,报表外文本 = server 拒 `rule_not_offered`);
648
699
  * batch 臂没有单条文本可抄,回决报**下标**(`respond` 体 `persistRule.batchOfferIndex`)。
649
- * 🔴 本键**领先** SDK 运行期锚一代(sdk 7.2.0 `TOOL_APPROVAL_FRAME_KEYS` 只有退役键
650
- * `ruleSuggestions`)⇒ 对账门(run-approval-frame-keys-test.mjs)AHEAD_OF_ANCHOR 带退出条件登记。
700
+ * **锚已追平(0.58.0 / sdk 8.2.0 提货,S-134 锚②)**:sdk 8.2.0 的运行期锚
701
+ * `TOOL_APPROVAL_FRAME_KEYS` **已含本键**(node 直读 18 项实证),对账门
702
+ * (run-approval-frame-keys-test.mjs)的 `AHEAD_OF_ANCHOR` 登记按它自己的退出条件
703
+ * **随本批删除** —— 0.43.0–0.57.0 那条「先追 server 不等 SDK」的领先记账到此结清。
651
704
  * 耐久路对偶 = `PendingCheckpoint.ruleOffers`(同契约、**下标语义不同**:那条腿 server 已逐条
652
705
  * 丢弃压紧过,且无兑付口 ⇒ 下标只是展示座),由 {@link surfaceFsApprovalAndDecide} 消费。
653
706
  */
@@ -767,7 +820,7 @@ export interface ToolApprovalFrame {
767
820
  * (帧 → {@link ApprovalCardRequest.inputHasBidi})。
768
821
  * 🔴 判据**不看 `message`**(引擎/策略写的说明文本,不是待执行输入)——两个来源折进一个布尔会让
769
822
  * 端无法判断该给哪一段加显形标记。
770
- * 🔴 本键**领先** SDK 运行期锚一代(sdk 7.2.0 尚无)⇒ 对账门 AHEAD_OF_ANCHOR 带退出条件登记。
823
+ * 🔴 本键**领先** SDK 运行期锚一代(sdk 8.2.0 仍无)⇒ 对账门 AHEAD_OF_ANCHOR 带退出条件登记。
771
824
  * 耐久路今天**无对偶**(server 7.46.0 的 `PendingCheckpoint`/`riskDescriptor` 均未声明本键;
772
825
  * server 侧那份在**卡内**,不是行上的键)⇒ durable 行 → 卡那条腿不 stamp。
773
826
  */
@@ -914,78 +967,38 @@ export interface RespondToolApprovalOpts {
914
967
  }
915
968
  export type RespondToolApprovalFn = (approvalId: string, decision: ToolApprovalRespondDecision, opts?: RespondToolApprovalOpts) => Promise<ToolApprovalRespondAck | void>;
916
969
  /**
917
- * respond 回执的**包内视图** —— sdk `ToolApprovalRespondAck` 的 additive 超集(#334,0.43.0)。
970
+ * respond 回执的**包内视图**。
918
971
  *
919
- * 为什么是超集而不是直接用 sdk 那个形:server 7.46.0 的兑付回执上有两个**规范文本回显位**,而
920
- * sdk 7.2.0 的 `ToolApprovalRespondAck` 声明里还没有它们( `ruleOffers` 同一次锚滞后)。缺这两位,
921
- * 「规则真正存成了什么样」在包边界上被吞掉 —— 而编辑臂的落盘文本**可能与人敲的原字节不同**
922
- * (core 会把 `Bash(adb *)` 规范成 `Bash(adb:*)`),批臂更是一次落多条。
923
- *
924
- * 🔴 **超集只加不改**:继承 sdk 那个形的每一位,语义与字节零改动;既有消费端读 `rulePersisted` /
925
- * `ruleRefusal` / `noteRecorded` 的写法一字不用动(返回型变宽对读方是源码兼容的)。
926
- * 🔴 sdk 锚补上这两位那天,本形按 `probeCause` 先例回收(直接用 sdk 形)。
972
+ * 🔴 **0.58.0(sdk 8.2.0 提货)起本形已按它自己写下的退役条款回收 —— 现在它就是 sdk
973
+ * `ToolApprovalRespondAck` 本身**(别名保留只为源码兼容,端 import 的名字一个都不用改)
974
+ * 0.43.0–0.57.0 它是一个 additive 超集,理由 = server ≤7.48.0 早已在回执上发的三位规范文本
975
+ * 回显(`persistedRule` / `persistedRules` / `persistedRuleAnchors`)当时**不在** sdk 声明里
976
+ * (与 `ruleOffers` 同一次锚滞后,§7d P-44 登记的那一族)。sdk 8.2.0 的 S-134 锚③把三位
977
+ * 一起补上(`dist/resources/tool-approvals.d.ts` `ToolApprovalRespondAck` 逐字在场)⇒
978
+ * 退役条件满足,超集不再有存在理由(留着 = 两份会各自漂的同名形)。
979
+ * 🔴 **判形与窄读一个字节没改**:{@link readToolApprovalRespondAck} 的每一条纪律照旧 ——
980
+ * 三位规范文本回显**整只判形**(半份清单/半份归属表比没有更坏)、单复数**同场即互斥矛盾**、
981
+ * 回显在场而 `rulePersisted !== true` 即自相矛盾、锚与清单**逐位置同文本**。上游补的是**类型**,
982
+ * 不是判官:wire 是 JSON,sdk 的 optional 声明是 server 的承诺不是本层的前提。
983
+ * 🔴 **锚缺席时端的呈现口径**(0.44.0 立,退役后仍然成立,故留在此处):`persistedRuleAnchors`
984
+ * 缺席(≤7.47 引擎)时本包对 `persistedRules` 做到的相关性只有 **id + decision + 基数**
985
+ * ({@link surfaceToolApprovalFrameAndRespond} 的臂相关性门)—— 基数抓得到「少报/多报」,
986
+ * **抓不到**「条数对但内容是另一批规则」。⇒ 那种情形下端要把它渲成「**引擎报告**落盘的规则」,
987
+ * **不是**「你刚才选的那批规则」。锚在场时限制解除(`offerIndex` 已把清单钉在用户真选的那只 offer 上)。
927
988
  */
928
- export interface ToolApprovalRespondAckView extends ToolApprovalRespondAck {
929
- /**
930
- * server ≥7.44(#340 编辑臂回显 `editedArmEcho`;7.46 沿用)——**编辑臂**兑付成功时,规则店里
931
- * **真正落盘**的那条规范文本。
932
- * 🔴 **界面要回显的是这一份,不是输入框里那一份**:core 会规范化人敲的拼写。
933
- * 只在编辑臂 ∧ 兑付成功 ∧ 落的是 single 时在场;候选臂/批臂/失败/老 server ⇒ 缺席(≠ 空串)。
934
- */
935
- persistedRule?: string;
936
- /**
937
- * server ≥7.46.0(design/377 批臂回执)——**批臂**兑付成功时落地的**全体**成员规范文本,
938
- * **展示序**(= batch offer 的成员序,壳逐条回显)。「落地」含 persisted 与 deduped 两种
939
- * (等价规则已在店 = 同意已生效)。
940
- * 🔴 **复数是契约不是巧合**:合取批一次授权多条规则,把它折成一条(或只报第一条)会让人以为
941
- * 自己只批了一条。非数组 / 含非串成员 / 空数组 ⇒ 整只降缺席(半份清单比没有清单更坏)。
942
- * 非批臂 / 兑付失败 / 老 server ⇒ 字段省略;**缺席 ≠ 空**。
943
- *
944
- * ✅ **P-39 已到货**(server 7.48.0,client-core 本批):上游补的 additive 锚 =
945
- * {@link ToolApprovalRespondAckView.persistedRuleAnchors}(每条带 `offerIndex` + `memberIndex`)。
946
- * 本注按 `probeCause` 先例跟批收紧 —— 下面这段记的是**锚缺席时**(≤7.47 引擎)仍然成立的残余:
947
- * 🔴 **锚缺席 ⇒ 逐条归属证不出**(异源对抗复审三轮 [medium] 登记的原始形)。那种情形下本包对这一位
948
- * 做到的相关性只有 **id + decision + 基数**({@link surfaceToolApprovalFrameAndRespond} 的臂相关性
949
- * 门):条数必须等于所选 batch 的成员数。基数抓得到「少报/多报」,**抓不到**「条数对但内容是
950
- * 另一批规则」—— 因为回执上没有任何锚能把这 N 条与那只 offer 对上(文本等式在这一位上不成立:
951
- * 落盘的是**规范化后**的文本,与 offer 上的文本按设计可以不同,拿文本去比就是装第二个判官)。
952
- * 🔴 ⇒ **锚缺席时端的呈现口径**:把它渲成「**引擎报告**落盘的规则」,**不是**「你刚才选的那批规则」。
953
- * 两句话在正常情形下指同一件事,但只有前一句是本包在无锚时能背书的。
954
- * **锚在场时**这条限制解除:`offerIndex` 已经把这份清单钉在用户真选的那只 offer 上。
955
- */
956
- persistedRules?: readonly string[];
957
- /**
958
- * server ≥7.48.0(P-39 正位解;#340/#334 批臂回执的**归属锚**)——批臂兑付成功时,每条落地规则
959
- * 与它**出自哪只 offer 的哪个成员**的对应关系。
960
- *
961
- * 直证(engine 7.48.0 fixture `@sema-agent/server/dist/tool-approval.js`):park 迟到腿 `:1360` 与
962
- * live 腿 `:1461` 两处逐字铸
963
- * `persistedRuleAnchors: persisted.members.map(m => ({ offerIndex: persistRule.batchOfferIndex,
964
- * memberIndex: m.memberIndex, rule: m.rule }))`。
965
- * 🔴 **载体是 respond 的 200 体**(与 `rulePersisted`/`persistedRules` 同级),**不是帧** ——
966
- * 所以它进的是本 ack 视图,不进 {@link TOOL_APPROVAL_FRAME_KEYS_MIRROR}。
967
- * 🔴 **只在批臂 ∧ 兑付成功 ∧ server 交得出 `members` 时在场**;单臂/失败/老 server ⇒ 缺席
968
- * (**缺席 ≠ 空数组**:空数组会被读成「一条都没落」)。
969
- * 🔴 **整只判形**(与 `persistedRules` 同族):坏形一律整只降缺席 —— 半份归属表比没有更坏,
970
- * 它驱动的断言是「这条规则出自**你选的那只批**」。判形见 {@link readPersistedRuleAnchors}。
971
- * 🔴 它**不替代** `persistedRules`:后者是展示序的规范文本清单(端逐条回显的那一份),
972
- * 本位是给**相关性门**用的归属证据。两位同场时条数必须一致,否则本位整只降缺席
973
- * (additive 位绝不回头削弱既有位的现行为)。
974
- */
975
- persistedRuleAnchors?: readonly PersistedRuleAnchor[];
976
- }
989
+ export type ToolApprovalRespondAckView = ToolApprovalRespondAck;
977
990
  /**
978
991
  * {@link ToolApprovalRespondAckView.persistedRuleAnchors} 的成员形(server 7.48.0 逐字三键)。
979
992
  *
993
+ * 🔴 **0.58.0 起直接是 sdk 8.2.0 的同名形**(S-134 锚③同批补;本包不再自铸)。此前本包自铸的
994
+ * 那份三键**逐字同形**,唯一差别是本包给三位钉了 `readonly` —— 别名化之后跟随 sdk 声明
995
+ * (读方源码兼容;本包自己的铸点仍只在 {@link readPersistedRuleAnchors} 一处,不外泄可写引用)。
996
+ *
980
997
  * `offerIndex` = 兑付时发出去的 `persistRule.batchOfferIndex`(整表同值 —— server 的 map 闭包捕获的
981
998
  * 就是那一个值);`memberIndex` = 该条在 batch offer 成员表里的下标;`rule` = **落盘后**的规范文本
982
999
  * (与 `persistedRules` 的同序成员同值;规范化是引擎的活,本包不复判文本)。
983
1000
  */
984
- export interface PersistedRuleAnchor {
985
- readonly offerIndex: number;
986
- readonly memberIndex: number;
987
- readonly rule: string;
988
- }
1001
+ export type PersistedRuleAnchor = SdkPersistedRuleAnchor;
989
1002
  /**
990
1003
  * respond 回执的**结构化读口**(wire 是 JSON:注入面可能是旧 liveClient 的 raw fetch,也可能是
991
1004
  * 比本包新一版的 SDK)。坏形一律降 `undefined` —— 与 `controlRouter.errCodes` 同族纪律:
@@ -1087,6 +1100,54 @@ export declare function readToolApprovalRespondRefusal(err: unknown): ToolApprov
1087
1100
  * `AgentEvent` 的臂了(durable 腿也回放),所以结构识别与 union 收窄两条路都成立;本函数仍按
1088
1101
  * 结构读(不依赖类型收窄),因为它同时服务 raw SSE 与 durable 回放两条入口。 */
1089
1102
  export declare function isToolApprovalFrame(ev: unknown): ev is ToolApprovalFrame;
1103
+ /**
1104
+ * `ruleOffers`(server ≥7.46.0 的判别联合)的结构读。
1105
+ *
1106
+ * 🔴 **[C228]/L-103(0.57.0)起本口是公面**(additive 导出,语义与字节一字未改)。此前它只经
1107
+ * **卡端口**({@link ApprovalCardRequest.ruleOffers})出包 —— 不走卡端口架构的宿主(浏览器端没有
1108
+ * Ink 三选卡,自己拿帧渲)只能在自己那边**重铸一遍**同一把窄读器,而这把窄读器承载的是
1109
+ * **兑付安全**判据(原始下标不前移、逐条丢坏、闭集 kind),重铸一次 = 多一份会各自漂的判官。
1110
+ * ⇒ 公面出口是「判定归包、呈现归端」在这一条腿上的兑现,不是便利函数。
1111
+ * 🔴 **两代 wire 键请走 {@link readRuleOfferSupply}**:本函数只读**新键**(server ≥7.46.0 的
1112
+ * `ruleOffers`);退役键 `ruleSuggestions`(server ≤7.45)的归一在那一口,两键的取舍序也在那里
1113
+ * (新键在场即定局,绝不混编)。手里只有新键才直接用本口。
1114
+ * 🔴 **`offerIndex` 的定义域随腿不同**,消费前必读 {@link RuleOffer} 顶注:活卡帧腿上它是合法
1115
+ * **选择键**(可当 `persistRule.batchOfferIndex` 回兑),durable 行腿上它只是展示/对账座
1116
+ * (server `boundedRuleOffers` 已压紧过一次)——**本函数不知道调用方在哪条腿上**,分辨是调用方的事。
1117
+ *
1118
+ * 🔴 **逐条丢坏、原始下标不前移**:坏 offer 逐条丢弃(一条坏的不该让另一条真的消失,与 server
1119
+ * `boundedRuleOffers` 同向),但留下来的每一条都带**原始 wire 下标** {@link RuleOffer.offerIndex} ——
1120
+ * core 的契约原话:做不到保住原始下标的消费端「must suppress its persistence actions entirely」,
1121
+ * 因为 `batch` 臂的兑付键就是下标。压紧 = 人点的第 k 个与服务端兑的第 k 个指向两条不同规则。
1122
+ * 🔴 `kind` 是**闭集判别位**:不认识的 kind ⇒ 丢这一条(不猜、不降级成 single)。
1123
+ * 全部不合形/非数组/超帽 ⇒ 整体缺席(卡不渲「不再询问」档)。
1124
+ */
1125
+ export declare function readRuleOffers(v: unknown): RuleOffer[] | undefined;
1126
+ /**
1127
+ * 两代 wire 供给 → **包内单一形**(#334/[5223],0.43.0):新键优先,新键整只读不出来才看旧键。
1128
+ *
1129
+ * 🔴 **[C228]/L-103(0.57.0)起本口是公面**(additive 导出,语义与字节一字未改;0.56.0 及更早的
1130
+ * 内部名是 `readOfferSupply`,**纯改名**没有第二个消费点)。宿主手里拿到的是**一整帧/一整行**,
1131
+ * 上面同时可能有 `ruleOffers`(新)与 `ruleSuggestions`(旧)两个键 —— 这一口是三端唯一该调的那个:
1132
+ * `readRuleOfferSupply(frame.ruleOffers, frame.ruleSuggestions)`。
1133
+ * 两代键的取舍序是**判据不是便利**(见下面两段红条),端各写一遍必然在 `null` 那一格上各错一遍。
1134
+ *
1135
+ * 🔴 **新键在场即定局,绝不混编**:新键**有载体**而读出空(数组在但全条坏形、或压根不是数组)
1136
+ * 也**不**回落旧键 —— 一台 7.46 引擎不会同时按两代形铸候选,拿旧键顶上去等于把一份异源素材
1137
+ * 冒充成这次 ask 的候选。
1138
+ *
1139
+ * 🔴 **`null` 与 `undefined` 同视为「新键缺席」**(异源对抗复审 [medium] 追问后的**明示裁定**,
1140
+ * 不是漏判):判据是**代价不对称**——
1141
+ * · 认 null 为缺席的失效面:一台 **7.46** 引擎把新键发成 `null` **且**同时发了旧键。这不可能
1142
+ * 发生:7.46 的三腿上旧键一个字都不铸(engine fixture 直证,同文件 0 命中)⇒ 回落读到的
1143
+ * 只会是 `undefined`,结果与「整只缺席」逐字节相同,没有异源素材可混;
1144
+ * · 认 null 为坏形的失效面:任何把「缺席」序列化成 `null` 的中转层(JSON 规范化包装器、
1145
+ * 某些 SQL/JSONB 读面、mock)会让**所有 ≤7.45 引擎**的「不再询问」档整段消失 —— 那正是
1146
+ * [5223] 这一批要修的病本身,只是换了个触发条件。
1147
+ * ⇒ 取「null == 缺席」。安全面上它**不新增**任何攻击面:一个能塞 `{ruleOffers:null, ruleSuggestions:[…]}`
1148
+ * 的注入面,同样能只塞 `{ruleSuggestions:[…]}`,而后者为了兼容 7.44 本来就必须收。
1149
+ */
1150
+ export declare function readRuleOfferSupply(offers: unknown, legacy: unknown): RuleOffer[] | undefined;
1090
1151
  /** 帧腿的宿主车道参数(#229 respond-note 批,0.29.0)。 */
1091
1152
  export interface ToolApprovalFrameLaneOpts {
1092
1153
  /**
@@ -1150,4 +1211,3 @@ export interface ToolApprovalFrameLaneOpts {
1150
1211
  windowIsCurrent?: boolean;
1151
1212
  }
1152
1213
  export declare function surfaceToolApprovalFrameAndRespond(frame: ToolApprovalFrame, respond: RespondToolApprovalFn, streamArgs: unknown | undefined, signal?: AbortSignal, lane?: ToolApprovalFrameLaneOpts): Promise<ToolApprovalFrameOutcome>;
1153
- export {};