@sema-agent/client-core 0.74.2 → 0.74.4

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/dist/index.js CHANGED
@@ -202,6 +202,10 @@ export * from './mcpReconnect.js';
202
202
  export * from './leaderConflict.js';
203
203
  // 0.60.0(engine ≥7.64.0 / sdk 8.4.0):终局因由与门记录两只**判定归包**的读器。
204
204
  export * from './runTerminal.js';
205
+ // 0.74.3 CC-71:run 记录 cancelContext 读口 + turn_aborted{engine_error} 后的成因闭集四词(cli L-212 (a) 消费半场归包)
206
+ export * from './runCancelContext.js';
207
+ // 0.74.3 CC-80(core 交叉扫 X-5 / cli L-R1):argv 末次旗值扫描原语上公面 —— 包内四消费者早已收编,端还在造第 N 份手写循环
208
+ export * from './argvFlagValue.js';
205
209
  // 0.61.0(engine ≥7.65.0 / sdk 8.5.0 / S-167):READ 容纳面档位 + 来源的 operator 面窄读器
206
210
  // (`WiringDiagnostics.readFace`)。与 `writeProtectionCapability` / `gateOutcome` 同构同纪律
207
211
  // (防御读 / 唯一措辞铸点 / UNTRUSTED-for-display);与租户面 `capabilities.readFace` 刻意不合流,
@@ -438,6 +442,8 @@ export * from './model/providerPresets.js';
438
442
  // 共享宿主通知面 + cancel-by-deny 有界观察 —— `askGateWire.ts` 已 import `toolApprovalWire.ts`,
439
443
  // 反向 import 会成环,所以两条腿共用的那一组挪进一个两边都能到达的独立模块。
440
444
  export * from './hitl/hitlBridge.js';
445
+ // 0.74.3 CC-73:durable suspended.reopened 三态读口(cli L-56 ②)
446
+ export * from './hitl/suspendedReopen.js';
441
447
  // [C93] P0 直讨(0.17.1):toolEndOutputText 单一真源导出——web/desktop 被点名「两端务必接」的
442
448
  // 6.0.0 output content-block 归一,此前 frameRouter 内私有,两端手抄=漂移温床。frameRouter 只
443
449
  // 挑名导出这一件(整星导出会把路由内部面全泄进公面)。
@@ -6,7 +6,7 @@
6
6
  */
7
7
  import { hostEnv } from './hostEnv.js';
8
8
  import { unrefTimer } from './unrefTimer.js';
9
- import { clearEnginePanelTaskResident, publishEngineAgentPanelEvent, } from './engineAgentPanelStore.js';
9
+ import { clearEnginePanelTaskResidentByWire, publishEngineAgentPanelEvent, } from './engineAgentPanelStore.js';
10
10
  // L-215②(0.65.0;core [6908]):「非成功终局」的**单铸谓词** —— 面板 settle 的 `isError` 位与
11
11
  // 三端自己的后台白名单必须读同一个判据;内联一个 `=== 'failed' || === 'killed'` 就是第二份会漂的台账。
12
12
  import { isTaskNotificationTerminalStatus, isTerminalNotSuccess, isTerminalStatus } from './runTerminal.js';
@@ -922,7 +922,8 @@ export function enqueueBgChildNotification(n) {
922
922
  // 0.72.13(test 0.72.12 验收 ①;DS-06 同形存量):只对**通知自己的终态词**(completed / failed / killed / cancelled)settle 面板行。
923
923
  // 此前对任何 status 都铸 `end`,而 `isError: isTerminalNotSuccess(status)` 对 running / queued / event / 未来词答 false ⇒
924
924
  // 面板把一条还在跑 / 认不出状态的行结成 **completed** —— 该谓词的 JSDoc 明禁拿它的 false 当成功。非终态 ⇒ 不 settle、常驻标不摘。
925
- clearEnginePanelTaskResident(n.taskId);
925
+ // 0.74.4 CC-83:按 wire 词清 —— 尾段若归先发布的 UUID 所有,那把键下的常驻标一起清(主通道与常驻账同一把键)
926
+ clearEnginePanelTaskResidentByWire(n.taskId, typeof n.seq === 'number' && Number.isInteger(n.seq) && n.seq >= BG_FIRST_SEQ ? { cycleSeq: n.seq } : undefined);
926
927
  publishEngineAgentPanelEvent({
927
928
  kind: 'end',
928
929
  taskId: n.taskId,
@@ -0,0 +1,49 @@
1
+ /**
2
+ * runCancelContext — run 记录上 server 自铸的**取消现场**侧记键 `cancelContext`(server ≥7.87.3 `PersistedTaskResult =
3
+ * TaskResult & { cancelContext? }`,`dist/plugins/store-contracts.d.ts` `RunCancelContext` 四座)的三端共用读面,与
4
+ * `turn_aborted{reason:'engine_error'}` 之后「到底是谁把这条 run 结掉的」的**成因判定**(0.74.3 CC-71;cli L-212 (a) 消费半场归包)。
5
+ * sdk 9.7.1 对该键无型 ⇒ 按契约结构读。
6
+ *
7
+ * ── 🔴 读法 ─────────────────────────────────────────────────────────────────────────────────
8
+ * ① `cancelContext` 缺席 = 老 server / 这条 run 不是被取消的 / 记录形不带 —— **不折成「未取消」**,读数是 `not_reported`。
9
+ * ② 四座各自可缺席、各自防御读:`lastEventKind`(串)/ `lastEventAgeMs`(≥0 有限数)/ `elapsedMs`(≥0 有限数;绝不折 0)/
10
+ * `lastBrainStatus`(对象,原样带出不窄读)。「有 age 无 kind」是合法读数。
11
+ * ③ 成因判定 {@link classifyRunAbortCause}:只由 run 记录上的**机读证据**得出 —— `errorCode` ∈ 取消码 ⇒ `cancelled_by_user`;
12
+ * `cancelContext` 在场而码不是取消码 ⇒ 仍按码判(现场只是附注);码缺席 / 认不出 ⇒ `unknown`。**缺席不猜**。
13
+ */
14
+ /** 四座读数(在场才带)。 */
15
+ export interface RunCancelContextView {
16
+ readonly lastEventKind?: string;
17
+ readonly lastEventAgeMs?: number;
18
+ readonly elapsedMs?: number;
19
+ readonly lastBrainStatus?: Readonly<Record<string, unknown>>;
20
+ }
21
+ export type RunCancelContextReading = {
22
+ kind: 'not_reported';
23
+ } | {
24
+ kind: 'present';
25
+ context: RunCancelContextView;
26
+ };
27
+ /** run 记录(`runs.get` 回体 / `done.result`)→ 取消现场读数;记录非对象 ⇒ `undefined`(判不出,与 not_reported 分开)。 */
28
+ export declare function readRunCancelContext(record: unknown): RunCancelContextReading | undefined;
29
+ import { type RunTerminalRead } from './runTerminal.js';
30
+ export type RunAbortCause = {
31
+ kind: 'cancelled';
32
+ context?: RunCancelContextView;
33
+ } | {
34
+ kind: 'engine_error';
35
+ code?: string;
36
+ message?: string;
37
+ }
38
+ /** run 记录仍非终态:流断了而 run 还在(壳这一端的事实,不是 run 的成因)。`status` 原词。 */
39
+ | {
40
+ kind: 'run_still_live';
41
+ status?: string;
42
+ } | {
43
+ kind: 'unknown';
44
+ terminal?: RunTerminalRead['kind'];
45
+ };
46
+ /** 取消码常量(server `CANCELLED_CODE` / sdk runs.d.ts 逐字)。 */
47
+ export declare const RUN_CANCELLED_CODE: "cancelled";
48
+ /** 壳带 `engineTaskId` 去 `runs.get` 拿回的记录 ⇒ 成因。只由机读证据得出;缺席不猜。 */
49
+ export declare function classifyRunAbortCause(record: unknown): RunAbortCause;
@@ -0,0 +1,91 @@
1
+ /**
2
+ * runCancelContext — run 记录上 server 自铸的**取消现场**侧记键 `cancelContext`(server ≥7.87.3 `PersistedTaskResult =
3
+ * TaskResult & { cancelContext? }`,`dist/plugins/store-contracts.d.ts` `RunCancelContext` 四座)的三端共用读面,与
4
+ * `turn_aborted{reason:'engine_error'}` 之后「到底是谁把这条 run 结掉的」的**成因判定**(0.74.3 CC-71;cli L-212 (a) 消费半场归包)。
5
+ * sdk 9.7.1 对该键无型 ⇒ 按契约结构读。
6
+ *
7
+ * ── 🔴 读法 ─────────────────────────────────────────────────────────────────────────────────
8
+ * ① `cancelContext` 缺席 = 老 server / 这条 run 不是被取消的 / 记录形不带 —— **不折成「未取消」**,读数是 `not_reported`。
9
+ * ② 四座各自可缺席、各自防御读:`lastEventKind`(串)/ `lastEventAgeMs`(≥0 有限数)/ `elapsedMs`(≥0 有限数;绝不折 0)/
10
+ * `lastBrainStatus`(对象,原样带出不窄读)。「有 age 无 kind」是合法读数。
11
+ * ③ 成因判定 {@link classifyRunAbortCause}:只由 run 记录上的**机读证据**得出 —— `errorCode` ∈ 取消码 ⇒ `cancelled_by_user`;
12
+ * `cancelContext` 在场而码不是取消码 ⇒ 仍按码判(现场只是附注);码缺席 / 认不出 ⇒ `unknown`。**缺席不猜**。
13
+ */
14
+ function nonNegFinite(v) {
15
+ return typeof v === 'number' && Number.isFinite(v) && v >= 0 ? v : undefined;
16
+ }
17
+ /**
18
+ * 记录形两种:顶层 `result`(PersistedTaskResult)或已经是 result 本身。只有 `result` 长得像一份 run 结果(带 terminal / status /
19
+ * cancelContext 任一键)才下钻 —— `TaskResult` 自己也有个 `result` 键(今天是串),哪天成了对象也不该被当成结果记录(test [7702] §七 ④)。
20
+ */
21
+ function runResultHolder(r) {
22
+ const inner = r.result;
23
+ if (inner === null || typeof inner !== 'object' || Array.isArray(inner))
24
+ return r;
25
+ const o = inner;
26
+ return Object.hasOwn(o, 'terminal') || Object.hasOwn(o, 'status') || Object.hasOwn(o, 'cancelContext') ? o : r;
27
+ }
28
+ /** run 记录(`runs.get` 回体 / `done.result`)→ 取消现场读数;记录非对象 ⇒ `undefined`(判不出,与 not_reported 分开)。 */
29
+ export function readRunCancelContext(record) {
30
+ if (record === null || typeof record !== 'object')
31
+ return undefined;
32
+ const r = record;
33
+ // 记录形两种:顶层 `result.cancelContext`(PersistedTaskResult)或已经是 result 本身。
34
+ const holder = runResultHolder(r);
35
+ if (!Object.hasOwn(holder, 'cancelContext') || holder.cancelContext === undefined)
36
+ return { kind: 'not_reported' };
37
+ const c = holder.cancelContext;
38
+ if (c === null || typeof c !== 'object' || Array.isArray(c))
39
+ return undefined;
40
+ const o = c;
41
+ const kind = typeof o.lastEventKind === 'string' && o.lastEventKind.length > 0 ? o.lastEventKind : undefined;
42
+ const age = nonNegFinite(o.lastEventAgeMs);
43
+ const elapsed = nonNegFinite(o.elapsedMs);
44
+ const brain = o.lastBrainStatus !== null && typeof o.lastBrainStatus === 'object' && !Array.isArray(o.lastBrainStatus) ? o.lastBrainStatus : undefined;
45
+ return {
46
+ kind: 'present',
47
+ context: {
48
+ ...(kind !== undefined ? { lastEventKind: kind } : {}),
49
+ ...(age !== undefined ? { lastEventAgeMs: age } : {}),
50
+ ...(elapsed !== undefined ? { elapsedMs: elapsed } : {}),
51
+ ...(brain !== undefined ? { lastBrainStatus: brain } : {}),
52
+ },
53
+ };
54
+ }
55
+ // ── 成因判定(闭集四词;cli L-212 (a) 对齐)────────────────────────────────────────────────
56
+ //
57
+ // 字节出处(cli 亲 grep server 7.87.3 dist):
58
+ // · 被取消 = 唯一铸点 `run-cancel-context.js` `mintCancelledResult` ⇒ `terminal:{kind:"failed", code:"cancelled"}`,
59
+ // 且**只有这条路**挂 `cancelContext`;
60
+ // · 引擎错 = `terminal.kind === "failed"` 且 code !== "cancelled";code 是 core 的**开集**(network / brain.* / limits.* …)⇒ 只渲原码,不枚举;
61
+ // · 客户端断连**没有独立字节**:server 走的是 detach / park(durable run 继续跑、在等的 ask 停驻),run 记录不会因此失败 ⇒
62
+ // 它不是 run 的成因,是壳这一端的事实 —— 判法 = run 记录仍非终态(running / queued / suspended / needs_review)⇒ `run_still_live`。
63
+ // · 别的(完成 / 挡住 / 读不出终态词)⇒ `unknown`,不猜。
64
+ import { readRunTerminal } from './runTerminal.js';
65
+ /** 取消码常量(server `CANCELLED_CODE` / sdk runs.d.ts 逐字)。 */
66
+ export const RUN_CANCELLED_CODE = 'cancelled';
67
+ const LIVE_STATUSES = new Set(['running', 'queued', 'suspended', 'needs_review']);
68
+ /** 壳带 `engineTaskId` 去 `runs.get` 拿回的记录 ⇒ 成因。只由机读证据得出;缺席不猜。 */
69
+ export function classifyRunAbortCause(record) {
70
+ if (record === null || typeof record !== 'object')
71
+ return { kind: 'unknown' };
72
+ const r = record;
73
+ const status = typeof r.status === 'string' && r.status.length > 0 ? r.status : undefined;
74
+ const read = readRunTerminal(runResultHolder(r));
75
+ if (read !== null && read.kind === 'failed') {
76
+ if (read.code === RUN_CANCELLED_CODE) {
77
+ const cc = readRunCancelContext(record);
78
+ return { kind: 'cancelled', ...(cc?.kind === 'present' ? { context: cc.context } : {}) };
79
+ }
80
+ return { kind: 'engine_error', ...(read.code !== undefined ? { code: read.code } : {}), ...(read.message !== undefined ? { message: read.message } : {}) };
81
+ }
82
+ // 非终态 = run 还活着:嵌套 paused 臂 / 平面 paused 词 / 行上 status 仍是在飞词(平面读器对 running / queued 答 unknown{word},
83
+ // 那不是「读不出」,是「还没结」—— 所以先看 status 再落 unknown)。
84
+ if (read !== null && read.kind === 'paused')
85
+ return { kind: 'run_still_live', ...(status !== undefined ? { status } : {}) };
86
+ // 异源复审 R2 [medium]:result 已是终态(completed / blocked)而行上 status 还是在飞词 = 两处证据矛盾 ⇒ unknown(带观测到的终态词),
87
+ // 不按外层 status 说「还活着」——result 是终局记录,行状态可能滞后;矛盾不是 liveness 的证据。
88
+ if ((read === null || read.kind === 'unknown') && status !== undefined && LIVE_STATUSES.has(status))
89
+ return { kind: 'run_still_live', status };
90
+ return { kind: 'unknown', ...(read !== null ? { terminal: read.kind } : {}) };
91
+ }
@@ -173,8 +173,8 @@ export function sqlEngineDoctorDetail(reading) {
173
173
  switch (reading.kind) {
174
174
  case 'unobserved':
175
175
  // 0.59.2(cli B-038):不点名任何端的命令 —— 「去哪里看」是端的事,包只说事实。
176
- return ('not observed — the engine reports it on /v1/capabilities; this process has not received ' +
177
- 'a capabilities response from the engine yet');
176
+ return ('not observed — the engine reports it on /v1/capabilities; this process has no usable ' +
177
+ 'capabilities reading cached for it (none received, or the last one was unreadable)');
178
178
  case 'not_reported':
179
179
  return 'not reported by this engine — the capability position needs a newer engine';
180
180
  case 'none':
@@ -126,7 +126,7 @@ export function webSearchBackendDoctorDetail(reading) {
126
126
  switch (reading.kind) {
127
127
  case 'unobserved':
128
128
  return ('deployment default backend not observed — the engine reports it on /v1/capabilities; ' +
129
- 'this process has not received a capabilities response from the engine yet');
129
+ 'this process has no usable capabilities reading cached for it (none received, or the last one was unreadable)');
130
130
  case 'not_reported':
131
131
  return ('deployment default backend not reported by this engine — only newer engines advertise it; ' +
132
132
  'this does not say whether the deployment has a search backend');
@@ -176,8 +176,8 @@ const WP_DETAIL_MAX = 40;
176
176
  export function writeProtectionDoctorDetail(reading) {
177
177
  switch (reading.kind) {
178
178
  case 'unobserved':
179
- return ('not observed — the engine reports it on /v1/capabilities; this process has not received ' +
180
- 'a capabilities response from the engine yet');
179
+ return ('not observed — the engine reports it on /v1/capabilities; this process has no usable ' +
180
+ 'capabilities reading cached for it (none received, or the last one was unreadable)');
181
181
  case 'not_reported':
182
182
  return ('not reported by this engine — the capability position needs a newer engine; this says ' +
183
183
  'nothing about whether a protected-name table is in effect (an absent seat is the engine ' +