@zhushanwen/subagent-engine-sdk 0.7.0 → 0.8.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 (50) hide show
  1. package/dist/best-effort.cjs +9 -1
  2. package/dist/best-effort.js +2 -2
  3. package/dist/{chunk-X24IVQKJ.js → chunk-3FVBDH3X.js} +3 -2
  4. package/dist/{chunk-YL5W5EMV.js → chunk-AF2ETADP.js} +1 -1
  5. package/dist/chunk-D36ZIQQK.js +28 -0
  6. package/dist/{chunk-W23PAAGX.js → chunk-DIIYVO4O.js} +1 -27
  7. package/dist/{chunk-RCT7L777.js → chunk-F7VDVSBZ.js} +1 -1
  8. package/dist/{chunk-HERD6RIR.js → chunk-MQPASWMA.js} +2 -2
  9. package/dist/{chunk-75QEMUGV.js → chunk-NXNNXGTY.js} +10 -1
  10. package/dist/{chunk-EJMF63R5.js → chunk-QMEHSKNR.js} +1 -1
  11. package/dist/{chunk-J4G2MXDS.js → chunk-VE3NVT7K.js} +1 -1
  12. package/dist/cli-entry.cjs +9 -1
  13. package/dist/cli-entry.js +2 -2
  14. package/dist/{contract-types-DiWyGRXr.d.cts → contract-types-DqOD58r-.d.cts} +7 -12
  15. package/dist/{contract-types-DiWyGRXr.d.ts → contract-types-DqOD58r-.d.ts} +7 -12
  16. package/dist/data-dir.cjs +10 -2
  17. package/dist/data-dir.js +2 -2
  18. package/dist/env.cjs +9 -1
  19. package/dist/env.d.cts +6 -6
  20. package/dist/env.d.ts +6 -6
  21. package/dist/env.js +2 -2
  22. package/dist/error-codes-C3oVToMr.d.cts +311 -0
  23. package/dist/error-codes-CiDwaODz.d.ts +311 -0
  24. package/dist/index.cjs +41 -3
  25. package/dist/index.d.cts +31 -3
  26. package/dist/index.d.ts +31 -3
  27. package/dist/index.js +62 -31
  28. package/dist/journal-io.d.cts +1 -1
  29. package/dist/journal-io.d.ts +1 -1
  30. package/dist/journal-replay.d.cts +1 -1
  31. package/dist/journal-replay.d.ts +1 -1
  32. package/dist/kill-chain.cjs +9 -1
  33. package/dist/kill-chain.d.cts +1 -1
  34. package/dist/kill-chain.d.ts +1 -1
  35. package/dist/kill-chain.js +2 -2
  36. package/dist/logger.cjs +11 -1
  37. package/dist/logger.js +1 -1
  38. package/dist/port-contract.d.cts +12 -6
  39. package/dist/port-contract.d.ts +12 -6
  40. package/dist/protocol/index.cjs +1 -1
  41. package/dist/protocol/index.d.cts +4 -296
  42. package/dist/protocol/index.d.ts +4 -296
  43. package/dist/protocol/index.js +7 -5
  44. package/dist/server/index.cjs +217 -0
  45. package/dist/server/index.d.cts +146 -0
  46. package/dist/server/index.d.ts +146 -0
  47. package/dist/server/index.js +143 -0
  48. package/dist/spawn.cjs +9 -1
  49. package/dist/spawn.js +3 -3
  50. package/package.json +12 -1
@@ -6,17 +6,19 @@ import {
6
6
  REVERSE_CHANNELS,
7
7
  REVERSE_CHANNEL_TIMEOUT_CLASS,
8
8
  errorResponseFrameSchema,
9
- isNotificationFrame,
10
- isRequestFrame,
11
- isResponseFrame,
12
- isReverseRequestFrame,
13
9
  notificationFrameSchema,
14
10
  protocolErrorSchema,
15
11
  requestFrameSchema,
16
12
  reverseRequestFrameSchema,
17
13
  runSessionParamsSchema,
18
14
  successResponseFrameSchema
19
- } from "../chunk-W23PAAGX.js";
15
+ } from "../chunk-DIIYVO4O.js";
16
+ import {
17
+ isNotificationFrame,
18
+ isRequestFrame,
19
+ isResponseFrame,
20
+ isReverseRequestFrame
21
+ } from "../chunk-D36ZIQQK.js";
20
22
  import {
21
23
  CANCEL_SETTLE_GRACE_MS,
22
24
  CRASH_REBUILD_BACKOFF_MS,
@@ -0,0 +1,217 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/server/index.ts
21
+ var server_exports = {};
22
+ __export(server_exports, {
23
+ REVERSE_TIMEOUT_DEFAULT_MS: () => REVERSE_TIMEOUT_DEFAULT_MS,
24
+ assembleFullTask: () => assembleFullTask,
25
+ classifyInboundFrame: () => classifyInboundFrame,
26
+ handleInboundFrame: () => handleInboundFrame,
27
+ initializeEngine: () => initializeEngine,
28
+ notInitializedError: () => notInitializedError,
29
+ reverseRequestRejection: () => reverseRequestRejection,
30
+ sendReverseRequest: () => sendReverseRequest,
31
+ toProtocolError: () => toProtocolError,
32
+ unknownMethodError: () => unknownMethodError,
33
+ writeRunEvent: () => writeRunEvent
34
+ });
35
+ module.exports = __toCommonJS(server_exports);
36
+
37
+ // src/error-message.ts
38
+ function toErrorMessage(e) {
39
+ if (e instanceof Error) return e.message;
40
+ if (typeof e === "object" && e !== null) {
41
+ try {
42
+ return JSON.stringify(e);
43
+ } catch {
44
+ return String(e);
45
+ }
46
+ }
47
+ return String(e);
48
+ }
49
+
50
+ // src/protocol/engine-protocol.ts
51
+ var ENGINE_PROTOCOL_VERSION = 1;
52
+
53
+ // src/protocol/error-codes.ts
54
+ var EngineSdkError = class extends Error {
55
+ code;
56
+ recovery;
57
+ data;
58
+ constructor(code, detail, recovery, data) {
59
+ super(`${code}: ${detail}`);
60
+ this.name = "EngineSdkError";
61
+ this.code = code;
62
+ this.recovery = recovery;
63
+ this.data = data;
64
+ }
65
+ /** 协议 error 帧载荷投影。 */
66
+ toStructured() {
67
+ return { code: this.code, message: this.message, recovery: this.recovery, data: this.data };
68
+ }
69
+ };
70
+
71
+ // src/protocol/frames.ts
72
+ function isRecord(v) {
73
+ return typeof v === "object" && v !== null;
74
+ }
75
+ function isResponseFrame(frame) {
76
+ if (!isRecord(frame) || !("id" in frame)) return false;
77
+ const idOk = typeof frame.id === "number" || typeof frame.id === "string";
78
+ if (!idOk) return false;
79
+ const hasResult = "result" in frame;
80
+ const hasError = "error" in frame;
81
+ return hasResult !== hasError;
82
+ }
83
+ function isReverseRequestFrame(frame) {
84
+ return isRecord(frame) && typeof frame.id === "string" && typeof frame.method === "string" && frame.method.startsWith("host/") && "params" in frame;
85
+ }
86
+
87
+ // src/server/index.ts
88
+ var REVERSE_TIMEOUT_DEFAULT_MS = 6e4;
89
+ function toProtocolError(err, recovery) {
90
+ if (err instanceof EngineSdkError) return err.toStructured();
91
+ return { code: "engine_run_failed", message: toErrorMessage(err), recovery };
92
+ }
93
+ function classifyInboundFrame(frame) {
94
+ if (isResponseFrame(frame)) return { kind: "reverse-response", id: frame.id };
95
+ if (isReverseRequestFrame(frame)) return { kind: "rejected-reverse-request", method: String(frame.method) };
96
+ if (typeof frame === "object" && frame !== null && "id" in frame && "method" in frame && typeof frame.method === "string") {
97
+ const { id, method, params } = frame;
98
+ if (typeof id === "number") return { kind: "request", id, method, params };
99
+ }
100
+ return { kind: "ignore" };
101
+ }
102
+ function reverseRequestRejection(method) {
103
+ return {
104
+ id: 0,
105
+ error: {
106
+ code: "engine_protocol_bad_frame",
107
+ message: `unexpected reverse request frame from host: ${method}`,
108
+ recovery: "The engine protocol v1 only carries host/* requests engine\u2192host."
109
+ }
110
+ };
111
+ }
112
+ function unknownMethodError(id, method) {
113
+ return new EngineSdkError(
114
+ "engine_protocol_unknown_method",
115
+ `unknown protocol method: ${method} (request id ${id})`,
116
+ "The engine speaks protocol v1; check the installed engine package version vs the host."
117
+ );
118
+ }
119
+ function handleInboundFrame(frame, ctx) {
120
+ const action = classifyInboundFrame(frame);
121
+ switch (action.kind) {
122
+ case "reverse-response":
123
+ ctx.settleReverse(action.id, frame);
124
+ return action;
125
+ case "rejected-reverse-request":
126
+ ctx.write(reverseRequestRejection(action.method));
127
+ return action;
128
+ case "request": {
129
+ let result;
130
+ try {
131
+ result = ctx.dispatch(action.id, action.method, action.params);
132
+ } catch (err) {
133
+ ctx.write({ id: action.id, error: ctx.toError(err) });
134
+ return action;
135
+ }
136
+ void Promise.resolve(result).then(
137
+ (value) => ctx.write({ id: action.id, result: value }),
138
+ (err) => ctx.write({ id: action.id, error: ctx.toError(err) })
139
+ );
140
+ return action;
141
+ }
142
+ case "ignore":
143
+ return action;
144
+ }
145
+ }
146
+ function sendReverseRequest(ctx, method, params) {
147
+ const id = ctx.nextId();
148
+ return new Promise((resolve, reject) => {
149
+ const timer = setTimeout(() => {
150
+ ctx.pending.delete(id);
151
+ ctx.clock?.settled(id);
152
+ reject(new Error(`reverse request ${method} (${id}) timed out after ${ctx.timeoutMs}ms`));
153
+ }, ctx.timeoutMs);
154
+ if (typeof timer.unref === "function") timer.unref();
155
+ ctx.pending.set(id, { resolve, reject, timer, ...ctx.pendingExtras?.(method) ?? {} });
156
+ ctx.clock?.started(id);
157
+ try {
158
+ ctx.write({ id, method, params });
159
+ } catch (err) {
160
+ ctx.pending.delete(id);
161
+ clearTimeout(timer);
162
+ ctx.clock?.settled(id);
163
+ reject(new Error(`reverse request ${method} (${id}) could not be written: ${toErrorMessage(err)}`));
164
+ }
165
+ });
166
+ }
167
+ function writeRunEvent(write, activeRuns, runId, event) {
168
+ const active = activeRuns.get(runId);
169
+ const seq = active !== void 0 ? ++active.seq : 0;
170
+ write({ method: "event", params: { runId, seq, event } });
171
+ }
172
+ function initializeEngine(params, ctx) {
173
+ if (params?.protocolVersion !== ENGINE_PROTOCOL_VERSION) {
174
+ throw new EngineSdkError(
175
+ "engine_protocol_mismatch",
176
+ `host protocol version ${String(params?.protocolVersion)} is not compatible with engine protocol v${ENGINE_PROTOCOL_VERSION}`,
177
+ `Upgrade the engine package or the host so both speak protocol v${ENGINE_PROTOCOL_VERSION}.`
178
+ );
179
+ }
180
+ const models = ctx.listModels();
181
+ return {
182
+ protocolVersion: ENGINE_PROTOCOL_VERSION,
183
+ engineId: ctx.engineId,
184
+ engineVersion: ctx.adapterVersion,
185
+ adapterVersion: ctx.adapterVersion,
186
+ capabilities: ctx.capabilities,
187
+ ...models !== null ? { models: models.map((m) => ({ id: m.id })) } : {}
188
+ };
189
+ }
190
+ function notInitializedError() {
191
+ return new EngineSdkError(
192
+ "engine_protocol_not_initialized",
193
+ "run before initialize is a protocol violation",
194
+ "The host must complete the initialize handshake before dispatching runs."
195
+ );
196
+ }
197
+ function assembleFullTask(task, ctx) {
198
+ return {
199
+ ...task,
200
+ ...ctx.model !== void 0 ? { model: ctx.model } : {},
201
+ ...ctx.cwd !== void 0 ? { cwd: ctx.cwd } : {}
202
+ };
203
+ }
204
+ // Annotate the CommonJS export names for ESM import in node:
205
+ 0 && (module.exports = {
206
+ REVERSE_TIMEOUT_DEFAULT_MS,
207
+ assembleFullTask,
208
+ classifyInboundFrame,
209
+ handleInboundFrame,
210
+ initializeEngine,
211
+ notInitializedError,
212
+ reverseRequestRejection,
213
+ sendReverseRequest,
214
+ toProtocolError,
215
+ unknownMethodError,
216
+ writeRunEvent
217
+ });
@@ -0,0 +1,146 @@
1
+ import { b as AgentCallOpts, A as AgentEvent } from '../contract-types-DqOD58r-.cjs';
2
+ import { I as InitializeResult, R as RunContextParams, a as InitializeParams, E as EngineSdkError } from '../error-codes-C3oVToMr.cjs';
3
+ import { ReverseRequestClock } from '../spawn.cjs';
4
+ import 'node:child_process';
5
+ import '../env.cjs';
6
+
7
+ /** 出站帧写入面(各引擎 main.ts 注入 process.stdout;测试注入内存缓冲)。 */
8
+ type FrameWriter = (frame: unknown) => void;
9
+ /**
10
+ * 反向请求应答等待缺省上限(ms)——数据面分类 core 侧 10s,两阶段等待放宽一档兜底。
11
+ *
12
+ * 两个引擎此值必须相同:它是「宿主应答迟到多久算超时」的协议面常数,分叉会让同一宿主
13
+ * 在不同引擎下得到不同的超时语义。
14
+ */
15
+ declare const REVERSE_TIMEOUT_DEFAULT_MS = 60000;
16
+ /** 单个 run 的在途登记(cancel 帧路由 + 事件 seq 计数)。 */
17
+ interface ActiveRun {
18
+ controller: AbortController;
19
+ seq: number;
20
+ }
21
+ /**
22
+ * 反向请求在途登记(引擎 → 宿主请求的应答等待项)。
23
+ *
24
+ * `method` 是 pi 引擎的扩展位(settle 时按通道守卫应答形态,如 askUser 的 UI 应答面
25
+ * 检查);zcode 无该通道守卫,可缺省。
26
+ */
27
+ interface ReversePending {
28
+ resolve: (result: unknown) => void;
29
+ reject: (err: Error) => void;
30
+ timer: NodeJS.Timeout;
31
+ method?: string;
32
+ }
33
+ /** 协议错误帧载荷(`{code,message,recovery}` 三件套——宿主据此渲染恢复指引)。 */
34
+ interface ProtocolErrorPayload {
35
+ code: string;
36
+ message: string;
37
+ recovery: string;
38
+ }
39
+ /**
40
+ * 异常 → 协议错误帧载荷。
41
+ *
42
+ * `EngineSdkError` 自带结构化(`toStructured()`,含引擎侧恢复指引);其余异常落
43
+ * `engine_run_failed` + 调用方给的恢复指引文案(各引擎的日志位置不同,故 recovery
44
+ * 由调用方注入而不是在这里写死)。
45
+ */
46
+ declare function toProtocolError(err: unknown, recovery: string): ProtocolErrorPayload;
47
+ /** 入站帧分类结果(纯判定、零副作用,便于单测逐分支断言)。 */
48
+ type InboundFrameAction = {
49
+ kind: "reverse-response";
50
+ id: number | string;
51
+ } | {
52
+ kind: "rejected-reverse-request";
53
+ method: string;
54
+ } | {
55
+ kind: "request";
56
+ id: number;
57
+ method: string;
58
+ params: unknown;
59
+ } | {
60
+ kind: "ignore";
61
+ };
62
+ /**
63
+ * 入站帧 → 动作。
64
+ *
65
+ * 判序即协议纪律:①反向应答(对端在等的 host/* 应答)②反向请求(引擎不发 host/*,
66
+ * 属非法入站 → 坏帧应答)③正向请求(`id` 为 number 且 `method` 为 string)④其余静默
67
+ * 忽略(stdout 是独占协议通道,不回显坏帧防对端解析器混乱)。
68
+ */
69
+ declare function classifyInboundFrame(frame: unknown): InboundFrameAction;
70
+ /** 引擎侧收到反向请求帧时的坏帧应答(`id: 0` = 非请求应答,对端只记坏帧)。 */
71
+ declare function reverseRequestRejection(method: string): {
72
+ id: number;
73
+ error: ProtocolErrorPayload;
74
+ };
75
+ /** 未知协议方法错误(两引擎逐字一致;表查找失败时抛,经 `toError` 转错误帧)。 */
76
+ declare function unknownMethodError(id: number, method: string): EngineSdkError;
77
+ /** 帧循环所需的最小上下文(引擎侧实现注入;每引擎构造一次,不在每帧重建)。 */
78
+ interface FrameLoopContext {
79
+ /** 出站帧写入面。 */
80
+ write: FrameWriter;
81
+ /** 反向应答帧落地(各引擎的两阶段 ack 语义在此,**刻意不统一**)。 */
82
+ settleReverse(id: number | string, frame: {
83
+ result?: unknown;
84
+ error?: unknown;
85
+ }): void;
86
+ /** 正向请求分发(9 方法表;抛出的错误经 `toError` 转错误帧)。 */
87
+ dispatch(id: number, method: string, params: unknown): unknown;
88
+ /** 错误 → 错误帧载荷(各引擎的恢复指引文案不同,故由引擎注入)。 */
89
+ toError(err: unknown): ProtocolErrorPayload;
90
+ }
91
+ /** 跑一帧(分类 → 落地)。返回值仅用于测试可读性,生产调用方忽略。 */
92
+ declare function handleInboundFrame(frame: unknown, ctx: FrameLoopContext): InboundFrameAction;
93
+ /**
94
+ * 反向请求发送(引擎 → 宿主请求的发出与等待登记)。
95
+ *
96
+ * 语义(两条都是踩过坑的):
97
+ * - 计时兜底在**发出侧**武装——应答侧不重复武装,两阶段 ack 只延长等待而不重置计时。
98
+ * - `write` 同步抛错(stdout 关闭等)就地收尾:清 pending + 停 timer + 记 clock 后转
99
+ * reject;不让异常同步逃出 Promise executor(逃出 = pending 条目与 timer 残留,
100
+ * 且 reject 无人消费时仍是 unhandled rejection 面)。
101
+ */
102
+ interface ReverseRequestSendContext {
103
+ write: FrameWriter;
104
+ pending: Map<string, ReversePending>;
105
+ timeoutMs: number;
106
+ clock?: ReverseRequestClock;
107
+ /** 请求 id 分配(各引擎可带自己的前缀与计数器)。 */
108
+ nextId(): string;
109
+ /** 实现特有的 pending 附加字段(pi 记 `method` 供应答面检查用;zcode 不记)。 */
110
+ pendingExtras?(method: string): Partial<ReversePending>;
111
+ }
112
+ declare function sendReverseRequest(ctx: ReverseRequestSendContext, method: string, params: unknown): Promise<unknown>;
113
+ /** 运行事件通知帧(`seq` 单调:无在途登记时取 0,仅作占位而非序号源)。 */
114
+ declare function writeRunEvent(write: FrameWriter, activeRuns: Map<string, ActiveRun>, runId: string, event: AgentEvent): void;
115
+ /** 初始化握手所需的最小上下文(版本协商共用;引擎实例面与适配器版本由引擎注入)。 */
116
+ interface InitializeHandshakeContext {
117
+ /** 引擎实例 id(`EnginePort.id`)。 */
118
+ engineId: string;
119
+ /** 引擎包自己的适配器版本常量(各包独立版本号)。 */
120
+ adapterVersion: string;
121
+ /** 能力位(`EnginePort.capabilities()` 的返回值)。 */
122
+ capabilities: InitializeResult["capabilities"];
123
+ /** 可用模型列表;`null` = 本引擎不提供(应答里不带 models 字段)。 */
124
+ listModels(): Array<{
125
+ id: string;
126
+ }> | null;
127
+ }
128
+ /**
129
+ * 初始化握手:协议版本协商(越界 → `engine_protocol_mismatch`)+ 能力与模型应答。
130
+ *
131
+ * 版本比对用严格相等:v1 系列内仍以 `ENGINE_PROTOCOL_VERSION` 为准(宿主与引擎同批发布),
132
+ * 放宽比对会让「装了旧引擎」静默通过,后续方法缺失才炸在更远处。
133
+ */
134
+ declare function initializeEngine(params: InitializeParams, ctx: InitializeHandshakeContext): InitializeResult;
135
+ /** run 前门未初始化拒绝(两引擎逐字一致的协议错误)。 */
136
+ declare function notInitializedError(): EngineSdkError;
137
+ /**
138
+ * 协议 `task` 子集 + `ctx` 还原 = 本地全量 `AgentCallOpts`(与宿主侧
139
+ * `RemoteEngine.toSdkTaskSubset` 镜像)。
140
+ *
141
+ * 还原纪律:`model` / `cwd` **有值才写**(wire additive 语义)——写 `undefined` 会覆盖
142
+ * 引擎侧缺省值,worktree 隔离与模型选择都会静默走错。
143
+ */
144
+ declare function assembleFullTask(task: AgentCallOpts, ctx: RunContextParams): AgentCallOpts;
145
+
146
+ export { type ActiveRun, type FrameLoopContext, type FrameWriter, type InboundFrameAction, type InitializeHandshakeContext, type ProtocolErrorPayload, REVERSE_TIMEOUT_DEFAULT_MS, type ReversePending, type ReverseRequestSendContext, assembleFullTask, classifyInboundFrame, handleInboundFrame, initializeEngine, notInitializedError, reverseRequestRejection, sendReverseRequest, toProtocolError, unknownMethodError, writeRunEvent };
@@ -0,0 +1,146 @@
1
+ import { b as AgentCallOpts, A as AgentEvent } from '../contract-types-DqOD58r-.js';
2
+ import { I as InitializeResult, R as RunContextParams, a as InitializeParams, E as EngineSdkError } from '../error-codes-CiDwaODz.js';
3
+ import { ReverseRequestClock } from '../spawn.js';
4
+ import 'node:child_process';
5
+ import '../env.js';
6
+
7
+ /** 出站帧写入面(各引擎 main.ts 注入 process.stdout;测试注入内存缓冲)。 */
8
+ type FrameWriter = (frame: unknown) => void;
9
+ /**
10
+ * 反向请求应答等待缺省上限(ms)——数据面分类 core 侧 10s,两阶段等待放宽一档兜底。
11
+ *
12
+ * 两个引擎此值必须相同:它是「宿主应答迟到多久算超时」的协议面常数,分叉会让同一宿主
13
+ * 在不同引擎下得到不同的超时语义。
14
+ */
15
+ declare const REVERSE_TIMEOUT_DEFAULT_MS = 60000;
16
+ /** 单个 run 的在途登记(cancel 帧路由 + 事件 seq 计数)。 */
17
+ interface ActiveRun {
18
+ controller: AbortController;
19
+ seq: number;
20
+ }
21
+ /**
22
+ * 反向请求在途登记(引擎 → 宿主请求的应答等待项)。
23
+ *
24
+ * `method` 是 pi 引擎的扩展位(settle 时按通道守卫应答形态,如 askUser 的 UI 应答面
25
+ * 检查);zcode 无该通道守卫,可缺省。
26
+ */
27
+ interface ReversePending {
28
+ resolve: (result: unknown) => void;
29
+ reject: (err: Error) => void;
30
+ timer: NodeJS.Timeout;
31
+ method?: string;
32
+ }
33
+ /** 协议错误帧载荷(`{code,message,recovery}` 三件套——宿主据此渲染恢复指引)。 */
34
+ interface ProtocolErrorPayload {
35
+ code: string;
36
+ message: string;
37
+ recovery: string;
38
+ }
39
+ /**
40
+ * 异常 → 协议错误帧载荷。
41
+ *
42
+ * `EngineSdkError` 自带结构化(`toStructured()`,含引擎侧恢复指引);其余异常落
43
+ * `engine_run_failed` + 调用方给的恢复指引文案(各引擎的日志位置不同,故 recovery
44
+ * 由调用方注入而不是在这里写死)。
45
+ */
46
+ declare function toProtocolError(err: unknown, recovery: string): ProtocolErrorPayload;
47
+ /** 入站帧分类结果(纯判定、零副作用,便于单测逐分支断言)。 */
48
+ type InboundFrameAction = {
49
+ kind: "reverse-response";
50
+ id: number | string;
51
+ } | {
52
+ kind: "rejected-reverse-request";
53
+ method: string;
54
+ } | {
55
+ kind: "request";
56
+ id: number;
57
+ method: string;
58
+ params: unknown;
59
+ } | {
60
+ kind: "ignore";
61
+ };
62
+ /**
63
+ * 入站帧 → 动作。
64
+ *
65
+ * 判序即协议纪律:①反向应答(对端在等的 host/* 应答)②反向请求(引擎不发 host/*,
66
+ * 属非法入站 → 坏帧应答)③正向请求(`id` 为 number 且 `method` 为 string)④其余静默
67
+ * 忽略(stdout 是独占协议通道,不回显坏帧防对端解析器混乱)。
68
+ */
69
+ declare function classifyInboundFrame(frame: unknown): InboundFrameAction;
70
+ /** 引擎侧收到反向请求帧时的坏帧应答(`id: 0` = 非请求应答,对端只记坏帧)。 */
71
+ declare function reverseRequestRejection(method: string): {
72
+ id: number;
73
+ error: ProtocolErrorPayload;
74
+ };
75
+ /** 未知协议方法错误(两引擎逐字一致;表查找失败时抛,经 `toError` 转错误帧)。 */
76
+ declare function unknownMethodError(id: number, method: string): EngineSdkError;
77
+ /** 帧循环所需的最小上下文(引擎侧实现注入;每引擎构造一次,不在每帧重建)。 */
78
+ interface FrameLoopContext {
79
+ /** 出站帧写入面。 */
80
+ write: FrameWriter;
81
+ /** 反向应答帧落地(各引擎的两阶段 ack 语义在此,**刻意不统一**)。 */
82
+ settleReverse(id: number | string, frame: {
83
+ result?: unknown;
84
+ error?: unknown;
85
+ }): void;
86
+ /** 正向请求分发(9 方法表;抛出的错误经 `toError` 转错误帧)。 */
87
+ dispatch(id: number, method: string, params: unknown): unknown;
88
+ /** 错误 → 错误帧载荷(各引擎的恢复指引文案不同,故由引擎注入)。 */
89
+ toError(err: unknown): ProtocolErrorPayload;
90
+ }
91
+ /** 跑一帧(分类 → 落地)。返回值仅用于测试可读性,生产调用方忽略。 */
92
+ declare function handleInboundFrame(frame: unknown, ctx: FrameLoopContext): InboundFrameAction;
93
+ /**
94
+ * 反向请求发送(引擎 → 宿主请求的发出与等待登记)。
95
+ *
96
+ * 语义(两条都是踩过坑的):
97
+ * - 计时兜底在**发出侧**武装——应答侧不重复武装,两阶段 ack 只延长等待而不重置计时。
98
+ * - `write` 同步抛错(stdout 关闭等)就地收尾:清 pending + 停 timer + 记 clock 后转
99
+ * reject;不让异常同步逃出 Promise executor(逃出 = pending 条目与 timer 残留,
100
+ * 且 reject 无人消费时仍是 unhandled rejection 面)。
101
+ */
102
+ interface ReverseRequestSendContext {
103
+ write: FrameWriter;
104
+ pending: Map<string, ReversePending>;
105
+ timeoutMs: number;
106
+ clock?: ReverseRequestClock;
107
+ /** 请求 id 分配(各引擎可带自己的前缀与计数器)。 */
108
+ nextId(): string;
109
+ /** 实现特有的 pending 附加字段(pi 记 `method` 供应答面检查用;zcode 不记)。 */
110
+ pendingExtras?(method: string): Partial<ReversePending>;
111
+ }
112
+ declare function sendReverseRequest(ctx: ReverseRequestSendContext, method: string, params: unknown): Promise<unknown>;
113
+ /** 运行事件通知帧(`seq` 单调:无在途登记时取 0,仅作占位而非序号源)。 */
114
+ declare function writeRunEvent(write: FrameWriter, activeRuns: Map<string, ActiveRun>, runId: string, event: AgentEvent): void;
115
+ /** 初始化握手所需的最小上下文(版本协商共用;引擎实例面与适配器版本由引擎注入)。 */
116
+ interface InitializeHandshakeContext {
117
+ /** 引擎实例 id(`EnginePort.id`)。 */
118
+ engineId: string;
119
+ /** 引擎包自己的适配器版本常量(各包独立版本号)。 */
120
+ adapterVersion: string;
121
+ /** 能力位(`EnginePort.capabilities()` 的返回值)。 */
122
+ capabilities: InitializeResult["capabilities"];
123
+ /** 可用模型列表;`null` = 本引擎不提供(应答里不带 models 字段)。 */
124
+ listModels(): Array<{
125
+ id: string;
126
+ }> | null;
127
+ }
128
+ /**
129
+ * 初始化握手:协议版本协商(越界 → `engine_protocol_mismatch`)+ 能力与模型应答。
130
+ *
131
+ * 版本比对用严格相等:v1 系列内仍以 `ENGINE_PROTOCOL_VERSION` 为准(宿主与引擎同批发布),
132
+ * 放宽比对会让「装了旧引擎」静默通过,后续方法缺失才炸在更远处。
133
+ */
134
+ declare function initializeEngine(params: InitializeParams, ctx: InitializeHandshakeContext): InitializeResult;
135
+ /** run 前门未初始化拒绝(两引擎逐字一致的协议错误)。 */
136
+ declare function notInitializedError(): EngineSdkError;
137
+ /**
138
+ * 协议 `task` 子集 + `ctx` 还原 = 本地全量 `AgentCallOpts`(与宿主侧
139
+ * `RemoteEngine.toSdkTaskSubset` 镜像)。
140
+ *
141
+ * 还原纪律:`model` / `cwd` **有值才写**(wire additive 语义)——写 `undefined` 会覆盖
142
+ * 引擎侧缺省值,worktree 隔离与模型选择都会静默走错。
143
+ */
144
+ declare function assembleFullTask(task: AgentCallOpts, ctx: RunContextParams): AgentCallOpts;
145
+
146
+ export { type ActiveRun, type FrameLoopContext, type FrameWriter, type InboundFrameAction, type InitializeHandshakeContext, type ProtocolErrorPayload, REVERSE_TIMEOUT_DEFAULT_MS, type ReversePending, type ReverseRequestSendContext, assembleFullTask, classifyInboundFrame, handleInboundFrame, initializeEngine, notInitializedError, reverseRequestRejection, sendReverseRequest, toProtocolError, unknownMethodError, writeRunEvent };
@@ -0,0 +1,143 @@
1
+ import {
2
+ isResponseFrame,
3
+ isReverseRequestFrame
4
+ } from "../chunk-D36ZIQQK.js";
5
+ import {
6
+ toErrorMessage
7
+ } from "../chunk-PYO3YR7W.js";
8
+ import {
9
+ ENGINE_PROTOCOL_VERSION,
10
+ EngineSdkError
11
+ } from "../chunk-SFNTX7Q3.js";
12
+ import "../chunk-JSBRDJBE.js";
13
+
14
+ // src/server/index.ts
15
+ var REVERSE_TIMEOUT_DEFAULT_MS = 6e4;
16
+ function toProtocolError(err, recovery) {
17
+ if (err instanceof EngineSdkError) return err.toStructured();
18
+ return { code: "engine_run_failed", message: toErrorMessage(err), recovery };
19
+ }
20
+ function classifyInboundFrame(frame) {
21
+ if (isResponseFrame(frame)) return { kind: "reverse-response", id: frame.id };
22
+ if (isReverseRequestFrame(frame)) return { kind: "rejected-reverse-request", method: String(frame.method) };
23
+ if (typeof frame === "object" && frame !== null && "id" in frame && "method" in frame && typeof frame.method === "string") {
24
+ const { id, method, params } = frame;
25
+ if (typeof id === "number") return { kind: "request", id, method, params };
26
+ }
27
+ return { kind: "ignore" };
28
+ }
29
+ function reverseRequestRejection(method) {
30
+ return {
31
+ id: 0,
32
+ error: {
33
+ code: "engine_protocol_bad_frame",
34
+ message: `unexpected reverse request frame from host: ${method}`,
35
+ recovery: "The engine protocol v1 only carries host/* requests engine\u2192host."
36
+ }
37
+ };
38
+ }
39
+ function unknownMethodError(id, method) {
40
+ return new EngineSdkError(
41
+ "engine_protocol_unknown_method",
42
+ `unknown protocol method: ${method} (request id ${id})`,
43
+ "The engine speaks protocol v1; check the installed engine package version vs the host."
44
+ );
45
+ }
46
+ function handleInboundFrame(frame, ctx) {
47
+ const action = classifyInboundFrame(frame);
48
+ switch (action.kind) {
49
+ case "reverse-response":
50
+ ctx.settleReverse(action.id, frame);
51
+ return action;
52
+ case "rejected-reverse-request":
53
+ ctx.write(reverseRequestRejection(action.method));
54
+ return action;
55
+ case "request": {
56
+ let result;
57
+ try {
58
+ result = ctx.dispatch(action.id, action.method, action.params);
59
+ } catch (err) {
60
+ ctx.write({ id: action.id, error: ctx.toError(err) });
61
+ return action;
62
+ }
63
+ void Promise.resolve(result).then(
64
+ (value) => ctx.write({ id: action.id, result: value }),
65
+ (err) => ctx.write({ id: action.id, error: ctx.toError(err) })
66
+ );
67
+ return action;
68
+ }
69
+ case "ignore":
70
+ return action;
71
+ }
72
+ }
73
+ function sendReverseRequest(ctx, method, params) {
74
+ const id = ctx.nextId();
75
+ return new Promise((resolve, reject) => {
76
+ const timer = setTimeout(() => {
77
+ ctx.pending.delete(id);
78
+ ctx.clock?.settled(id);
79
+ reject(new Error(`reverse request ${method} (${id}) timed out after ${ctx.timeoutMs}ms`));
80
+ }, ctx.timeoutMs);
81
+ if (typeof timer.unref === "function") timer.unref();
82
+ ctx.pending.set(id, { resolve, reject, timer, ...ctx.pendingExtras?.(method) ?? {} });
83
+ ctx.clock?.started(id);
84
+ try {
85
+ ctx.write({ id, method, params });
86
+ } catch (err) {
87
+ ctx.pending.delete(id);
88
+ clearTimeout(timer);
89
+ ctx.clock?.settled(id);
90
+ reject(new Error(`reverse request ${method} (${id}) could not be written: ${toErrorMessage(err)}`));
91
+ }
92
+ });
93
+ }
94
+ function writeRunEvent(write, activeRuns, runId, event) {
95
+ const active = activeRuns.get(runId);
96
+ const seq = active !== void 0 ? ++active.seq : 0;
97
+ write({ method: "event", params: { runId, seq, event } });
98
+ }
99
+ function initializeEngine(params, ctx) {
100
+ if (params?.protocolVersion !== ENGINE_PROTOCOL_VERSION) {
101
+ throw new EngineSdkError(
102
+ "engine_protocol_mismatch",
103
+ `host protocol version ${String(params?.protocolVersion)} is not compatible with engine protocol v${ENGINE_PROTOCOL_VERSION}`,
104
+ `Upgrade the engine package or the host so both speak protocol v${ENGINE_PROTOCOL_VERSION}.`
105
+ );
106
+ }
107
+ const models = ctx.listModels();
108
+ return {
109
+ protocolVersion: ENGINE_PROTOCOL_VERSION,
110
+ engineId: ctx.engineId,
111
+ engineVersion: ctx.adapterVersion,
112
+ adapterVersion: ctx.adapterVersion,
113
+ capabilities: ctx.capabilities,
114
+ ...models !== null ? { models: models.map((m) => ({ id: m.id })) } : {}
115
+ };
116
+ }
117
+ function notInitializedError() {
118
+ return new EngineSdkError(
119
+ "engine_protocol_not_initialized",
120
+ "run before initialize is a protocol violation",
121
+ "The host must complete the initialize handshake before dispatching runs."
122
+ );
123
+ }
124
+ function assembleFullTask(task, ctx) {
125
+ return {
126
+ ...task,
127
+ ...ctx.model !== void 0 ? { model: ctx.model } : {},
128
+ ...ctx.cwd !== void 0 ? { cwd: ctx.cwd } : {}
129
+ };
130
+ }
131
+ export {
132
+ REVERSE_TIMEOUT_DEFAULT_MS,
133
+ assembleFullTask,
134
+ classifyInboundFrame,
135
+ handleInboundFrame,
136
+ initializeEngine,
137
+ notInitializedError,
138
+ reverseRequestRejection,
139
+ sendReverseRequest,
140
+ toProtocolError,
141
+ unknownMethodError,
142
+ writeRunEvent
143
+ };