@zhushanwen/subagent-engine-sdk 0.10.0 → 0.11.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 (67) hide show
  1. package/dist/{chunk-AF2ETADP.js → chunk-2L3I2TWJ.js} +5 -10
  2. package/dist/{chunk-HSNDUHFH.js → chunk-3MCOZY3Z.js} +32 -4
  3. package/dist/{chunk-JZN76I3S.js → chunk-NVF3PADP.js} +29 -1
  4. package/dist/{chunk-LM7P7OTA.js → chunk-QBXDEF4N.js} +35 -3
  5. package/dist/{chunk-NTOLHLCL.js → chunk-QGXILDWB.js} +1 -1
  6. package/dist/{chunk-CT3FEBDO.js → chunk-QOFFM5YW.js} +7 -1
  7. package/dist/{chunk-CNCFMPEH.js → chunk-TJMS3YOR.js} +1 -1
  8. package/dist/{chunk-SGAIDL63.js → chunk-YFSNX3N3.js} +2 -2
  9. package/dist/cli-entry.d.cts +1 -1
  10. package/dist/cli-entry.d.ts +1 -1
  11. package/dist/{contract-types-jSa1g28F.d.cts → contract-types-BUHUMF9R.d.cts} +17 -17
  12. package/dist/{contract-types-jSa1g28F.d.ts → contract-types-BUHUMF9R.d.ts} +17 -17
  13. package/dist/env.cjs +5 -10
  14. package/dist/env.d.cts +6 -17
  15. package/dist/env.d.ts +6 -17
  16. package/dist/env.js +1 -1
  17. package/dist/{error-codes-f-UO4a8D.d.cts → error-codes-D_aPibUt.d.cts} +42 -6
  18. package/dist/{error-codes-DnFru4L4.d.ts → error-codes-DrNf0gwT.d.ts} +42 -6
  19. package/dist/index.cjs +133 -97
  20. package/dist/index.d.cts +29 -41
  21. package/dist/index.d.ts +29 -41
  22. package/dist/index.js +42 -59
  23. package/dist/journal-io.d.cts +1 -1
  24. package/dist/journal-io.d.ts +1 -1
  25. package/dist/journal-replay.cjs +2 -2
  26. package/dist/journal-replay.d.cts +4 -4
  27. package/dist/journal-replay.d.ts +4 -4
  28. package/dist/journal-replay.js +1 -1
  29. package/dist/kill-chain.d.cts +5 -5
  30. package/dist/kill-chain.d.ts +5 -5
  31. package/dist/kill-chain.js +2 -2
  32. package/dist/logger.d.cts +1 -1
  33. package/dist/logger.d.ts +1 -1
  34. package/dist/logs/stderr-rotation.d.cts +4 -4
  35. package/dist/logs/stderr-rotation.d.ts +4 -4
  36. package/dist/{methods-C2zvZqhP.d.ts → methods-BdIH3FwS.d.ts} +5 -5
  37. package/dist/{methods-BLxg4ZFr.d.cts → methods-CHiDwvRK.d.cts} +5 -5
  38. package/dist/node-executor.cjs +1 -1
  39. package/dist/node-executor.d.cts +4 -4
  40. package/dist/node-executor.d.ts +4 -4
  41. package/dist/node-executor.js +2 -2
  42. package/dist/port-contract.d.cts +9 -9
  43. package/dist/port-contract.d.ts +9 -9
  44. package/dist/protocol/index.cjs +73 -4
  45. package/dist/protocol/index.d.cts +57 -14
  46. package/dist/protocol/index.d.ts +57 -14
  47. package/dist/protocol/index.js +20 -2
  48. package/dist/server/index.cjs +1 -1
  49. package/dist/server/index.d.cts +10 -10
  50. package/dist/server/index.d.ts +10 -10
  51. package/dist/server/index.js +1 -1
  52. package/dist/spawn.cjs +32 -3
  53. package/dist/spawn.d.cts +34 -8
  54. package/dist/spawn.d.ts +34 -8
  55. package/dist/spawn.js +5 -3
  56. package/dist/ui-types.d.cts +2 -2
  57. package/dist/ui-types.d.ts +2 -2
  58. package/dist/zcode-db-paths.cjs +9 -2
  59. package/dist/zcode-db-paths.d.cts +11 -1
  60. package/dist/zcode-db-paths.d.ts +11 -1
  61. package/dist/zcode-db-paths.js +5 -3
  62. package/package.json +2 -2
  63. package/dist/chunk-GSW3DMN6.js +0 -39
  64. package/dist/relay-env.cjs +0 -71
  65. package/dist/relay-env.d.cts +0 -37
  66. package/dist/relay-env.d.ts +0 -37
  67. package/dist/relay-env.js +0 -23
@@ -5,14 +5,19 @@ import {
5
5
  PROTOCOL_METHODS,
6
6
  REVERSE_CHANNELS,
7
7
  REVERSE_CHANNEL_TIMEOUT_CLASS,
8
+ SUBAGENT_CONTROL_CLOSED_REASONS,
9
+ SUBAGENT_CONTROL_FRAME_KINDS,
10
+ SUBAGENT_CONTROL_PROTOCOL_VERSION,
8
11
  errorResponseFrameSchema,
12
+ isSubagentControlClosedReason,
13
+ isSubagentControlFrameKind,
9
14
  notificationFrameSchema,
10
15
  protocolErrorSchema,
11
16
  requestFrameSchema,
12
17
  reverseRequestFrameSchema,
13
18
  runSessionParamsSchema,
14
19
  successResponseFrameSchema
15
- } from "../chunk-LM7P7OTA.js";
20
+ } from "../chunk-QBXDEF4N.js";
16
21
  import {
17
22
  isNotificationFrame,
18
23
  isRequestFrame,
@@ -24,7 +29,11 @@ import {
24
29
  ENGINE_ERROR_CODE_PREFIX,
25
30
  ENGINE_PROTOCOL_ERROR_CODES,
26
31
  ENGINE_PROTOCOL_VERSION,
32
+ ENGINE_SPAWN_DELIVERY_ERROR_CODES,
33
+ ENGINE_SPAWN_DELIVERY_ERROR_RECOVERY,
27
34
  ENGINE_TIMEOUT_RECOVERY,
35
+ ENGINE_TRANSPORT_ERROR_CODES,
36
+ ENGINE_TRANSPORT_ERROR_RECOVERY,
28
37
  EngineSdkError,
29
38
  HANDSHAKE_TIMEOUT_MS,
30
39
  REVERSE_REQUEST_TIMEOUT_MS,
@@ -44,7 +53,7 @@ import {
44
53
  isEngineProtocolErrorCode,
45
54
  isProtocolVersionCompatible,
46
55
  schemaEmulationFailedDetail
47
- } from "../chunk-JZN76I3S.js";
56
+ } from "../chunk-NVF3PADP.js";
48
57
  import "../chunk-JSBRDJBE.js";
49
58
  export {
50
59
  AGENT_EVENT_TYPE_NAMES,
@@ -53,7 +62,11 @@ export {
53
62
  ENGINE_PROTOCOL_ERROR_CODES,
54
63
  ENGINE_PROTOCOL_SCHEMAS,
55
64
  ENGINE_PROTOCOL_VERSION,
65
+ ENGINE_SPAWN_DELIVERY_ERROR_CODES,
66
+ ENGINE_SPAWN_DELIVERY_ERROR_RECOVERY,
56
67
  ENGINE_TIMEOUT_RECOVERY,
68
+ ENGINE_TRANSPORT_ERROR_CODES,
69
+ ENGINE_TRANSPORT_ERROR_RECOVERY,
57
70
  EngineSdkError,
58
71
  FORBIDDEN_CREDENTIAL_KEY_FRAGMENTS,
59
72
  HANDSHAKE_TIMEOUT_MS,
@@ -67,6 +80,9 @@ export {
67
80
  SET_MODEL_STAGE_TIMEOUT_MS,
68
81
  STDERR_TAIL_CHARS,
69
82
  STDOUT_TAIL_ECHO_CHARS,
83
+ SUBAGENT_CONTROL_CLOSED_REASONS,
84
+ SUBAGENT_CONTROL_FRAME_KINDS,
85
+ SUBAGENT_CONTROL_PROTOCOL_VERSION,
70
86
  SUPPORTED_PROTOCOL_RANGE,
71
87
  assertChatConversationSupported,
72
88
  engineConversationUnsupportedError,
@@ -81,6 +97,8 @@ export {
81
97
  isRequestFrame,
82
98
  isResponseFrame,
83
99
  isReverseRequestFrame,
100
+ isSubagentControlClosedReason,
101
+ isSubagentControlFrameKind,
84
102
  notificationFrameSchema,
85
103
  protocolErrorSchema,
86
104
  requestFrameSchema,
@@ -88,7 +88,7 @@ var EngineSdkError = class extends Error {
88
88
  this.recovery = recovery;
89
89
  this.data = data;
90
90
  }
91
- /** 协议 error 帧载荷投影。 */
91
+ /** 协议 error 帧载荷派生视图。 */
92
92
  toStructured() {
93
93
  return { code: this.code, message: this.message, recovery: this.recovery, data: this.data };
94
94
  }
@@ -1,16 +1,16 @@
1
- import { b as AgentCallOpts, A as AgentEvent } from '../contract-types-jSa1g28F.cjs';
2
- import { E as EngineSdkError } from '../error-codes-f-UO4a8D.cjs';
3
- import { I as InitializeResult, R as RunContextParams, b as InitializeParams } from '../methods-BLxg4ZFr.cjs';
1
+ import { b as AgentCallOpts, A as AgentEvent } from '../contract-types-BUHUMF9R.cjs';
2
+ import { E as EngineSdkError } from '../error-codes-D_aPibUt.cjs';
3
+ import { I as InitializeResult, R as RunContextParams, b as InitializeParams } from '../methods-CHiDwvRK.cjs';
4
4
  import { ReverseRequestClock } from '../spawn.cjs';
5
5
  import 'node:child_process';
6
6
  import '../env.cjs';
7
7
 
8
- /** 出站帧写入面(各引擎 main.ts 注入 process.stdout;测试注入内存缓冲)。 */
8
+ /** 出站帧写侧(各引擎 main.ts 注入 process.stdout;测试注入内存缓冲)。 */
9
9
  type FrameWriter = (frame: unknown) => void;
10
10
  /**
11
- * 反向请求应答等待缺省上限(ms)——数据面分类 core 侧 10s,两阶段等待放宽一档兜底。
11
+ * 反向请求应答等待缺省上限(ms)——数据范围分类 core 侧 10s,两阶段等待放宽一档兜底。
12
12
  *
13
- * 两个引擎此值必须相同:它是「宿主应答迟到多久算超时」的协议面常数,分叉会让同一宿主
13
+ * 两个引擎此值必须相同:它是「宿主应答迟到多久算超时」的协议范围常数,分叉会让同一宿主
14
14
  * 在不同引擎下得到不同的超时语义。
15
15
  */
16
16
  declare const REVERSE_TIMEOUT_DEFAULT_MS = 60000;
@@ -22,8 +22,8 @@ interface ActiveRun {
22
22
  /**
23
23
  * 反向请求在途登记(引擎 → 宿主请求的应答等待项)。
24
24
  *
25
- * `method` 是 pi 引擎的扩展位(settle 时按通道守卫应答形态,如 askUser 的 UI 应答面
26
- * 检查);zcode 无该通道守卫,可缺省。
25
+ * `method` 是 pi 引擎的扩展位(settle 时按通道检查应答形态,如 askUser 的 UI 应答
26
+ * 检查);zcode 无该通道检查,可缺省。
27
27
  */
28
28
  interface ReversePending {
29
29
  resolve: (result: unknown) => void;
@@ -77,7 +77,7 @@ declare function reverseRequestRejection(method: string): {
77
77
  declare function unknownMethodError(id: number, method: string): EngineSdkError;
78
78
  /** 帧循环所需的最小上下文(引擎侧实现注入;每引擎构造一次,不在每帧重建)。 */
79
79
  interface FrameLoopContext {
80
- /** 出站帧写入面。 */
80
+ /** 出站帧写侧。 */
81
81
  write: FrameWriter;
82
82
  /** 反向应答帧落地(各引擎的两阶段 ack 语义在此,**刻意不统一**)。 */
83
83
  settleReverse(id: number | string, frame: {
@@ -107,7 +107,7 @@ interface ReverseRequestSendContext {
107
107
  clock?: ReverseRequestClock;
108
108
  /** 请求 id 分配(各引擎可带自己的前缀与计数器)。 */
109
109
  nextId(): string;
110
- /** 实现特有的 pending 附加字段(pi 记 `method` 供应答面检查用;zcode 不记)。 */
110
+ /** 实现特有的 pending 附加字段(pi 记 `method` 供应答侧检查用;zcode 不记)。 */
111
111
  pendingExtras?(method: string): Partial<ReversePending>;
112
112
  }
113
113
  declare function sendReverseRequest(ctx: ReverseRequestSendContext, method: string, params: unknown): Promise<unknown>;
@@ -1,16 +1,16 @@
1
- import { b as AgentCallOpts, A as AgentEvent } from '../contract-types-jSa1g28F.js';
2
- import { E as EngineSdkError } from '../error-codes-DnFru4L4.js';
3
- import { I as InitializeResult, R as RunContextParams, b as InitializeParams } from '../methods-C2zvZqhP.js';
1
+ import { b as AgentCallOpts, A as AgentEvent } from '../contract-types-BUHUMF9R.js';
2
+ import { E as EngineSdkError } from '../error-codes-DrNf0gwT.js';
3
+ import { I as InitializeResult, R as RunContextParams, b as InitializeParams } from '../methods-BdIH3FwS.js';
4
4
  import { ReverseRequestClock } from '../spawn.js';
5
5
  import 'node:child_process';
6
6
  import '../env.js';
7
7
 
8
- /** 出站帧写入面(各引擎 main.ts 注入 process.stdout;测试注入内存缓冲)。 */
8
+ /** 出站帧写侧(各引擎 main.ts 注入 process.stdout;测试注入内存缓冲)。 */
9
9
  type FrameWriter = (frame: unknown) => void;
10
10
  /**
11
- * 反向请求应答等待缺省上限(ms)——数据面分类 core 侧 10s,两阶段等待放宽一档兜底。
11
+ * 反向请求应答等待缺省上限(ms)——数据范围分类 core 侧 10s,两阶段等待放宽一档兜底。
12
12
  *
13
- * 两个引擎此值必须相同:它是「宿主应答迟到多久算超时」的协议面常数,分叉会让同一宿主
13
+ * 两个引擎此值必须相同:它是「宿主应答迟到多久算超时」的协议范围常数,分叉会让同一宿主
14
14
  * 在不同引擎下得到不同的超时语义。
15
15
  */
16
16
  declare const REVERSE_TIMEOUT_DEFAULT_MS = 60000;
@@ -22,8 +22,8 @@ interface ActiveRun {
22
22
  /**
23
23
  * 反向请求在途登记(引擎 → 宿主请求的应答等待项)。
24
24
  *
25
- * `method` 是 pi 引擎的扩展位(settle 时按通道守卫应答形态,如 askUser 的 UI 应答面
26
- * 检查);zcode 无该通道守卫,可缺省。
25
+ * `method` 是 pi 引擎的扩展位(settle 时按通道检查应答形态,如 askUser 的 UI 应答
26
+ * 检查);zcode 无该通道检查,可缺省。
27
27
  */
28
28
  interface ReversePending {
29
29
  resolve: (result: unknown) => void;
@@ -77,7 +77,7 @@ declare function reverseRequestRejection(method: string): {
77
77
  declare function unknownMethodError(id: number, method: string): EngineSdkError;
78
78
  /** 帧循环所需的最小上下文(引擎侧实现注入;每引擎构造一次,不在每帧重建)。 */
79
79
  interface FrameLoopContext {
80
- /** 出站帧写入面。 */
80
+ /** 出站帧写侧。 */
81
81
  write: FrameWriter;
82
82
  /** 反向应答帧落地(各引擎的两阶段 ack 语义在此,**刻意不统一**)。 */
83
83
  settleReverse(id: number | string, frame: {
@@ -107,7 +107,7 @@ interface ReverseRequestSendContext {
107
107
  clock?: ReverseRequestClock;
108
108
  /** 请求 id 分配(各引擎可带自己的前缀与计数器)。 */
109
109
  nextId(): string;
110
- /** 实现特有的 pending 附加字段(pi 记 `method` 供应答面检查用;zcode 不记)。 */
110
+ /** 实现特有的 pending 附加字段(pi 记 `method` 供应答侧检查用;zcode 不记)。 */
111
111
  pendingExtras?(method: string): Partial<ReversePending>;
112
112
  }
113
113
  declare function sendReverseRequest(ctx: ReverseRequestSendContext, method: string, params: unknown): Promise<unknown>;
@@ -8,7 +8,7 @@ import {
8
8
  import {
9
9
  ENGINE_PROTOCOL_VERSION,
10
10
  EngineSdkError
11
- } from "../chunk-JZN76I3S.js";
11
+ } from "../chunk-NVF3PADP.js";
12
12
  import "../chunk-JSBRDJBE.js";
13
13
 
14
14
  // src/server/index.ts
package/dist/spawn.cjs CHANGED
@@ -24,6 +24,7 @@ __export(spawn_exports, {
24
24
  ENGINE_ABORT_KILL_GRACE_MS: () => ENGINE_ABORT_KILL_GRACE_MS,
25
25
  ENGINE_HOST_REQUEST_TIMEOUT_ENV: () => ENGINE_HOST_REQUEST_TIMEOUT_ENV,
26
26
  armEngineSelfDestruct: () => armEngineSelfDestruct,
27
+ killOwnProcessGroup: () => killOwnProcessGroup,
27
28
  pumpNdjsonLines: () => pumpNdjsonLines,
28
29
  spawnEngineChild: () => spawnEngineChild
29
30
  });
@@ -232,13 +233,40 @@ function resolveHostRequestTimeoutMs(opts) {
232
233
  }
233
234
  return parsed;
234
235
  }
235
- function killOwnProcessGroup() {
236
+ function killOwnProcessGroup(deps = {}) {
236
237
  const pid = process.pid;
238
+ const kill = deps.killFn ?? ((targetPid, signal) => process.kill(targetPid, signal));
239
+ if ((deps.platform ?? process.platform) === "win32") {
240
+ const fallbackSelfKill = (reason) => {
241
+ logger2.warn(`taskkill self-tree failed (${reason}); falling back to self SIGKILL`);
242
+ try {
243
+ kill(pid, "SIGKILL");
244
+ } catch (err) {
245
+ logger2.warn(
246
+ `self SIGKILL fallback failed (${String(err)}); descendant pi may linger until runtime sweep`
247
+ );
248
+ }
249
+ };
250
+ const spawnFn = deps.spawnFn ?? ((command, args, options) => (0, import_node_child_process.spawn)(command, [...args], options));
251
+ try {
252
+ const child = spawnFn("taskkill", ["/PID", String(pid), "/T", "/F"], {
253
+ stdio: "ignore",
254
+ windowsHide: true
255
+ });
256
+ child.on("error", (err) => {
257
+ fallbackSelfKill(String(err));
258
+ });
259
+ child.unref?.();
260
+ } catch (err) {
261
+ fallbackSelfKill(`spawn threw: ${String(err)}`);
262
+ }
263
+ return;
264
+ }
237
265
  try {
238
- process.kill(-pid, "SIGKILL");
266
+ kill(-pid, "SIGKILL");
239
267
  } catch (err) {
240
268
  logger2.warn(`process-group kill failed (${String(err)}), falling back to self kill`);
241
- process.kill(pid, "SIGKILL");
269
+ kill(pid, "SIGKILL");
242
270
  }
243
271
  }
244
272
  function armEngineSelfDestruct(opts) {
@@ -307,6 +335,7 @@ function pumpNdjsonLines(stream, onLine) {
307
335
  ENGINE_ABORT_KILL_GRACE_MS,
308
336
  ENGINE_HOST_REQUEST_TIMEOUT_ENV,
309
337
  armEngineSelfDestruct,
338
+ killOwnProcessGroup,
310
339
  pumpNdjsonLines,
311
340
  spawnEngineChild
312
341
  });
package/dist/spawn.d.cts CHANGED
@@ -39,19 +39,19 @@ declare function spawnEngineChild(opts: SpawnEngineChildOptions): ChildProcess;
39
39
  declare const DEFAULT_ENGINE_HOST_REQUEST_TIMEOUT_MS = 30000;
40
40
  /** 计时超时覆盖 env 名(引擎 CLI 启动时读;非法值 warn + 回落缺省)。 */
41
41
  declare const ENGINE_HOST_REQUEST_TIMEOUT_ENV = "TAIJI_ENGINE_HOST_REQUEST_TIMEOUT_MS";
42
- /** 反向请求计时面操作接口(消费方 = 引擎 CLI 的反向通道分发层)。 */
42
+ /** 反向请求计时侧操作接口(消费方 = 引擎 CLI 的反向通道分发层)。 */
43
43
  interface ReverseRequestClock {
44
- /** 反向请求已发出(未 ack)——进入计时面。 */
44
+ /** 反向请求已发出(未 ack)——进入计时侧。 */
45
45
  started(id: string): void;
46
46
  /**
47
47
  * 收到 ack(两阶段第一阶段:已 ack 的 host/askUser、HostBridge.executeAndAwait
48
- * 的 ack)——移出计时面但不终结(R9-2:已 ack 的等待不计入 in-flight 超时,
48
+ * 的 ack)——移出计时侧但不终结(R9-2:已 ack 的等待不计入 in-flight 超时,
49
49
  * ADR-0047 静默 ≠ 卡死)。
50
50
  */
51
51
  acked(id: string): void;
52
52
  /** 请求终结(应答完成/失败/取消)——彻底移出。 */
53
53
  settled(id: string): void;
54
- /** 卸载守卫(引擎正常 shutdown 路径;自灭后幂等)。 */
54
+ /** 卸载检查(引擎正常 shutdown 路径;自灭后幂等)。 */
55
55
  dispose(): void;
56
56
  }
57
57
  interface EngineSelfDestructOptions {
@@ -64,14 +64,40 @@ interface EngineSelfDestructOptions {
64
64
  /** 自灭执行器(缺省 = 杀自己进程组再杀自己;测试注入用)。 */
65
65
  killSelf?: () => void;
66
66
  }
67
+ /** taskkill 子进程的最小面(self-destruct 是 fire-and-forget:只挂 error + unref)。 */
68
+ type KillOwnProcessGroupSpawnResult = {
69
+ on(event: "error", listener: (err: Error) => void): unknown;
70
+ unref?: () => void;
71
+ };
72
+ /** 自灭杀链依赖(缺省 = 真实 platform / spawn / process.kill;测试注入分支用)。 */
73
+ type KillOwnProcessGroupDeps = {
74
+ readonly platform?: NodeJS.Platform;
75
+ readonly spawnFn?: (command: string, args: readonly string[], options: {
76
+ readonly stdio: "ignore";
77
+ readonly windowsHide: boolean;
78
+ }) => KillOwnProcessGroupSpawnResult;
79
+ readonly killFn?: (pid: number, signal: NodeJS.Signals) => unknown;
80
+ };
67
81
  /**
68
- * 武装引擎侧自灭守卫。返回 ReverseRequestClock 给反向通道分发层登记请求生命周期。
82
+ * 缺省自灭:先杀自己进程组(收割引擎 spawn 的任务子进程),失败回落杀自己。
83
+ *
84
+ * 平台矩阵(设计 D7):POSIX = 负 pid 组杀;Windows 无进程组信号语义,用
85
+ * `taskkill /PID <self> /T /F` 树杀(stdio ignore + fire-and-forget,不阻塞自灭链)。
86
+ * Windows 分支在 taskkill 根本起不来(spawn 同步抛错,或 child 'error':PATH 缺
87
+ * System32 / EMFILE 等)时回落 `SIGKILL` 杀自己(R2A-N4):只杀自己是「可接受
88
+ * 降级」(后代 pi 交给 runtime sweep / 组登记),但引擎自身必须停住——否则引擎事件
89
+ * 循环仍有活句柄时宿主死后引擎与 pi 都不死,比原行为更差。两条失败路径都 warn 留痕。
90
+ * 依赖可注入 = 平台分支单测 seam(不实跑 Windows)。
91
+ */
92
+ declare function killOwnProcessGroup(deps?: KillOwnProcessGroupDeps): void;
93
+ /**
94
+ * 武装引擎侧自灭检查。返回 ReverseRequestClock 给反向通道分发层登记请求生命周期。
69
95
  *
70
96
  * 判据:
71
- * - 主判据 stdio EOF:stdin 'end'(数据面读尽)或 'close'(fd 关闭)→ 立即自灭
97
+ * - 主判据 stdio EOF:stdin 'end'(数据范围读尽)或 'close'(fd 关闭)→ 立即自灭
72
98
  * (宿主死后无人再写协议帧,引擎继续跑只烧 token);
73
99
  * - 辅助判据 in-flight 反向请求计时:未 ack 的反向请求超过 hostRequestTimeoutMs
74
- * 仍无 ack → 宿主大概率已死(EOF 未达或正在关闭)→ 自灭。**排除面**:已 ack 的
100
+ * 仍无 ack → 宿主大概率已死(EOF 未达或正在关闭)→ 自灭。**排除情形**:已 ack 的
75
101
  * host/askUser 与两阶段 ack 的长运行 HostBridge.executeAndAwait(ack 后等待任意
76
102
  * 时长合法,漏此项即「>30s pi 任务被自灭」turnTimeoutMs 同型事故)。
77
103
  *
@@ -88,4 +114,4 @@ declare function armEngineSelfDestruct(opts: EngineSelfDestructOptions): Reverse
88
114
  */
89
115
  declare function pumpNdjsonLines(stream: NodeJS.ReadableStream | null | undefined, onLine: (line: string) => void): void;
90
116
 
91
- export { DEFAULT_ENGINE_HOST_REQUEST_TIMEOUT_MS, ENGINE_ABORT_KILL_GRACE_MS, ENGINE_HOST_REQUEST_TIMEOUT_ENV, type EngineChildEnv, type EngineSelfDestructOptions, type ReverseRequestClock, type SpawnEngineChildOptions, armEngineSelfDestruct, pumpNdjsonLines, spawnEngineChild };
117
+ export { DEFAULT_ENGINE_HOST_REQUEST_TIMEOUT_MS, ENGINE_ABORT_KILL_GRACE_MS, ENGINE_HOST_REQUEST_TIMEOUT_ENV, type EngineChildEnv, type EngineSelfDestructOptions, type KillOwnProcessGroupDeps, type KillOwnProcessGroupSpawnResult, type ReverseRequestClock, type SpawnEngineChildOptions, armEngineSelfDestruct, killOwnProcessGroup, pumpNdjsonLines, spawnEngineChild };
package/dist/spawn.d.ts CHANGED
@@ -39,19 +39,19 @@ declare function spawnEngineChild(opts: SpawnEngineChildOptions): ChildProcess;
39
39
  declare const DEFAULT_ENGINE_HOST_REQUEST_TIMEOUT_MS = 30000;
40
40
  /** 计时超时覆盖 env 名(引擎 CLI 启动时读;非法值 warn + 回落缺省)。 */
41
41
  declare const ENGINE_HOST_REQUEST_TIMEOUT_ENV = "TAIJI_ENGINE_HOST_REQUEST_TIMEOUT_MS";
42
- /** 反向请求计时面操作接口(消费方 = 引擎 CLI 的反向通道分发层)。 */
42
+ /** 反向请求计时侧操作接口(消费方 = 引擎 CLI 的反向通道分发层)。 */
43
43
  interface ReverseRequestClock {
44
- /** 反向请求已发出(未 ack)——进入计时面。 */
44
+ /** 反向请求已发出(未 ack)——进入计时侧。 */
45
45
  started(id: string): void;
46
46
  /**
47
47
  * 收到 ack(两阶段第一阶段:已 ack 的 host/askUser、HostBridge.executeAndAwait
48
- * 的 ack)——移出计时面但不终结(R9-2:已 ack 的等待不计入 in-flight 超时,
48
+ * 的 ack)——移出计时侧但不终结(R9-2:已 ack 的等待不计入 in-flight 超时,
49
49
  * ADR-0047 静默 ≠ 卡死)。
50
50
  */
51
51
  acked(id: string): void;
52
52
  /** 请求终结(应答完成/失败/取消)——彻底移出。 */
53
53
  settled(id: string): void;
54
- /** 卸载守卫(引擎正常 shutdown 路径;自灭后幂等)。 */
54
+ /** 卸载检查(引擎正常 shutdown 路径;自灭后幂等)。 */
55
55
  dispose(): void;
56
56
  }
57
57
  interface EngineSelfDestructOptions {
@@ -64,14 +64,40 @@ interface EngineSelfDestructOptions {
64
64
  /** 自灭执行器(缺省 = 杀自己进程组再杀自己;测试注入用)。 */
65
65
  killSelf?: () => void;
66
66
  }
67
+ /** taskkill 子进程的最小面(self-destruct 是 fire-and-forget:只挂 error + unref)。 */
68
+ type KillOwnProcessGroupSpawnResult = {
69
+ on(event: "error", listener: (err: Error) => void): unknown;
70
+ unref?: () => void;
71
+ };
72
+ /** 自灭杀链依赖(缺省 = 真实 platform / spawn / process.kill;测试注入分支用)。 */
73
+ type KillOwnProcessGroupDeps = {
74
+ readonly platform?: NodeJS.Platform;
75
+ readonly spawnFn?: (command: string, args: readonly string[], options: {
76
+ readonly stdio: "ignore";
77
+ readonly windowsHide: boolean;
78
+ }) => KillOwnProcessGroupSpawnResult;
79
+ readonly killFn?: (pid: number, signal: NodeJS.Signals) => unknown;
80
+ };
67
81
  /**
68
- * 武装引擎侧自灭守卫。返回 ReverseRequestClock 给反向通道分发层登记请求生命周期。
82
+ * 缺省自灭:先杀自己进程组(收割引擎 spawn 的任务子进程),失败回落杀自己。
83
+ *
84
+ * 平台矩阵(设计 D7):POSIX = 负 pid 组杀;Windows 无进程组信号语义,用
85
+ * `taskkill /PID <self> /T /F` 树杀(stdio ignore + fire-and-forget,不阻塞自灭链)。
86
+ * Windows 分支在 taskkill 根本起不来(spawn 同步抛错,或 child 'error':PATH 缺
87
+ * System32 / EMFILE 等)时回落 `SIGKILL` 杀自己(R2A-N4):只杀自己是「可接受
88
+ * 降级」(后代 pi 交给 runtime sweep / 组登记),但引擎自身必须停住——否则引擎事件
89
+ * 循环仍有活句柄时宿主死后引擎与 pi 都不死,比原行为更差。两条失败路径都 warn 留痕。
90
+ * 依赖可注入 = 平台分支单测 seam(不实跑 Windows)。
91
+ */
92
+ declare function killOwnProcessGroup(deps?: KillOwnProcessGroupDeps): void;
93
+ /**
94
+ * 武装引擎侧自灭检查。返回 ReverseRequestClock 给反向通道分发层登记请求生命周期。
69
95
  *
70
96
  * 判据:
71
- * - 主判据 stdio EOF:stdin 'end'(数据面读尽)或 'close'(fd 关闭)→ 立即自灭
97
+ * - 主判据 stdio EOF:stdin 'end'(数据范围读尽)或 'close'(fd 关闭)→ 立即自灭
72
98
  * (宿主死后无人再写协议帧,引擎继续跑只烧 token);
73
99
  * - 辅助判据 in-flight 反向请求计时:未 ack 的反向请求超过 hostRequestTimeoutMs
74
- * 仍无 ack → 宿主大概率已死(EOF 未达或正在关闭)→ 自灭。**排除面**:已 ack 的
100
+ * 仍无 ack → 宿主大概率已死(EOF 未达或正在关闭)→ 自灭。**排除情形**:已 ack 的
75
101
  * host/askUser 与两阶段 ack 的长运行 HostBridge.executeAndAwait(ack 后等待任意
76
102
  * 时长合法,漏此项即「>30s pi 任务被自灭」turnTimeoutMs 同型事故)。
77
103
  *
@@ -88,4 +114,4 @@ declare function armEngineSelfDestruct(opts: EngineSelfDestructOptions): Reverse
88
114
  */
89
115
  declare function pumpNdjsonLines(stream: NodeJS.ReadableStream | null | undefined, onLine: (line: string) => void): void;
90
116
 
91
- export { DEFAULT_ENGINE_HOST_REQUEST_TIMEOUT_MS, ENGINE_ABORT_KILL_GRACE_MS, ENGINE_HOST_REQUEST_TIMEOUT_ENV, type EngineChildEnv, type EngineSelfDestructOptions, type ReverseRequestClock, type SpawnEngineChildOptions, armEngineSelfDestruct, pumpNdjsonLines, spawnEngineChild };
117
+ export { DEFAULT_ENGINE_HOST_REQUEST_TIMEOUT_MS, ENGINE_ABORT_KILL_GRACE_MS, ENGINE_HOST_REQUEST_TIMEOUT_ENV, type EngineChildEnv, type EngineSelfDestructOptions, type KillOwnProcessGroupDeps, type KillOwnProcessGroupSpawnResult, type ReverseRequestClock, type SpawnEngineChildOptions, armEngineSelfDestruct, killOwnProcessGroup, pumpNdjsonLines, spawnEngineChild };
package/dist/spawn.js CHANGED
@@ -3,12 +3,13 @@ import {
3
3
  ENGINE_ABORT_KILL_GRACE_MS,
4
4
  ENGINE_HOST_REQUEST_TIMEOUT_ENV,
5
5
  armEngineSelfDestruct,
6
+ killOwnProcessGroup,
6
7
  pumpNdjsonLines,
7
8
  spawnEngineChild
8
- } from "./chunk-HSNDUHFH.js";
9
- import "./chunk-CNCFMPEH.js";
9
+ } from "./chunk-3MCOZY3Z.js";
10
+ import "./chunk-TJMS3YOR.js";
10
11
  import "./chunk-PYO3YR7W.js";
11
- import "./chunk-JZN76I3S.js";
12
+ import "./chunk-NVF3PADP.js";
12
13
  import "./chunk-NXNNXGTY.js";
13
14
  import "./chunk-JSBRDJBE.js";
14
15
  export {
@@ -16,6 +17,7 @@ export {
16
17
  ENGINE_ABORT_KILL_GRACE_MS,
17
18
  ENGINE_HOST_REQUEST_TIMEOUT_ENV,
18
19
  armEngineSelfDestruct,
20
+ killOwnProcessGroup,
19
21
  pumpNdjsonLines,
20
22
  spawnEngineChild
21
23
  };
@@ -58,8 +58,8 @@ type UiResponse = {
58
58
  ack: true;
59
59
  };
60
60
  /** UiResponse 载荷结构判定(四成员判别;形态对齐 reverse-channels 的
61
- * isHostStreamDeltaParams 先例)。消费方:引擎侧应答落位前守卫,防宿主畸形帧
62
- * 静默流入 UI 队列(S7:askUser 应答跨界无守卫)。 */
61
+ * isHostStreamDeltaParams 先例)。消费方:引擎侧应答落位前检查,防宿主畸形帧
62
+ * 静默流入 UI 队列(S7:askUser 应答跨界无检查)。 */
63
63
  declare function isUiResponse(value: unknown): value is UiResponse;
64
64
  /** UI 请求 handler 签名(单函数,按 req.method 内部路由)。
65
65
  * 实现方负责:channel 业务路由(ask_user → AskUserComponent)+ 默认转发(ctx.ui.*)。
@@ -58,8 +58,8 @@ type UiResponse = {
58
58
  ack: true;
59
59
  };
60
60
  /** UiResponse 载荷结构判定(四成员判别;形态对齐 reverse-channels 的
61
- * isHostStreamDeltaParams 先例)。消费方:引擎侧应答落位前守卫,防宿主畸形帧
62
- * 静默流入 UI 队列(S7:askUser 应答跨界无守卫)。 */
61
+ * isHostStreamDeltaParams 先例)。消费方:引擎侧应答落位前检查,防宿主畸形帧
62
+ * 静默流入 UI 队列(S7:askUser 应答跨界无检查)。 */
63
63
  declare function isUiResponse(value: unknown): value is UiResponse;
64
64
  /** UI 请求 handler 签名(单函数,按 req.method 内部路由)。
65
65
  * 实现方负责:channel 业务路由(ask_user → AskUserComponent)+ 默认转发(ctx.ui.*)。
@@ -21,13 +21,20 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  var zcode_db_paths_exports = {};
22
22
  __export(zcode_db_paths_exports, {
23
23
  ZCODE_HOST_DB_SUFFIX: () => ZCODE_HOST_DB_SUFFIX,
24
- ZCODE_ISOLATED_DB_SEGMENTS: () => ZCODE_ISOLATED_DB_SEGMENTS
24
+ ZCODE_ISOLATED_DB_SEGMENTS: () => ZCODE_ISOLATED_DB_SEGMENTS,
25
+ ZCODE_PI_SYNCED_PROVIDER_CONFIG_SEGMENTS: () => ZCODE_PI_SYNCED_PROVIDER_CONFIG_SEGMENTS
25
26
  });
26
27
  module.exports = __toCommonJS(zcode_db_paths_exports);
27
28
  var ZCODE_HOST_DB_SUFFIX = [".zcode", "cli", "db", "db.sqlite"];
28
29
  var ZCODE_ISOLATED_DB_SEGMENTS = ["engines", "zcode", "session-db", "db.sqlite"];
30
+ var ZCODE_PI_SYNCED_PROVIDER_CONFIG_SEGMENTS = [
31
+ "engines",
32
+ "zcode",
33
+ "pi-synced-provider-config.json"
34
+ ];
29
35
  // Annotate the CommonJS export names for ESM import in node:
30
36
  0 && (module.exports = {
31
37
  ZCODE_HOST_DB_SUFFIX,
32
- ZCODE_ISOLATED_DB_SEGMENTS
38
+ ZCODE_ISOLATED_DB_SEGMENTS,
39
+ ZCODE_PI_SYNCED_PROVIDER_CONFIG_SEGMENTS
33
40
  });
@@ -11,5 +11,15 @@ declare const ZCODE_HOST_DB_SUFFIX: readonly [".zcode", "cli", "db", "db.sqlite"
11
11
  * 之外——池 TTL 清理不得触及会话库(设计 D1/F11)。
12
12
  */
13
13
  declare const ZCODE_ISOLATED_DB_SEGMENTS: readonly ["engines", "zcode", "session-db", "db.sqlite"];
14
+ /**
15
+ * taiji 同步副本相对段(`<dataDir>/engines/zcode/pi-synced-provider-config.json`,
16
+ * 绝对路径 = join(dataDir, ...segments)):runtime 启动段把 pi 侧 provider 映射落盘
17
+ * 的合并副本(唯一写方 = runtime provider 同步模块 zcode-provider-sync-wiring.ts,
18
+ * 读侧另一处 = session-records.ts zcodeModelListPaths 缺省拼装;引擎读侧 =
19
+ * zcode-subagent-cli preparer.ts 个人 provider 解析链——副本存在即用之,缺失回落
20
+ * 真实 `~/.zcode/v2/provider_config.json`)。与 ZCODE_ISOLATED_DB_SEGMENTS 同族:
21
+ * 同以 dataDir 为 join 根的 dataDir 相对段(区别于 homedir 根的 _SUFFIX 常量)。
22
+ */
23
+ declare const ZCODE_PI_SYNCED_PROVIDER_CONFIG_SEGMENTS: readonly ["engines", "zcode", "pi-synced-provider-config.json"];
14
24
 
15
- export { ZCODE_HOST_DB_SUFFIX, ZCODE_ISOLATED_DB_SEGMENTS };
25
+ export { ZCODE_HOST_DB_SUFFIX, ZCODE_ISOLATED_DB_SEGMENTS, ZCODE_PI_SYNCED_PROVIDER_CONFIG_SEGMENTS };
@@ -11,5 +11,15 @@ declare const ZCODE_HOST_DB_SUFFIX: readonly [".zcode", "cli", "db", "db.sqlite"
11
11
  * 之外——池 TTL 清理不得触及会话库(设计 D1/F11)。
12
12
  */
13
13
  declare const ZCODE_ISOLATED_DB_SEGMENTS: readonly ["engines", "zcode", "session-db", "db.sqlite"];
14
+ /**
15
+ * taiji 同步副本相对段(`<dataDir>/engines/zcode/pi-synced-provider-config.json`,
16
+ * 绝对路径 = join(dataDir, ...segments)):runtime 启动段把 pi 侧 provider 映射落盘
17
+ * 的合并副本(唯一写方 = runtime provider 同步模块 zcode-provider-sync-wiring.ts,
18
+ * 读侧另一处 = session-records.ts zcodeModelListPaths 缺省拼装;引擎读侧 =
19
+ * zcode-subagent-cli preparer.ts 个人 provider 解析链——副本存在即用之,缺失回落
20
+ * 真实 `~/.zcode/v2/provider_config.json`)。与 ZCODE_ISOLATED_DB_SEGMENTS 同族:
21
+ * 同以 dataDir 为 join 根的 dataDir 相对段(区别于 homedir 根的 _SUFFIX 常量)。
22
+ */
23
+ declare const ZCODE_PI_SYNCED_PROVIDER_CONFIG_SEGMENTS: readonly ["engines", "zcode", "pi-synced-provider-config.json"];
14
24
 
15
- export { ZCODE_HOST_DB_SUFFIX, ZCODE_ISOLATED_DB_SEGMENTS };
25
+ export { ZCODE_HOST_DB_SUFFIX, ZCODE_ISOLATED_DB_SEGMENTS, ZCODE_PI_SYNCED_PROVIDER_CONFIG_SEGMENTS };
@@ -1,9 +1,11 @@
1
1
  import {
2
2
  ZCODE_HOST_DB_SUFFIX,
3
- ZCODE_ISOLATED_DB_SEGMENTS
4
- } from "./chunk-CT3FEBDO.js";
3
+ ZCODE_ISOLATED_DB_SEGMENTS,
4
+ ZCODE_PI_SYNCED_PROVIDER_CONFIG_SEGMENTS
5
+ } from "./chunk-QOFFM5YW.js";
5
6
  import "./chunk-JSBRDJBE.js";
6
7
  export {
7
8
  ZCODE_HOST_DB_SUFFIX,
8
- ZCODE_ISOLATED_DB_SEGMENTS
9
+ ZCODE_ISOLATED_DB_SEGMENTS,
10
+ ZCODE_PI_SYNCED_PROVIDER_CONFIG_SEGMENTS
9
11
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zhushanwen/subagent-engine-sdk",
3
- "version": "0.10.0",
3
+ "version": "0.11.0",
4
4
  "description": "Engine-side SDK for the subagent engine protocol: NDJSON stdio contract types, engine primitives (schema emulation, nesting guard, kill chain, journal replay projection, data-dir/paths resolution) — the shared contract root between subagent-core and engine CLI packages (engines import SDK only, never core)",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -45,7 +45,7 @@
45
45
  "default": "./dist/server/index.js"
46
46
  }
47
47
  },
48
- "$comment": "W1 骨架(docs/design/subagent-engine-protocolization.impl-plan.md §2.1)。双形态同 subagent-core 先例(D4):workspace 消费走 import 条件 -> src;npm 消费走 publishConfig -> dist。exports 面先收窄到 ./ 与 ./protocol(exports = semver 契约,收窄不放宽;引擎包 W5/W7 消费经主 barrel)。协议版本独立于包版本:ENGINE_PROTOCOL_VERSION = 1(src/protocol/engine-protocol.ts)。不变量:本包禁止 import @zhushanwen/subagent-core(守卫 .githooks/check-engine-sdk-boundary.mjs)。src/env.ts 与 src/spawn.ts 是 W12 领地(impl-plan §2.12),本单元仅空骨架占位。tsup entry 逐模块具名登记(§2.1 末行),新增模块必须同步登记。files 不含 src/(对齐 subagent-core 2026-09-16 同型收敛):npm 消费面经 publishConfig 整体替换后全指 dist,TS 源仅服务 workspace(node_modules symlink 直读磁盘源文件,不经 tarball);dist 产物无 sourcemap/sourceMappingURL,移除 src 零断链。已知残留:顶层 main(src/index.ts,workspace 形态载体)被 npm files 规则强制隐含打进 tarball,对 npm 消费者不可达,纯体积噪声。",
48
+ "$comment": "W1 骨架(docs/design/subagent-engine-protocolization.impl-plan.md §2.1)。双形态同 subagent-core 先例(D4):workspace 消费走 import 条件 -> src;npm 消费走 publishConfig -> dist。exports 面先收窄到 ./ 与 ./protocol(exports = semver 契约,收窄不放宽;引擎包 W5/W7 消费经主 barrel)。协议版本独立于包版本:ENGINE_PROTOCOL_VERSION = 1(src/protocol/engine-protocol.ts)。不变量:本包禁止 import @zhushanwen/subagent-core(检查 .githooks/check-engine-sdk-boundary.mjs)。src/env.ts 与 src/spawn.ts 是 W12 领地(impl-plan §2.12),本单元仅空骨架占位。tsup entry 逐模块具名登记(§2.1 末行),新增模块必须同步登记。files 不含 src/(对齐 subagent-core 2026-09-16 同型收敛):npm 消费方经 publishConfig 整体替换后全指 dist,TS 源仅服务 workspace(node_modules symlink 直读磁盘源文件,不经 tarball);dist 产物无 sourcemap/sourceMappingURL,移除 src 零断链。已知残留:顶层 main(src/index.ts,workspace 形态载体)被 npm files 规则强制隐含打进 tarball,对 npm 消费者不可达,纯体积噪声。",
49
49
  "files": [
50
50
  "dist/"
51
51
  ],
@@ -1,39 +0,0 @@
1
- // src/relay-env.ts
2
- var RELAY_ENV_SOCKET = "TAIJI_SUBAGENT_RELAY_SOCKET";
3
- var RELAY_ENV_NODE = "TAIJI_SUBAGENT_RELAY_NODE";
4
- var RELAY_ENV_SCRIPT = "TAIJI_SUBAGENT_RELAY_SCRIPT";
5
- var RELAY_ENV_SESSION_ID = "TAIJI_SUBAGENT_RELAY_SESSION_ID";
6
- var RELAY_ENV_RECORD_ID = "TAIJI_SUBAGENT_RELAY_RECORD_ID";
7
- var RELAY_PROTOCOL_VERSION = 1;
8
- var RELAY_EXIT_CODES = {
9
- /** 握手被拒:协议版本不匹配(安装损坏,重装应用)。 */
10
- VERSION_MISMATCH: 10,
11
- /** relay socket 不可达(runtime 未运行或已重启)。 */
12
- SOCKET_UNREACHABLE: 11,
13
- /** socket 中途断开(runtime 崩溃等)——代理生命线断即退。 */
14
- SOCKET_CLOSED: 12,
15
- /** 归属 env(SESSION_ID/RECORD_ID)缺失——防无归属帧污染广播。 */
16
- MISSING_IDENTITY: 13
17
- };
18
- function isRelayActive(env) {
19
- return Boolean(env[RELAY_ENV_SOCKET] && env[RELAY_ENV_NODE] && env[RELAY_ENV_SCRIPT]);
20
- }
21
- function readRelayForwardEnv(env) {
22
- const socket = env[RELAY_ENV_SOCKET];
23
- const node = env[RELAY_ENV_NODE];
24
- const script = env[RELAY_ENV_SCRIPT];
25
- if (!isRelayActive(env)) return void 0;
26
- return { socket, node, script };
27
- }
28
-
29
- export {
30
- RELAY_ENV_SOCKET,
31
- RELAY_ENV_NODE,
32
- RELAY_ENV_SCRIPT,
33
- RELAY_ENV_SESSION_ID,
34
- RELAY_ENV_RECORD_ID,
35
- RELAY_PROTOCOL_VERSION,
36
- RELAY_EXIT_CODES,
37
- isRelayActive,
38
- readRelayForwardEnv
39
- };