@sema-agent/client-core 0.11.8 → 0.11.10

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.
package/README.md CHANGED
@@ -23,7 +23,9 @@ Renamed from **`@sema-agent/wire-cc-adapter`** (0.1.x, deprecated — see *Migra
23
23
 
24
24
  ## Scope
25
25
 
26
- - **Today (0.10.0)** — the adapter seam, the whole `adapt()` pipeline (all 14 A-layer arms plus the
26
+ **Version:** 0.11.10
27
+
28
+ - **Today** — the adapter seam, the whole `adapt()` pipeline (all 14 A-layer arms plus the
27
29
  B/D/E tool-card layers), the notification/caps/model families, the adapter kernel (stream driver
28
30
  + downstream projectors), the request-shaping surface **for both lanes** (interactive and the
29
31
  headless `-p` print lane), the fleet/panel projections and the subagent wire family, the workflow
@@ -39,9 +41,22 @@ Renamed from **`@sema-agent/wire-cc-adapter`** (0.1.x, deprecated — see *Migra
39
41
 
40
42
  ## Dependencies
41
43
 
42
- - **Zero runtime dependencies** (`"dependencies": {}`), `sideEffects: false`.
43
- - **Peer / type-only**: `@sema-agent/agent-types` owns the CC session vocabulary (today's only
44
- import `SDKMessage`, type-only), `@sema-agent/sdk` owns the wire contract.
44
+ - **Runtime dependencies:** `diff` (jsdiff 9 — zero transitive deps, pure JS, browser-safe). It is
45
+ the T20 client-side hunk computation; core ruled that hunks belong to the client, so keeping it
46
+ out of this package would mean three re-implementations (TUI / web / desktop). The portability
47
+ guard pins the runtime dependency set with an *equality* check, so this list cannot drift.
48
+ `sideEffects: false`.
49
+ - **Peers:**
50
+ - `@sema-agent/agent-types` — the CC session vocabulary (`SDKMessage` and friends). **Type-only**:
51
+ it ships no runtime code at all.
52
+ - `@sema-agent/sdk` — the wire contract. **Value-level, not type-only**: `AgentClient`,
53
+ `SseIdleError`, `probeHealth`, `APIError` and `TaskStopConflictError` are imported as values in
54
+ five modules, and the browser bundle really bundles the SDK through (the portability guard would
55
+ exit 3 rather than quietly mark it external).
56
+ - The declared floor is `>=0.1.9`, and it is *witnessed*: the guard checks that an actually
57
+ installed SDK at that line still exports every value-level symbol this package imports and still
58
+ declares `TaskStats.costMicroUsd` (the key `costOrNull` reads). A floor nobody ever ran is a
59
+ promise, not a contract.
45
60
  - The direction is constitutional: **sdk (wire) + agent-types (vocabulary) → this package**,
46
61
  and neither depends back.
47
62
 
@@ -181,13 +196,30 @@ both sides — what it records is why a compensation exists and when it can be d
181
196
 
182
197
  ```bash
183
198
  npm install
184
- node scripts/run-client-core-pure-test.mjs # 1058 consumer-view checks (22 + 140 + 208 + 59 + 101 + 96 + 241 + 163 + 28); no CLI tree needed
185
- node scripts/run-client-core-portability-test.mjs # 39 checks: kernel + A-layer + index closures, browser bundle
186
- node scripts/run-client-core-diff-test.mjs # 1397 checks: differential + replay-id + ledger
199
+ npm test # = node scripts/run-client-core-all-gates.mjs runs every suite below
187
200
  ```
188
201
 
202
+ `npm test` is a **collecting** runner, not a `&&` chain: a suite that exits 3 (SKIP, its material is
203
+ absent) does not short-circuit the ones after it, and the runner prints the three-part verdict
204
+ itself (FAILED names + skipped names + arithmetic reconciliation). All-SKIP reports exit 3, never 0.
205
+
206
+ | Suite | What it guards |
207
+ |---|---|
208
+ | `scripts/run-client-core-pure-test.mjs` | Consumer-view behaviour of every moved-in module; segment floors (B1–B8 + C) that only move up |
209
+ | `scripts/run-client-core-portability-test.mjs` | Kernel / A-layer / index import closures, the runtime-dependency equality gate, barrel reachability, and a real esbuild `--platform=browser` bundle |
210
+ | `scripts/run-client-core-diff-test.mjs` | Differential equivalence against the CLI reference bridge + replay-id invariant + ledger round-trip |
211
+ | `scripts/run-seat-contract-keys-test.mjs` | The seat IPC contract: verb list ↔ SPEC ↔ types, element-wise |
212
+ | `scripts/run-approval-frame-keys-test.mjs` | The tool-approval frame key mirror, element-wise against the SDK's runtime anchor |
213
+ | `scripts/run-print-bash-iserror-test.mjs` | The print lane's Bash `is_error` authority (structured over regex) |
214
+ | `scripts/run-sdk-floor-test.mjs` | The SDK version floor — and, more to the point, that the *installed* type declarations still carry the keys this package reads |
215
+ | `scripts/run-engine-vocab-floor-test.mjs` | Engine-mirrored vocabularies (structured card whitelist, self-reported tool face, control verbs, recogniser sets) against the *installed* `@sema-agent/core` |
216
+ | `scripts/run-public-surface-test.mjs` | The outward promises: the npm export surface baseline, the peer floor witness, and this README's claims |
217
+
189
218
  Each suite carries a floor that only moves up — a refactor that stops executing a group of
190
- assertions is a failure, not a quieter pass.
219
+ assertions is a failure, not a quieter pass. Guards anchor on the **installed artefact's content**
220
+ rather than on a version number, a directory name or a count: a version string can lie, a type
221
+ declaration cannot, and a count has no discriminating power when the content changes but the
222
+ cardinality does not.
191
223
 
192
224
  The portability guard walks the value-level import closure of the stream driver (asserting zero
193
225
  Node builtins, zero react, zero shell debug edge, closure size under its ceiling) and then really
@@ -19,15 +19,10 @@
19
19
  * is a ThinkingLevel (off|minimal|low|medium|high|xhigh|max); `auto` (let engine default), `ultracode` (a
20
20
  * separate mode, future slice), numeric and unset all OMIT — the engine then uses its own default.
21
21
  */
22
- const REASONING_EFFORTS = new Set([
23
- 'off',
24
- 'minimal',
25
- 'low',
26
- 'medium',
27
- 'high',
28
- 'xhigh',
29
- 'max',
30
- ]);
22
+ const REASONING_EFFORT_TUPLE = ['off', 'minimal', 'low', 'medium', 'high', 'xhigh', 'max'];
23
+ const _effortPins = [true, true];
24
+ void _effortPins;
25
+ const REASONING_EFFORTS = new Set(REASONING_EFFORT_TUPLE);
31
26
  /**
32
27
  * Project a picked `EffortValue` (string level | number | undefined) → the wire `reasoningEffort`, or
33
28
  * undefined to OMIT. Returns the value verbatim iff it is a core ThinkingLevel; everything else (auto,
@@ -130,6 +130,14 @@ export declare function deriveAgentLabel(agentType: string | undefined, agentNam
130
130
  *
131
131
  * 集合 = core `RESERVED_AGENT_NAMES`(subagent.ts)的 CC-parity PascalCase 形 + goal 模式的
132
132
  * `DeclareDone`。引擎 ≥ core 1.176 经 `canonicalToolName` 发 PascalCase。
133
+ *
134
+ * 🔴 [2006] A-CC-4(2026-07-29):此表此前**零门看守**,而 core 早已把子代委派工具改名成
135
+ * `Agent`(`DEFAULT_SUBAGENT_TOOL_NAME`;`Task`/`Fork` 退成 `OLD_TO_NEW` 旧名,`Fork` 还进了
136
+ * `TOMBSTONED_TOOLS`)。表里缺 `Agent` ⇒ 今天绝大多数 fleet 行的 description(引擎发的正是
137
+ * canonical 形 `Agent`)**压制不掉**,控制面动词照样泄漏进行正文 —— 正是本函数存在的理由被
138
+ * 静默架空。看守从此是 engine-vocab 门对**实装 core** `RESERVED_AGENT_NAMES` 的等值门;
139
+ * `Fork` 作为**登记旧名**保留(老引擎仍可能发;压制集多一个只多压制、不误伤真工具),
140
+ * 而"登记"本身要过门 —— 登记项必须是 core 认过的改名/墓碑词。
133
141
  */
134
142
  export declare const CONTROL_TOOL_VERBS: ReadonlySet<string>;
135
143
  /** 行的活动正文:控制面动词 ⇒ 空(187 从不显示它),否则原样。 */
@@ -82,8 +82,17 @@ export function deriveAgentLabel(agentType, agentName, name, id) {
82
82
  *
83
83
  * 集合 = core `RESERVED_AGENT_NAMES`(subagent.ts)的 CC-parity PascalCase 形 + goal 模式的
84
84
  * `DeclareDone`。引擎 ≥ core 1.176 经 `canonicalToolName` 发 PascalCase。
85
+ *
86
+ * 🔴 [2006] A-CC-4(2026-07-29):此表此前**零门看守**,而 core 早已把子代委派工具改名成
87
+ * `Agent`(`DEFAULT_SUBAGENT_TOOL_NAME`;`Task`/`Fork` 退成 `OLD_TO_NEW` 旧名,`Fork` 还进了
88
+ * `TOMBSTONED_TOOLS`)。表里缺 `Agent` ⇒ 今天绝大多数 fleet 行的 description(引擎发的正是
89
+ * canonical 形 `Agent`)**压制不掉**,控制面动词照样泄漏进行正文 —— 正是本函数存在的理由被
90
+ * 静默架空。看守从此是 engine-vocab 门对**实装 core** `RESERVED_AGENT_NAMES` 的等值门;
91
+ * `Fork` 作为**登记旧名**保留(老引擎仍可能发;压制集多一个只多压制、不误伤真工具),
92
+ * 而"登记"本身要过门 —— 登记项必须是 core 认过的改名/墓碑词。
85
93
  */
86
94
  export const CONTROL_TOOL_VERBS = new Set([
95
+ 'Agent',
87
96
  'Task',
88
97
  'Fork',
89
98
  'StructuredOutput',
@@ -30,8 +30,6 @@ import { type PermissionMode, type PermissionModeField } from './permissionWireC
30
30
  import { type EnvLike } from './hostEnv.js';
31
31
  /** 部署旋钮 env 键名(settings.json env 块 → 1a-envseed → process.env 同车道)。 */
32
32
  export declare const HEADLESS_PERMISSION_MODE_ENV = "SEMA_HEADLESS_PERMISSION_MODE";
33
- /** wire 词表(permissionWireCaps.PermissionMode 的运行时镜像;大小写敏感——与 CC flag choices 一致)。
34
- * 'auto'(分类器批3,[907]):server ≥1.209 五模式表认;老 server coerce 未知词 → "default" 只紧不松。 */
35
33
  export declare const HEADLESS_PERMISSION_WIRE_MODES: readonly PermissionMode[];
36
34
  export type HeadlessPermissionResolution = {
37
35
  /** 直接展开进 TaskRequest 的字段({} = 不 stamp,现状 absent-mode)。 */
@@ -32,13 +32,10 @@ import { hostEnv } from './hostEnv.js';
32
32
  export const HEADLESS_PERMISSION_MODE_ENV = 'SEMA_HEADLESS_PERMISSION_MODE';
33
33
  /** wire 词表(permissionWireCaps.PermissionMode 的运行时镜像;大小写敏感——与 CC flag choices 一致)。
34
34
  * 'auto'(分类器批3,[907]):server ≥1.209 五模式表认;老 server coerce 未知词 → "default" 只紧不松。 */
35
- export const HEADLESS_PERMISSION_WIRE_MODES = [
36
- 'default',
37
- 'plan',
38
- 'acceptEdits',
39
- 'bypassPermissions',
40
- 'auto',
41
- ];
35
+ const HEADLESS_PERMISSION_WIRE_MODE_TUPLE = ['default', 'plan', 'acceptEdits', 'bypassPermissions', 'auto'];
36
+ const _headlessPermissionModePins = [true, true];
37
+ void _headlessPermissionModePins;
38
+ export const HEADLESS_PERMISSION_WIRE_MODES = HEADLESS_PERMISSION_WIRE_MODE_TUPLE;
42
39
  /**
43
40
  * argv 里的 `--permission-mode <v>` / `--permission-mode=<v>`(后者/后出现者赢,commander 同语义)与
44
41
  * `--dangerously-skip-permissions`(= bypassPermissions;`--permission-mode` 在场时让位)。
@@ -8,8 +8,8 @@
8
8
  * 2. `require('../utils/messages.js').REJECT_MESSAGE` 的 lazy require + 内联字面量兜底
9
9
  * → 直接用常量 `HITL_REJECT_MESSAGE`(**逐字**同一串)。lazy require 存在的理由是「wire 模块
10
10
  * 别拉 React/ink 图」,在包里没有那张图 ⇒ 理由消失,只留常量。
11
- * 🔴 常量漂移锁:pure 门 B7 段拿壳树 `src/utils/messages.ts` 的 `REJECT_MESSAGE` 做
12
- * byte-identity 对拍(壳树缺席 ⇒ DEGRADED 打印,不假绿)。
11
+ * 🔴 常量锁(0.11.10 换锚):CC 原文在 pure 门 B7 段有**包内冻结字面量**(无条件,不依赖外部树);
12
+ * 壳树在场时再加一条**全树扫描**——壳里每一处 `REJECT_MESSAGE` 声明都必须逐字节等于它。
13
13
  * 3. `getAppStateStoreRef()` 直写 `AppState.notifications` → `HitlHostSurface` 口
14
14
  * (`showNotice` / `clearNoticeIfCurrent`)—— `AppState` 是**端的状态形状**。
15
15
  * 同理 `surfaceClassifierDeny`(footer 通知 + /permissions Recent Denials 记账,两者都是壳资产)
@@ -84,7 +84,7 @@ export declare function _resetHitlHostSurfaceForTest(): void;
84
84
  /**
85
85
  * CC `utils/messages.ts` 的 `REJECT_MESSAGE` **逐字**(搬迁差分 2)。deny 后重放 tool_end 的
86
86
  * render 面 stamp 用 —— vendored `renderToolUseRejectedMessage` 渲 `User rejected <op> to <path>`。
87
- * 🔴 与壳树那份的 byte-identity 由 pure 门 B7 段锁住(壳树缺席 ⇒ DEGRADED,不假绿)。
87
+ * 🔴 pure 门 B7 段:包内冻结字面量(无条件)+ 壳树全树扫描「每一处声明都逐字节相同」(壳树缺席=跳过)。
88
88
  */
89
89
  export declare const HITL_REJECT_MESSAGE = "The user doesn't want to proceed with this tool use. The tool use was rejected (eg. if it was a file edit, the new_string was NOT written to the file). STOP what you are doing and wait for the user to tell you how to proceed.";
90
90
  /** 本桥消费的 wire 面(@sema-ai/sdk AgentClient 的结构切片,mock 可注入)。 */
@@ -30,7 +30,7 @@ function surface() {
30
30
  /**
31
31
  * CC `utils/messages.ts` 的 `REJECT_MESSAGE` **逐字**(搬迁差分 2)。deny 后重放 tool_end 的
32
32
  * render 面 stamp 用 —— vendored `renderToolUseRejectedMessage` 渲 `User rejected <op> to <path>`。
33
- * 🔴 与壳树那份的 byte-identity 由 pure 门 B7 段锁住(壳树缺席 ⇒ DEGRADED,不假绿)。
33
+ * 🔴 pure 门 B7 段:包内冻结字面量(无条件)+ 壳树全树扫描「每一处声明都逐字节相同」(壳树缺席=跳过)。
34
34
  */
35
35
  export const HITL_REJECT_MESSAGE = "The user doesn't want to proceed with this tool use. The tool use was rejected (eg. if it was a file edit, the new_string was NOT written to the file). STOP what you are doing and wait for the user to tell you how to proceed.";
36
36
  function rejectMessageForRender() {
package/dist/index.d.ts CHANGED
@@ -45,7 +45,7 @@
45
45
  * ② **P4 残件三**:`hooksWireCaps`(SettingsPort 的第一个真消费者;port 缺席 = 整体 fail-closed)·
46
46
  * `liveInitToolFace`(凭证换 §8-2 的 `resolveWireAuth`,三条动态 import 转静态)·
47
47
  * **model 数据表**(`model/providerPresets.{ts,json}` + `modelFamilies.json` —— `modelBudgetRule`
48
- * 封顶① 的 `perModelCap` 的唯一来源;与壳树副本有 byte-identity 漂移锁);
48
+ * 封顶① 的 `perModelCap` 的唯一来源;单一真源三锚见 model/providerPresets.ts 头注);
49
49
  * ③ **P5**:T32/T34/T47/T48/T49(整条进包)与 T35/T36/T44(拆)逐条核实并配断言,新出
50
50
  * `compensations.ts` 登记表(自检口 `compensationSplitViolations()` 恒应为空)+ **P1-2 归属回落
51
51
  * 定案**(FIFO 回落**不删** = tolerate-absent 保护臂;typed 双键在场恒赢已成对反钉;退役条件
package/dist/index.js CHANGED
@@ -45,7 +45,7 @@
45
45
  * ② **P4 残件三**:`hooksWireCaps`(SettingsPort 的第一个真消费者;port 缺席 = 整体 fail-closed)·
46
46
  * `liveInitToolFace`(凭证换 §8-2 的 `resolveWireAuth`,三条动态 import 转静态)·
47
47
  * **model 数据表**(`model/providerPresets.{ts,json}` + `modelFamilies.json` —— `modelBudgetRule`
48
- * 封顶① 的 `perModelCap` 的唯一来源;与壳树副本有 byte-identity 漂移锁);
48
+ * 封顶① 的 `perModelCap` 的唯一来源;单一真源三锚见 model/providerPresets.ts 头注);
49
49
  * ③ **P5**:T32/T34/T47/T48/T49(整条进包)与 T35/T36/T44(拆)逐条核实并配断言,新出
50
50
  * `compensations.ts` 登记表(自检口 `compensationSplitViolations()` 恒应为空)+ **P1-2 归属回落
51
51
  * 定案**(FIFO 回落**不删** = tolerate-absent 保护臂;typed 双键在场恒赢已成对反钉;退役条件
@@ -250,7 +250,8 @@ export * from './hooksWireCaps.js';
250
250
  export * from './liveInitToolFace.js';
251
251
  // 🔴 model 数据表 —— `modelBudgetRule.defaultMaxTokensFor()` 的封顶① 参数 `perModelCap` 的**唯一**
252
252
  // 来源。表不在包里,那条中央规则在 web/桌面上恒拿不到 cap ⇒ 对 deepseek-chat(8192)这类模型
253
- // 超发 ⇒ 网关 400。搬迁期与壳树两份 JSON 由 pure 门的 byte-identity 断言锁住。
253
+ // 超发 ⇒ 网关 400。搬迁期那条「与壳树副本逐字节相等」的漂移锁 0.11.10 已退役(前提消失=僵尸腿),
254
+ // 继任锚:pure 门校 dist 与 src 语义等同 + 包内/壳树单一真源,public-surface 门校真实发布清单。
254
255
  export * from './model/providerPresets.js';
255
256
  // ── B7 批:HITL 族(2026-07-27,设计稿 §3 B7)────────────────────────────────────────────────
256
257
  // 🔴 `hitl/hitlBridge.ts` 里的 **D-1 两元组 verbatim 回显**是安全不变量(`bindingOf` 绝不重算
@@ -7,11 +7,15 @@
7
7
  * 在 web/桌面上**永远拿不到 cap**,`defaultMaxTokensFor(ctx)` 恒走 min(base, ctx/4),
8
8
  * 对 deepseek-chat(cap 8192)这类模型直接超发 ⇒ 网关 400。这不是「少个装饰」。
9
9
  *
10
- * 🔴 **两份副本的漂移锁**:搬迁期壳树那两个 JSON 还在(壳侧 shim 批之前 onboard 全族在读它),
11
- * 所以 pure 门加了一条 **byte-identity 断言**:本包 `src/model/*.json` 与壳树
12
- * `src/sema/onboard/*.json` 必须**逐字节相等**,任一侧加一行 provider 而另一侧没加即当场红。
13
- * 壳侧 shim 落地(那两个 JSON 删除、providerPresets.ts 改 re-export 本包)之后,该断言
14
- * 自动降为 SKIP(壳树缺席 = 搬完了),不会变成陈旧的假红。
10
+ * 🔴 **搬迁期的双份漂移锁已退役(0.11.10)**:搬迁期壳树那两个 JSON 还在,pure 门当时有一条
11
+ * **byte-identity 断言**(本包 `src/model/*.json` 与壳树 `src/sema/onboard/*.json` 逐字节相等)。
12
+ * 壳侧 shim 落地(那两个 JSON 删除、`providerPresets.ts` re-export 本包)之后,那条断言的
13
+ * **前提消失**了 —— 它从此每跑必打 DEGRADED 且**永远不会再跑**(校一个已经不存在的物,再自我
14
+ * 降级放过 = 僵尸腿)。继任不变量不是「两份一致」,是「**只有一份、而且用户拿到的就是它**」:
15
+ * · pure 门:`dist/model/*.json` 与 src **语义**等同(tsc emit 会重排缩进,跨 emit 边界只能校
16
+ * 语义)+ 运行时表的 id 序列 === 表本身 + src 树里各恰好一份 + 壳树零副本/shim 仍 re-export;
17
+ * · public-surface 门:`npm pack` 的**真实发布清单**里必须有这两个 JSON(换 bundler / 一行
18
+ * .npmignore 就能让数据表静悄悄不进 tarball,而类型与单测照样全绿)。
15
19
  *
16
20
  * ── 以下为原文件的领域说明(逐字保留)────────────────────────────────────────────────────────
17
21
  *
@@ -255,23 +255,10 @@ export interface StartSessionOptions {
255
255
  * ComposerMode 加一档而宿主闭集门不认的那天,红在编译期而不是用户提交那一刻。
256
256
  */
257
257
  export type PermissionModeIntent = "default" | "plan" | "acceptEdits" | "bypassPermissions" | "auto";
258
- /** The closed set the inbound gate checks. CLOSED deliberately, unlike `outcome` above: this word
259
- * ORIGINATES in our own renderer and goes OUT to a wire that 400s on anything else, so an unknown
260
- * value is a local bug we want reported at the door — not an unknown future wire word we must
261
- * tolerate. (The direction of travel is what decides open vs closed, not the field's shape.) */
262
258
  export declare const PERMISSION_MODE_INTENTS: readonly PermissionModeIntent[];
263
259
  /** Per-task attachment cap — the server's own limit (`attachmentIds` > 16 ⇒ 400). Gated here so the
264
260
  * seat gets a precise local error instead of a wire 400 halfway through a turn. */
265
261
  export declare const ATTACHMENT_IDS_PER_TASK_CAP = 16;
266
- /** The per-turn `reasoningEffort` accept-set — core's ThinkingLevel tiers, re-exported from the
267
- * package's own wire projection (`effortWire.ReasoningEffort`) rather than re-typed here.
268
- *
269
- * CLOSED for the same reason `PERMISSION_MODE_INTENTS` is: the word ORIGINATES in our own composer
270
- * and travels OUT to a wire that 400s (fail-loud) on an unknown tier — so an unknown value is a
271
- * local bug we want reported at the seat's door, not a future wire word to tolerate. `ultracode` is
272
- * deliberately NOT a tier here: in CC it is a standalone `settings.ultracode` preset boolean that
273
- * COEXISTS with `xhigh` (see `SeatTurnSettings`), and folding it into this axis is exactly how the
274
- * orchestration axis gets eaten by the reasoning axis. */
275
262
  export declare const SEAT_REASONING_EFFORTS: readonly ReasoningEffort[];
276
263
  /** The `settings` sub-object a seat turn may carry. A CLOSED set with its own name list + pin,
277
264
  * exactly like the top-level request: `SEND_MESSAGE_REQUEST_KEYS` checks `keyof SendMessageRequest`
@@ -118,13 +118,14 @@ export const CHROME_EVENT_KINDS = [
118
118
  * ORIGINATES in our own renderer and goes OUT to a wire that 400s on anything else, so an unknown
119
119
  * value is a local bug we want reported at the door — not an unknown future wire word we must
120
120
  * tolerate. (The direction of travel is what decides open vs closed, not the field's shape.) */
121
- export const PERMISSION_MODE_INTENTS = [
121
+ const PERMISSION_MODE_INTENT_TUPLE = [
122
122
  "default",
123
123
  "plan",
124
124
  "acceptEdits",
125
125
  "bypassPermissions",
126
126
  "auto",
127
127
  ];
128
+ export const PERMISSION_MODE_INTENTS = PERMISSION_MODE_INTENT_TUPLE;
128
129
  /** Per-task attachment cap — the server's own limit (`attachmentIds` > 16 ⇒ 400). Gated here so the
129
130
  * seat gets a precise local error instead of a wire 400 halfway through a turn. */
130
131
  export const ATTACHMENT_IDS_PER_TASK_CAP = 16;
@@ -137,7 +138,7 @@ export const ATTACHMENT_IDS_PER_TASK_CAP = 16;
137
138
  * deliberately NOT a tier here: in CC it is a standalone `settings.ultracode` preset boolean that
138
139
  * COEXISTS with `xhigh` (see `SeatTurnSettings`), and folding it into this axis is exactly how the
139
140
  * orchestration axis gets eaten by the reasoning axis. */
140
- export const SEAT_REASONING_EFFORTS = [
141
+ const SEAT_REASONING_EFFORT_TUPLE = [
141
142
  "off",
142
143
  "minimal",
143
144
  "low",
@@ -146,6 +147,7 @@ export const SEAT_REASONING_EFFORTS = [
146
147
  "xhigh",
147
148
  "max",
148
149
  ];
150
+ export const SEAT_REASONING_EFFORTS = SEAT_REASONING_EFFORT_TUPLE;
149
151
  export const SEAT_TURN_SETTINGS_KEYS = ["ultracode"];
150
152
  // ───────────────────────────── validators (CC dual-gate posture) ─────────────────────────────
151
153
  export function isLocalSessionRecord(s) {
@@ -423,5 +425,6 @@ const _seatContractPins = [
423
425
  true, true, true, true, true, true, true, true, true,
424
426
  true, true, true, true, true, true, true, true,
425
427
  true, true,
428
+ true, true, true, true,
426
429
  ];
427
430
  void _seatContractPins;
@@ -46,6 +46,11 @@ export const STRUCTURED_DETAIL_TYPES = new Set([
46
46
  'update',
47
47
  'bash',
48
48
  'notebook-edit',
49
+ // 🔴 [2006] A-CC-3(2026-07-29):`notebook` = Read 读 .ipynb 的投影卡(core RB-227,filePath +
50
+ // projected cells)。此前本表漏它而 core 照发 `tool_end.structured` ⇒ `structuredDetailType()`
51
+ // 返 undefined ⇒ 那张卡退回**正则解模型面文本**([assert-absence-check-fallback-layers] 同族)。
52
+ // 看守从「size===30 计数钉」换成对**实装 core** `CC_DETAIL_TYPES` 的等值门(engine-vocab 门)。
53
+ 'notebook',
49
54
  'text',
50
55
  'grep',
51
56
  'glob',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sema-agent/client-core",
3
- "version": "0.11.8",
3
+ "version": "0.11.10",
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",
@@ -20,6 +20,7 @@
20
20
  "sideEffects": false,
21
21
  "scripts": {
22
22
  "build": "tsc -p tsconfig.json",
23
+ "prepare": "npm run build",
23
24
  "test": "node scripts/run-client-core-all-gates.mjs"
24
25
  },
25
26
  "dependencies": {
@@ -27,7 +28,7 @@
27
28
  },
28
29
  "peerDependencies": {
29
30
  "@sema-agent/agent-types": ">=0.2.0",
30
- "@sema-agent/sdk": ">=0.1.0"
31
+ "@sema-agent/sdk": ">=0.1.9"
31
32
  },
32
33
  "devDependencies": {
33
34
  "@sema-agent/agent-types": "^0.2.0",