@zhushanwen/zcode-subagent-cli 0.4.3 → 0.4.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.
@@ -328,9 +328,9 @@ import {
328
328
  sessionIdFromHandle
329
329
  } from "@zhushanwen/subagent-engine-sdk";
330
330
  function replayJournalToSessionView(handle, engineId) {
331
- const journalPath = handle.data.journalPath;
332
- if (journalPath === void 0) return void 0;
333
- const events = replayJournal2(journalPath);
331
+ const eventsPath = handle.data.eventsPath;
332
+ if (eventsPath === void 0) return void 0;
333
+ const events = replayJournal2(eventsPath);
334
334
  if (events.length === 0) return void 0;
335
335
  return eventsToSessionView(events, engineId, sessionIdFromHandle(handle.data));
336
336
  }
@@ -2560,10 +2560,7 @@ var ZcodeEngine = class {
2560
2560
  engineId: ZCODE_ENGINE_ID,
2561
2561
  content: "",
2562
2562
  durationMs: Date.now() - startedAt,
2563
- ...typeof task.worktree === "object" && task.worktree !== null ? { worktreePath: task.worktree.path } : {},
2564
- // D9① fallback 留痕:路由层经 RunContext 投影(zcode 无 record 通路,outcome 是
2565
- // 唯一留痕面;pi 引擎另有 record 投影)
2566
- ...ctx.engineFallback !== void 0 ? { engineFallback: ctx.engineFallback } : {}
2563
+ ...typeof task.worktree === "object" && task.worktree !== null ? { worktreePath: task.worktree.path } : {}
2567
2564
  };
2568
2565
  const emit = (event) => {
2569
2566
  ctx.onEvent?.(event);
@@ -2658,7 +2655,7 @@ var ZcodeEngine = class {
2658
2655
  * D6 read 三级降级:①sqlite 原生读取 → ②宿主 event journal 重放(对齐点①接线:
2659
2656
  * replayJournalToSessionView 复用 live reducer,重放等价性见 §3.3.6)→ ③outcome-only。
2660
2657
  * sessionId 缺失(解析失败的 run 无法定位 session)跳过①级;②级依赖
2661
- * handle.journalPath(宿主 run 后回填)。dbPath:新 handle 恒为隔离库绝对路径
2658
+ * handle.eventsPath(宿主 run 后回填)。dbPath:新 handle 恒为隔离库绝对路径
2662
2659
  * (zcodeSessionDbPath(engineDataDir),tier1 白名单集合见方法体——宿主路径仅
2663
2660
  * 「共享 HOME 时代」存量兼容);旧 records(池时代)的相对路径仍按池目录锚定
2664
2661
  * 解析(read 兼容旧数据,池目录不存在时自然落②级 journal 降级)。[池抽象降级
@@ -3076,24 +3073,32 @@ function createDefaultZcodeEngine() {
3076
3073
 
3077
3074
  // src/server.ts
3078
3075
  import {
3079
- ENGINE_PROTOCOL_VERSION,
3080
3076
  EngineSdkError,
3081
- getLogger as getLogger5,
3082
- isResponseFrame,
3083
- isReverseRequestFrame
3077
+ getLogger as getLogger5
3084
3078
  } from "@zhushanwen/subagent-engine-sdk";
3085
3079
 
3086
3080
  // src/port-types.ts
3087
3081
  import { parseCtxModel } from "@zhushanwen/subagent-engine-sdk";
3088
3082
 
3089
3083
  // src/server.ts
3084
+ import {
3085
+ assembleFullTask,
3086
+ handleInboundFrame,
3087
+ initializeEngine,
3088
+ notInitializedError,
3089
+ sendReverseRequest,
3090
+ unknownMethodError,
3091
+ writeRunEvent,
3092
+ REVERSE_TIMEOUT_DEFAULT_MS,
3093
+ toProtocolError as toProtocolErrorShared
3094
+ } from "@zhushanwen/subagent-engine-sdk/server";
3090
3095
  var logger5 = getLogger5("subagents");
3091
- var REVERSE_TIMEOUT_DEFAULT_MS = 6e4;
3092
3096
  var EngineProtocolServer = class {
3093
3097
  write;
3094
3098
  engine;
3095
3099
  reverseClock;
3096
3100
  reverseTimeoutMs;
3101
+ frameLoop;
3097
3102
  activeRuns = /* @__PURE__ */ new Map();
3098
3103
  reversePending = /* @__PURE__ */ new Map();
3099
3104
  revSeq = 0;
@@ -3103,45 +3108,21 @@ var EngineProtocolServer = class {
3103
3108
  this.engine = opts.engine ?? createDefaultZcodeEngine();
3104
3109
  this.reverseClock = opts.reverseClock;
3105
3110
  this.reverseTimeoutMs = opts.reverseTimeoutMs ?? REVERSE_TIMEOUT_DEFAULT_MS;
3111
+ this.frameLoop = {
3112
+ write: this.write,
3113
+ settleReverse: (id, frame) => this.settleReverse(id, frame),
3114
+ dispatch: (id, method, params) => this.dispatch(id, method, params),
3115
+ toError: (err) => toProtocolError(err)
3116
+ };
3106
3117
  }
3107
3118
  /** 入站帧消费(请求帧 + 反向请求应答帧;main.ts 的行解析器拆行后喂入)。 */
3108
3119
  handleFrame(frame) {
3109
- if (isResponseFrame(frame)) {
3110
- this.settleReverse(frame.id, frame);
3111
- return;
3112
- }
3113
- if (isReverseRequestFrame(frame)) {
3114
- this.write({
3115
- id: 0,
3116
- error: {
3117
- code: "engine_protocol_bad_frame",
3118
- message: `unexpected reverse request frame from host: ${String(frame.method)}`,
3119
- recovery: "The engine protocol v1 only carries host/* requests engine\u2192host."
3120
- }
3121
- });
3122
- return;
3123
- }
3124
- if (typeof frame === "object" && frame !== null && "id" in frame && "method" in frame && typeof frame.method === "string") {
3125
- const { id, method, params } = frame;
3126
- if (typeof id === "number") {
3127
- void this.dispatch(id, method, params).then(
3128
- (result) => this.write({ id, result }),
3129
- (err) => this.write({ id, error: toProtocolError(err) })
3130
- );
3131
- return;
3132
- }
3133
- }
3120
+ handleInboundFrame(frame, this.frameLoop);
3134
3121
  }
3135
3122
  /** 9 正向方法分发(表驱动:method → 处理器;未知方法 → engine_protocol_unknown_method)。 */
3136
3123
  async dispatch(id, method, params) {
3137
3124
  const handler = this.methodHandlers[method];
3138
- if (handler === void 0) {
3139
- throw new EngineSdkError(
3140
- "engine_protocol_unknown_method",
3141
- `unknown protocol method: ${method} (request id ${id})`,
3142
- "The engine speaks protocol v1; check the installed engine package version vs the host."
3143
- );
3144
- }
3125
+ if (handler === void 0) throw unknownMethodError(id, method);
3145
3126
  return handler(params);
3146
3127
  }
3147
3128
  /**
@@ -3164,42 +3145,23 @@ var EngineProtocolServer = class {
3164
3145
  };
3165
3146
  // ── initialize:版本协商(越界 → engine_protocol_mismatch)+ 能力应答 ──
3166
3147
  initialize(params) {
3167
- if (params?.protocolVersion !== ENGINE_PROTOCOL_VERSION) {
3168
- throw new EngineSdkError(
3169
- "engine_protocol_mismatch",
3170
- `host protocol version ${String(params?.protocolVersion)} is not compatible with engine protocol v${ENGINE_PROTOCOL_VERSION}`,
3171
- `Upgrade the engine package or the host so both speak protocol v${ENGINE_PROTOCOL_VERSION}.`
3172
- );
3173
- }
3174
- this.initialized = true;
3175
- const models = this.engine.listModels?.() ?? null;
3176
- return {
3177
- protocolVersion: ENGINE_PROTOCOL_VERSION,
3148
+ const result = initializeEngine(params, {
3178
3149
  engineId: this.engine.id,
3179
- engineVersion: ZCODE_ADAPTER_VERSION,
3180
3150
  adapterVersion: ZCODE_ADAPTER_VERSION,
3181
3151
  capabilities: this.engine.capabilities(),
3182
- ...models !== null ? { models: models.map((m) => ({ id: m.id })) } : {}
3183
- };
3152
+ listModels: () => this.engine.listModels?.() ?? null
3153
+ });
3154
+ this.initialized = true;
3155
+ return result;
3184
3156
  }
3185
3157
  // ── run:协议载荷 → 本地 AgentCallOpts/RunContext;事件 → 通知/host 通道 ──
3186
3158
  async run(params) {
3187
- if (!this.initialized) {
3188
- throw new EngineSdkError(
3189
- "engine_protocol_not_initialized",
3190
- "run before initialize is a protocol violation",
3191
- "The host must complete the initialize handshake before dispatching runs."
3192
- );
3193
- }
3159
+ if (!this.initialized) throw notInitializedError();
3194
3160
  const { runId, task, ctx } = params;
3195
3161
  const controller = new AbortController();
3196
3162
  const active = { controller, seq: 0 };
3197
3163
  this.activeRuns.set(runId, active);
3198
- const fullTask = {
3199
- ...task,
3200
- ...ctx.model !== void 0 ? { model: ctx.model } : {},
3201
- ...ctx.cwd !== void 0 ? { cwd: ctx.cwd } : {}
3202
- };
3164
+ const fullTask = assembleFullTask(task, ctx);
3203
3165
  const ctxModel = parseCtxModel(ctx.ctxModel);
3204
3166
  const stream = ctx.streamMode === "stream" ? {
3205
3167
  onDelta: (delta) => {
@@ -3212,7 +3174,6 @@ var EngineProtocolServer = class {
3212
3174
  onEvent: (event) => this.emitEvent(runId, event),
3213
3175
  ...ctxModel !== void 0 ? { ctxModel } : {},
3214
3176
  ...stream !== void 0 ? { stream } : {},
3215
- ...ctx.engineFallback !== void 0 ? { engineFallback: ctx.engineFallback } : {},
3216
3177
  // [U6 / §3.2.6 要点 3] resume 锚点透传(宿主 → 引擎的续聊通道:zcode 锚
3217
3178
  // sessionRef {sessionId, dbPath},引擎侧 resume 读 + 新 session 注入消费)。
3218
3179
  ...params.resume !== void 0 ? { resume: params.resume } : {},
@@ -3247,9 +3208,7 @@ var EngineProtocolServer = class {
3247
3208
  }
3248
3209
  // ── 出站:事件通知 + 反向请求客户端 ──
3249
3210
  emitEvent(runId, event) {
3250
- const active = this.activeRuns.get(runId);
3251
- const seq = active !== void 0 ? ++active.seq : 0;
3252
- this.write({ method: "event", params: { runId, seq, event } });
3211
+ writeRunEvent(this.write, this.activeRuns, runId, event);
3253
3212
  }
3254
3213
  /**
3255
3214
  * 发反向请求并等应答(帧④必须应答)。计时面登记:发出 → clock.started;收到
@@ -3275,25 +3234,17 @@ var EngineProtocolServer = class {
3275
3234
  return this.reverseRequestInternal(method, params);
3276
3235
  }
3277
3236
  reverseRequestInternal(method, params) {
3278
- const id = `rev-${++this.revSeq}`;
3279
- return new Promise((resolve2, reject) => {
3280
- const timer = setTimeout(() => {
3281
- this.reversePending.delete(id);
3282
- this.reverseClock?.settled(id);
3283
- reject(new Error(`reverse request ${method} (${id}) timed out after ${this.reverseTimeoutMs}ms`));
3284
- }, this.reverseTimeoutMs);
3285
- if (typeof timer.unref === "function") timer.unref();
3286
- this.reversePending.set(id, { resolve: resolve2, reject, timer });
3287
- this.reverseClock?.started(id);
3288
- try {
3289
- this.write({ id, method, params });
3290
- } catch (err) {
3291
- this.reversePending.delete(id);
3292
- clearTimeout(timer);
3293
- this.reverseClock?.settled(id);
3294
- reject(new Error(`reverse request ${method} (${id}) could not be written: ${toErrorMessage(err)}`));
3295
- }
3296
- });
3237
+ return sendReverseRequest(
3238
+ {
3239
+ write: this.write,
3240
+ pending: this.reversePending,
3241
+ timeoutMs: this.reverseTimeoutMs,
3242
+ ...this.reverseClock !== void 0 ? { clock: this.reverseClock } : {},
3243
+ nextId: () => `rev-${++this.revSeq}`
3244
+ },
3245
+ method,
3246
+ params
3247
+ );
3297
3248
  }
3298
3249
  /** 反向请求应答落位(ack 两阶段:{ack:true}/{unsupported:true}/{ok:true} 均先 ack 计时面)。 */
3299
3250
  settleReverse(id, frame) {
@@ -3310,13 +3261,9 @@ var EngineProtocolServer = class {
3310
3261
  function probeParamsOf(params) {
3311
3262
  return typeof params === "object" && params !== null ? params : void 0;
3312
3263
  }
3264
+ var RUN_FAILURE_RECOVERY = "Check the engine process logs (engineDataDir/logs/) and rerun; if persistent, reinstall or upgrade the engine package.";
3313
3265
  function toProtocolError(err) {
3314
- if (err instanceof EngineSdkError) return err.toStructured();
3315
- return {
3316
- code: "engine_run_failed",
3317
- message: toErrorMessage(err),
3318
- recovery: "Check the engine process logs (engineDataDir/logs/) and rerun; if persistent, reinstall or upgrade the engine package."
3319
- };
3266
+ return toProtocolErrorShared(err, RUN_FAILURE_RECOVERY);
3320
3267
  }
3321
3268
 
3322
3269
  export {
package/dist/index.cjs CHANGED
@@ -104,9 +104,9 @@ var import_subagent_engine_sdk11 = require("@zhushanwen/subagent-engine-sdk");
104
104
  var import_subagent_engine_sdk = require("@zhushanwen/subagent-engine-sdk");
105
105
  var import_subagent_engine_sdk2 = require("@zhushanwen/subagent-engine-sdk");
106
106
  function replayJournalToSessionView(handle, engineId) {
107
- const journalPath = handle.data.journalPath;
108
- if (journalPath === void 0) return void 0;
109
- const events = (0, import_subagent_engine_sdk2.replayJournal)(journalPath);
107
+ const eventsPath = handle.data.eventsPath;
108
+ if (eventsPath === void 0) return void 0;
109
+ const events = (0, import_subagent_engine_sdk2.replayJournal)(eventsPath);
110
110
  if (events.length === 0) return void 0;
111
111
  return (0, import_subagent_engine_sdk2.eventsToSessionView)(events, engineId, (0, import_subagent_engine_sdk2.sessionIdFromHandle)(handle.data));
112
112
  }
@@ -2578,10 +2578,7 @@ var ZcodeEngine = class {
2578
2578
  engineId: ZCODE_ENGINE_ID,
2579
2579
  content: "",
2580
2580
  durationMs: Date.now() - startedAt,
2581
- ...typeof task.worktree === "object" && task.worktree !== null ? { worktreePath: task.worktree.path } : {},
2582
- // D9① fallback 留痕:路由层经 RunContext 投影(zcode 无 record 通路,outcome 是
2583
- // 唯一留痕面;pi 引擎另有 record 投影)
2584
- ...ctx.engineFallback !== void 0 ? { engineFallback: ctx.engineFallback } : {}
2581
+ ...typeof task.worktree === "object" && task.worktree !== null ? { worktreePath: task.worktree.path } : {}
2585
2582
  };
2586
2583
  const emit = (event) => {
2587
2584
  ctx.onEvent?.(event);
@@ -2676,7 +2673,7 @@ var ZcodeEngine = class {
2676
2673
  * D6 read 三级降级:①sqlite 原生读取 → ②宿主 event journal 重放(对齐点①接线:
2677
2674
  * replayJournalToSessionView 复用 live reducer,重放等价性见 §3.3.6)→ ③outcome-only。
2678
2675
  * sessionId 缺失(解析失败的 run 无法定位 session)跳过①级;②级依赖
2679
- * handle.journalPath(宿主 run 后回填)。dbPath:新 handle 恒为隔离库绝对路径
2676
+ * handle.eventsPath(宿主 run 后回填)。dbPath:新 handle 恒为隔离库绝对路径
2680
2677
  * (zcodeSessionDbPath(engineDataDir),tier1 白名单集合见方法体——宿主路径仅
2681
2678
  * 「共享 HOME 时代」存量兼容);旧 records(池时代)的相对路径仍按池目录锚定
2682
2679
  * 解析(read 兼容旧数据,池目录不存在时自然落②级 journal 降级)。[池抽象降级
@@ -3095,13 +3092,14 @@ function createDefaultZcodeEngine() {
3095
3092
  var import_subagent_engine_sdk13 = require("@zhushanwen/subagent-engine-sdk");
3096
3093
 
3097
3094
  // src/server.ts
3095
+ var import_server = require("@zhushanwen/subagent-engine-sdk/server");
3098
3096
  var logger5 = (0, import_subagent_engine_sdk14.getLogger)("subagents");
3099
- var REVERSE_TIMEOUT_DEFAULT_MS = 6e4;
3100
3097
  var EngineProtocolServer = class {
3101
3098
  write;
3102
3099
  engine;
3103
3100
  reverseClock;
3104
3101
  reverseTimeoutMs;
3102
+ frameLoop;
3105
3103
  activeRuns = /* @__PURE__ */ new Map();
3106
3104
  reversePending = /* @__PURE__ */ new Map();
3107
3105
  revSeq = 0;
@@ -3110,46 +3108,22 @@ var EngineProtocolServer = class {
3110
3108
  this.write = opts.write;
3111
3109
  this.engine = opts.engine ?? createDefaultZcodeEngine();
3112
3110
  this.reverseClock = opts.reverseClock;
3113
- this.reverseTimeoutMs = opts.reverseTimeoutMs ?? REVERSE_TIMEOUT_DEFAULT_MS;
3111
+ this.reverseTimeoutMs = opts.reverseTimeoutMs ?? import_server.REVERSE_TIMEOUT_DEFAULT_MS;
3112
+ this.frameLoop = {
3113
+ write: this.write,
3114
+ settleReverse: (id, frame) => this.settleReverse(id, frame),
3115
+ dispatch: (id, method, params) => this.dispatch(id, method, params),
3116
+ toError: (err) => toProtocolError(err)
3117
+ };
3114
3118
  }
3115
3119
  /** 入站帧消费(请求帧 + 反向请求应答帧;main.ts 的行解析器拆行后喂入)。 */
3116
3120
  handleFrame(frame) {
3117
- if ((0, import_subagent_engine_sdk14.isResponseFrame)(frame)) {
3118
- this.settleReverse(frame.id, frame);
3119
- return;
3120
- }
3121
- if ((0, import_subagent_engine_sdk14.isReverseRequestFrame)(frame)) {
3122
- this.write({
3123
- id: 0,
3124
- error: {
3125
- code: "engine_protocol_bad_frame",
3126
- message: `unexpected reverse request frame from host: ${String(frame.method)}`,
3127
- recovery: "The engine protocol v1 only carries host/* requests engine\u2192host."
3128
- }
3129
- });
3130
- return;
3131
- }
3132
- if (typeof frame === "object" && frame !== null && "id" in frame && "method" in frame && typeof frame.method === "string") {
3133
- const { id, method, params } = frame;
3134
- if (typeof id === "number") {
3135
- void this.dispatch(id, method, params).then(
3136
- (result) => this.write({ id, result }),
3137
- (err) => this.write({ id, error: toProtocolError(err) })
3138
- );
3139
- return;
3140
- }
3141
- }
3121
+ (0, import_server.handleInboundFrame)(frame, this.frameLoop);
3142
3122
  }
3143
3123
  /** 9 正向方法分发(表驱动:method → 处理器;未知方法 → engine_protocol_unknown_method)。 */
3144
3124
  async dispatch(id, method, params) {
3145
3125
  const handler = this.methodHandlers[method];
3146
- if (handler === void 0) {
3147
- throw new import_subagent_engine_sdk14.EngineSdkError(
3148
- "engine_protocol_unknown_method",
3149
- `unknown protocol method: ${method} (request id ${id})`,
3150
- "The engine speaks protocol v1; check the installed engine package version vs the host."
3151
- );
3152
- }
3126
+ if (handler === void 0) throw (0, import_server.unknownMethodError)(id, method);
3153
3127
  return handler(params);
3154
3128
  }
3155
3129
  /**
@@ -3172,42 +3146,23 @@ var EngineProtocolServer = class {
3172
3146
  };
3173
3147
  // ── initialize:版本协商(越界 → engine_protocol_mismatch)+ 能力应答 ──
3174
3148
  initialize(params) {
3175
- if (params?.protocolVersion !== import_subagent_engine_sdk14.ENGINE_PROTOCOL_VERSION) {
3176
- throw new import_subagent_engine_sdk14.EngineSdkError(
3177
- "engine_protocol_mismatch",
3178
- `host protocol version ${String(params?.protocolVersion)} is not compatible with engine protocol v${import_subagent_engine_sdk14.ENGINE_PROTOCOL_VERSION}`,
3179
- `Upgrade the engine package or the host so both speak protocol v${import_subagent_engine_sdk14.ENGINE_PROTOCOL_VERSION}.`
3180
- );
3181
- }
3182
- this.initialized = true;
3183
- const models = this.engine.listModels?.() ?? null;
3184
- return {
3185
- protocolVersion: import_subagent_engine_sdk14.ENGINE_PROTOCOL_VERSION,
3149
+ const result = (0, import_server.initializeEngine)(params, {
3186
3150
  engineId: this.engine.id,
3187
- engineVersion: ZCODE_ADAPTER_VERSION,
3188
3151
  adapterVersion: ZCODE_ADAPTER_VERSION,
3189
3152
  capabilities: this.engine.capabilities(),
3190
- ...models !== null ? { models: models.map((m) => ({ id: m.id })) } : {}
3191
- };
3153
+ listModels: () => this.engine.listModels?.() ?? null
3154
+ });
3155
+ this.initialized = true;
3156
+ return result;
3192
3157
  }
3193
3158
  // ── run:协议载荷 → 本地 AgentCallOpts/RunContext;事件 → 通知/host 通道 ──
3194
3159
  async run(params) {
3195
- if (!this.initialized) {
3196
- throw new import_subagent_engine_sdk14.EngineSdkError(
3197
- "engine_protocol_not_initialized",
3198
- "run before initialize is a protocol violation",
3199
- "The host must complete the initialize handshake before dispatching runs."
3200
- );
3201
- }
3160
+ if (!this.initialized) throw (0, import_server.notInitializedError)();
3202
3161
  const { runId, task, ctx } = params;
3203
3162
  const controller = new AbortController();
3204
3163
  const active = { controller, seq: 0 };
3205
3164
  this.activeRuns.set(runId, active);
3206
- const fullTask = {
3207
- ...task,
3208
- ...ctx.model !== void 0 ? { model: ctx.model } : {},
3209
- ...ctx.cwd !== void 0 ? { cwd: ctx.cwd } : {}
3210
- };
3165
+ const fullTask = (0, import_server.assembleFullTask)(task, ctx);
3211
3166
  const ctxModel = (0, import_subagent_engine_sdk13.parseCtxModel)(ctx.ctxModel);
3212
3167
  const stream = ctx.streamMode === "stream" ? {
3213
3168
  onDelta: (delta) => {
@@ -3220,7 +3175,6 @@ var EngineProtocolServer = class {
3220
3175
  onEvent: (event) => this.emitEvent(runId, event),
3221
3176
  ...ctxModel !== void 0 ? { ctxModel } : {},
3222
3177
  ...stream !== void 0 ? { stream } : {},
3223
- ...ctx.engineFallback !== void 0 ? { engineFallback: ctx.engineFallback } : {},
3224
3178
  // [U6 / §3.2.6 要点 3] resume 锚点透传(宿主 → 引擎的续聊通道:zcode 锚
3225
3179
  // sessionRef {sessionId, dbPath},引擎侧 resume 读 + 新 session 注入消费)。
3226
3180
  ...params.resume !== void 0 ? { resume: params.resume } : {},
@@ -3255,9 +3209,7 @@ var EngineProtocolServer = class {
3255
3209
  }
3256
3210
  // ── 出站:事件通知 + 反向请求客户端 ──
3257
3211
  emitEvent(runId, event) {
3258
- const active = this.activeRuns.get(runId);
3259
- const seq = active !== void 0 ? ++active.seq : 0;
3260
- this.write({ method: "event", params: { runId, seq, event } });
3212
+ (0, import_server.writeRunEvent)(this.write, this.activeRuns, runId, event);
3261
3213
  }
3262
3214
  /**
3263
3215
  * 发反向请求并等应答(帧④必须应答)。计时面登记:发出 → clock.started;收到
@@ -3283,25 +3235,17 @@ var EngineProtocolServer = class {
3283
3235
  return this.reverseRequestInternal(method, params);
3284
3236
  }
3285
3237
  reverseRequestInternal(method, params) {
3286
- const id = `rev-${++this.revSeq}`;
3287
- return new Promise((resolve2, reject) => {
3288
- const timer = setTimeout(() => {
3289
- this.reversePending.delete(id);
3290
- this.reverseClock?.settled(id);
3291
- reject(new Error(`reverse request ${method} (${id}) timed out after ${this.reverseTimeoutMs}ms`));
3292
- }, this.reverseTimeoutMs);
3293
- if (typeof timer.unref === "function") timer.unref();
3294
- this.reversePending.set(id, { resolve: resolve2, reject, timer });
3295
- this.reverseClock?.started(id);
3296
- try {
3297
- this.write({ id, method, params });
3298
- } catch (err) {
3299
- this.reversePending.delete(id);
3300
- clearTimeout(timer);
3301
- this.reverseClock?.settled(id);
3302
- reject(new Error(`reverse request ${method} (${id}) could not be written: ${(0, import_subagent_engine_sdk4.toErrorMessage)(err)}`));
3303
- }
3304
- });
3238
+ return (0, import_server.sendReverseRequest)(
3239
+ {
3240
+ write: this.write,
3241
+ pending: this.reversePending,
3242
+ timeoutMs: this.reverseTimeoutMs,
3243
+ ...this.reverseClock !== void 0 ? { clock: this.reverseClock } : {},
3244
+ nextId: () => `rev-${++this.revSeq}`
3245
+ },
3246
+ method,
3247
+ params
3248
+ );
3305
3249
  }
3306
3250
  /** 反向请求应答落位(ack 两阶段:{ack:true}/{unsupported:true}/{ok:true} 均先 ack 计时面)。 */
3307
3251
  settleReverse(id, frame) {
@@ -3318,13 +3262,9 @@ var EngineProtocolServer = class {
3318
3262
  function probeParamsOf(params) {
3319
3263
  return typeof params === "object" && params !== null ? params : void 0;
3320
3264
  }
3265
+ var RUN_FAILURE_RECOVERY = "Check the engine process logs (engineDataDir/logs/) and rerun; if persistent, reinstall or upgrade the engine package.";
3321
3266
  function toProtocolError(err) {
3322
- if (err instanceof import_subagent_engine_sdk14.EngineSdkError) return err.toStructured();
3323
- return {
3324
- code: "engine_run_failed",
3325
- message: (0, import_subagent_engine_sdk4.toErrorMessage)(err),
3326
- recovery: "Check the engine process logs (engineDataDir/logs/) and rerun; if persistent, reinstall or upgrade the engine package."
3327
- };
3267
+ return (0, import_server.toProtocolError)(err, RUN_FAILURE_RECOVERY);
3328
3268
  }
3329
3269
 
3330
3270
  // src/golden-sample.ts
package/dist/index.d.cts CHANGED
@@ -1,7 +1,6 @@
1
1
  import { EnginePort, ReverseRequestClock, EngineCapabilities, ProbeReport, EngineAgentCallOpts, RunContext, EngineRunResult, EngineHandle, SessionView } from '@zhushanwen/subagent-engine-sdk';
2
+ import { FrameWriter } from '@zhushanwen/subagent-engine-sdk/server';
2
3
 
3
- /** 出站帧写入面(main.ts 注入 process.stdout;测试注入内存缓冲)。 */
4
- type FrameWriter = (frame: unknown) => void;
5
4
  /** 入站帧来源( readline 已拆行的请求帧 + 反向请求应答帧混流)。 */
6
5
  interface EngineProtocolServerOptions {
7
6
  /** stdout 写入面(每帧一行 JSON)。 */
@@ -23,6 +22,7 @@ declare class EngineProtocolServer {
23
22
  private readonly engine;
24
23
  private readonly reverseClock;
25
24
  private readonly reverseTimeoutMs;
25
+ private readonly frameLoop;
26
26
  private readonly activeRuns;
27
27
  private readonly reversePending;
28
28
  private revSeq;
@@ -283,7 +283,7 @@ declare class ZcodeEngine implements EnginePort {
283
283
  * D6 read 三级降级:①sqlite 原生读取 → ②宿主 event journal 重放(对齐点①接线:
284
284
  * replayJournalToSessionView 复用 live reducer,重放等价性见 §3.3.6)→ ③outcome-only。
285
285
  * sessionId 缺失(解析失败的 run 无法定位 session)跳过①级;②级依赖
286
- * handle.journalPath(宿主 run 后回填)。dbPath:新 handle 恒为隔离库绝对路径
286
+ * handle.eventsPath(宿主 run 后回填)。dbPath:新 handle 恒为隔离库绝对路径
287
287
  * (zcodeSessionDbPath(engineDataDir),tier1 白名单集合见方法体——宿主路径仅
288
288
  * 「共享 HOME 时代」存量兼容);旧 records(池时代)的相对路径仍按池目录锚定
289
289
  * 解析(read 兼容旧数据,池目录不存在时自然落②级 journal 降级)。[池抽象降级
package/dist/index.d.ts CHANGED
@@ -1,7 +1,6 @@
1
1
  import { EnginePort, ReverseRequestClock, EngineCapabilities, ProbeReport, EngineAgentCallOpts, RunContext, EngineRunResult, EngineHandle, SessionView } from '@zhushanwen/subagent-engine-sdk';
2
+ import { FrameWriter } from '@zhushanwen/subagent-engine-sdk/server';
2
3
 
3
- /** 出站帧写入面(main.ts 注入 process.stdout;测试注入内存缓冲)。 */
4
- type FrameWriter = (frame: unknown) => void;
5
4
  /** 入站帧来源( readline 已拆行的请求帧 + 反向请求应答帧混流)。 */
6
5
  interface EngineProtocolServerOptions {
7
6
  /** stdout 写入面(每帧一行 JSON)。 */
@@ -23,6 +22,7 @@ declare class EngineProtocolServer {
23
22
  private readonly engine;
24
23
  private readonly reverseClock;
25
24
  private readonly reverseTimeoutMs;
25
+ private readonly frameLoop;
26
26
  private readonly activeRuns;
27
27
  private readonly reversePending;
28
28
  private revSeq;
@@ -283,7 +283,7 @@ declare class ZcodeEngine implements EnginePort {
283
283
  * D6 read 三级降级:①sqlite 原生读取 → ②宿主 event journal 重放(对齐点①接线:
284
284
  * replayJournalToSessionView 复用 live reducer,重放等价性见 §3.3.6)→ ③outcome-only。
285
285
  * sessionId 缺失(解析失败的 run 无法定位 session)跳过①级;②级依赖
286
- * handle.journalPath(宿主 run 后回填)。dbPath:新 handle 恒为隔离库绝对路径
286
+ * handle.eventsPath(宿主 run 后回填)。dbPath:新 handle 恒为隔离库绝对路径
287
287
  * (zcodeSessionDbPath(engineDataDir),tier1 白名单集合见方法体——宿主路径仅
288
288
  * 「共享 HOME 时代」存量兼容);旧 records(池时代)的相对路径仍按池目录锚定
289
289
  * 解析(read 兼容旧数据,池目录不存在时自然落②级 journal 降级)。[池抽象降级
package/dist/index.js CHANGED
@@ -10,7 +10,7 @@ import {
10
10
  readZcodeSessionView,
11
11
  zcodeDbPathAllowlist,
12
12
  zcodeSessionDbPath
13
- } from "./chunk-F6YT6OGA.js";
13
+ } from "./chunk-DLLNMF45.js";
14
14
 
15
15
  // src/golden-sample.ts
16
16
  var ZCODE_APPSERVER_GOLDEN = {
package/dist/main.cjs CHANGED
@@ -84,9 +84,9 @@ var import_subagent_engine_sdk11 = require("@zhushanwen/subagent-engine-sdk");
84
84
  var import_subagent_engine_sdk = require("@zhushanwen/subagent-engine-sdk");
85
85
  var import_subagent_engine_sdk2 = require("@zhushanwen/subagent-engine-sdk");
86
86
  function replayJournalToSessionView(handle, engineId) {
87
- const journalPath = handle.data.journalPath;
88
- if (journalPath === void 0) return void 0;
89
- const events = (0, import_subagent_engine_sdk2.replayJournal)(journalPath);
87
+ const eventsPath = handle.data.eventsPath;
88
+ if (eventsPath === void 0) return void 0;
89
+ const events = (0, import_subagent_engine_sdk2.replayJournal)(eventsPath);
90
90
  if (events.length === 0) return void 0;
91
91
  return (0, import_subagent_engine_sdk2.eventsToSessionView)(events, engineId, (0, import_subagent_engine_sdk2.sessionIdFromHandle)(handle.data));
92
92
  }
@@ -2558,10 +2558,7 @@ var ZcodeEngine = class {
2558
2558
  engineId: ZCODE_ENGINE_ID,
2559
2559
  content: "",
2560
2560
  durationMs: Date.now() - startedAt,
2561
- ...typeof task.worktree === "object" && task.worktree !== null ? { worktreePath: task.worktree.path } : {},
2562
- // D9① fallback 留痕:路由层经 RunContext 投影(zcode 无 record 通路,outcome 是
2563
- // 唯一留痕面;pi 引擎另有 record 投影)
2564
- ...ctx.engineFallback !== void 0 ? { engineFallback: ctx.engineFallback } : {}
2561
+ ...typeof task.worktree === "object" && task.worktree !== null ? { worktreePath: task.worktree.path } : {}
2565
2562
  };
2566
2563
  const emit = (event) => {
2567
2564
  ctx.onEvent?.(event);
@@ -2656,7 +2653,7 @@ var ZcodeEngine = class {
2656
2653
  * D6 read 三级降级:①sqlite 原生读取 → ②宿主 event journal 重放(对齐点①接线:
2657
2654
  * replayJournalToSessionView 复用 live reducer,重放等价性见 §3.3.6)→ ③outcome-only。
2658
2655
  * sessionId 缺失(解析失败的 run 无法定位 session)跳过①级;②级依赖
2659
- * handle.journalPath(宿主 run 后回填)。dbPath:新 handle 恒为隔离库绝对路径
2656
+ * handle.eventsPath(宿主 run 后回填)。dbPath:新 handle 恒为隔离库绝对路径
2660
2657
  * (zcodeSessionDbPath(engineDataDir),tier1 白名单集合见方法体——宿主路径仅
2661
2658
  * 「共享 HOME 时代」存量兼容);旧 records(池时代)的相对路径仍按池目录锚定
2662
2659
  * 解析(read 兼容旧数据,池目录不存在时自然落②级 journal 降级)。[池抽象降级
@@ -3075,13 +3072,14 @@ function createDefaultZcodeEngine() {
3075
3072
  var import_subagent_engine_sdk13 = require("@zhushanwen/subagent-engine-sdk");
3076
3073
 
3077
3074
  // src/server.ts
3075
+ var import_server = require("@zhushanwen/subagent-engine-sdk/server");
3078
3076
  var logger5 = (0, import_subagent_engine_sdk14.getLogger)("subagents");
3079
- var REVERSE_TIMEOUT_DEFAULT_MS = 6e4;
3080
3077
  var EngineProtocolServer = class {
3081
3078
  write;
3082
3079
  engine;
3083
3080
  reverseClock;
3084
3081
  reverseTimeoutMs;
3082
+ frameLoop;
3085
3083
  activeRuns = /* @__PURE__ */ new Map();
3086
3084
  reversePending = /* @__PURE__ */ new Map();
3087
3085
  revSeq = 0;
@@ -3090,46 +3088,22 @@ var EngineProtocolServer = class {
3090
3088
  this.write = opts.write;
3091
3089
  this.engine = opts.engine ?? createDefaultZcodeEngine();
3092
3090
  this.reverseClock = opts.reverseClock;
3093
- this.reverseTimeoutMs = opts.reverseTimeoutMs ?? REVERSE_TIMEOUT_DEFAULT_MS;
3091
+ this.reverseTimeoutMs = opts.reverseTimeoutMs ?? import_server.REVERSE_TIMEOUT_DEFAULT_MS;
3092
+ this.frameLoop = {
3093
+ write: this.write,
3094
+ settleReverse: (id, frame) => this.settleReverse(id, frame),
3095
+ dispatch: (id, method, params) => this.dispatch(id, method, params),
3096
+ toError: (err) => toProtocolError(err)
3097
+ };
3094
3098
  }
3095
3099
  /** 入站帧消费(请求帧 + 反向请求应答帧;main.ts 的行解析器拆行后喂入)。 */
3096
3100
  handleFrame(frame) {
3097
- if ((0, import_subagent_engine_sdk14.isResponseFrame)(frame)) {
3098
- this.settleReverse(frame.id, frame);
3099
- return;
3100
- }
3101
- if ((0, import_subagent_engine_sdk14.isReverseRequestFrame)(frame)) {
3102
- this.write({
3103
- id: 0,
3104
- error: {
3105
- code: "engine_protocol_bad_frame",
3106
- message: `unexpected reverse request frame from host: ${String(frame.method)}`,
3107
- recovery: "The engine protocol v1 only carries host/* requests engine\u2192host."
3108
- }
3109
- });
3110
- return;
3111
- }
3112
- if (typeof frame === "object" && frame !== null && "id" in frame && "method" in frame && typeof frame.method === "string") {
3113
- const { id, method, params } = frame;
3114
- if (typeof id === "number") {
3115
- void this.dispatch(id, method, params).then(
3116
- (result) => this.write({ id, result }),
3117
- (err) => this.write({ id, error: toProtocolError(err) })
3118
- );
3119
- return;
3120
- }
3121
- }
3101
+ (0, import_server.handleInboundFrame)(frame, this.frameLoop);
3122
3102
  }
3123
3103
  /** 9 正向方法分发(表驱动:method → 处理器;未知方法 → engine_protocol_unknown_method)。 */
3124
3104
  async dispatch(id, method, params) {
3125
3105
  const handler = this.methodHandlers[method];
3126
- if (handler === void 0) {
3127
- throw new import_subagent_engine_sdk14.EngineSdkError(
3128
- "engine_protocol_unknown_method",
3129
- `unknown protocol method: ${method} (request id ${id})`,
3130
- "The engine speaks protocol v1; check the installed engine package version vs the host."
3131
- );
3132
- }
3106
+ if (handler === void 0) throw (0, import_server.unknownMethodError)(id, method);
3133
3107
  return handler(params);
3134
3108
  }
3135
3109
  /**
@@ -3152,42 +3126,23 @@ var EngineProtocolServer = class {
3152
3126
  };
3153
3127
  // ── initialize:版本协商(越界 → engine_protocol_mismatch)+ 能力应答 ──
3154
3128
  initialize(params) {
3155
- if (params?.protocolVersion !== import_subagent_engine_sdk14.ENGINE_PROTOCOL_VERSION) {
3156
- throw new import_subagent_engine_sdk14.EngineSdkError(
3157
- "engine_protocol_mismatch",
3158
- `host protocol version ${String(params?.protocolVersion)} is not compatible with engine protocol v${import_subagent_engine_sdk14.ENGINE_PROTOCOL_VERSION}`,
3159
- `Upgrade the engine package or the host so both speak protocol v${import_subagent_engine_sdk14.ENGINE_PROTOCOL_VERSION}.`
3160
- );
3161
- }
3162
- this.initialized = true;
3163
- const models = this.engine.listModels?.() ?? null;
3164
- return {
3165
- protocolVersion: import_subagent_engine_sdk14.ENGINE_PROTOCOL_VERSION,
3129
+ const result = (0, import_server.initializeEngine)(params, {
3166
3130
  engineId: this.engine.id,
3167
- engineVersion: ZCODE_ADAPTER_VERSION,
3168
3131
  adapterVersion: ZCODE_ADAPTER_VERSION,
3169
3132
  capabilities: this.engine.capabilities(),
3170
- ...models !== null ? { models: models.map((m) => ({ id: m.id })) } : {}
3171
- };
3133
+ listModels: () => this.engine.listModels?.() ?? null
3134
+ });
3135
+ this.initialized = true;
3136
+ return result;
3172
3137
  }
3173
3138
  // ── run:协议载荷 → 本地 AgentCallOpts/RunContext;事件 → 通知/host 通道 ──
3174
3139
  async run(params) {
3175
- if (!this.initialized) {
3176
- throw new import_subagent_engine_sdk14.EngineSdkError(
3177
- "engine_protocol_not_initialized",
3178
- "run before initialize is a protocol violation",
3179
- "The host must complete the initialize handshake before dispatching runs."
3180
- );
3181
- }
3140
+ if (!this.initialized) throw (0, import_server.notInitializedError)();
3182
3141
  const { runId, task, ctx } = params;
3183
3142
  const controller = new AbortController();
3184
3143
  const active = { controller, seq: 0 };
3185
3144
  this.activeRuns.set(runId, active);
3186
- const fullTask = {
3187
- ...task,
3188
- ...ctx.model !== void 0 ? { model: ctx.model } : {},
3189
- ...ctx.cwd !== void 0 ? { cwd: ctx.cwd } : {}
3190
- };
3145
+ const fullTask = (0, import_server.assembleFullTask)(task, ctx);
3191
3146
  const ctxModel = (0, import_subagent_engine_sdk13.parseCtxModel)(ctx.ctxModel);
3192
3147
  const stream = ctx.streamMode === "stream" ? {
3193
3148
  onDelta: (delta) => {
@@ -3200,7 +3155,6 @@ var EngineProtocolServer = class {
3200
3155
  onEvent: (event) => this.emitEvent(runId, event),
3201
3156
  ...ctxModel !== void 0 ? { ctxModel } : {},
3202
3157
  ...stream !== void 0 ? { stream } : {},
3203
- ...ctx.engineFallback !== void 0 ? { engineFallback: ctx.engineFallback } : {},
3204
3158
  // [U6 / §3.2.6 要点 3] resume 锚点透传(宿主 → 引擎的续聊通道:zcode 锚
3205
3159
  // sessionRef {sessionId, dbPath},引擎侧 resume 读 + 新 session 注入消费)。
3206
3160
  ...params.resume !== void 0 ? { resume: params.resume } : {},
@@ -3235,9 +3189,7 @@ var EngineProtocolServer = class {
3235
3189
  }
3236
3190
  // ── 出站:事件通知 + 反向请求客户端 ──
3237
3191
  emitEvent(runId, event) {
3238
- const active = this.activeRuns.get(runId);
3239
- const seq = active !== void 0 ? ++active.seq : 0;
3240
- this.write({ method: "event", params: { runId, seq, event } });
3192
+ (0, import_server.writeRunEvent)(this.write, this.activeRuns, runId, event);
3241
3193
  }
3242
3194
  /**
3243
3195
  * 发反向请求并等应答(帧④必须应答)。计时面登记:发出 → clock.started;收到
@@ -3263,25 +3215,17 @@ var EngineProtocolServer = class {
3263
3215
  return this.reverseRequestInternal(method, params);
3264
3216
  }
3265
3217
  reverseRequestInternal(method, params) {
3266
- const id = `rev-${++this.revSeq}`;
3267
- return new Promise((resolve2, reject) => {
3268
- const timer = setTimeout(() => {
3269
- this.reversePending.delete(id);
3270
- this.reverseClock?.settled(id);
3271
- reject(new Error(`reverse request ${method} (${id}) timed out after ${this.reverseTimeoutMs}ms`));
3272
- }, this.reverseTimeoutMs);
3273
- if (typeof timer.unref === "function") timer.unref();
3274
- this.reversePending.set(id, { resolve: resolve2, reject, timer });
3275
- this.reverseClock?.started(id);
3276
- try {
3277
- this.write({ id, method, params });
3278
- } catch (err) {
3279
- this.reversePending.delete(id);
3280
- clearTimeout(timer);
3281
- this.reverseClock?.settled(id);
3282
- reject(new Error(`reverse request ${method} (${id}) could not be written: ${(0, import_subagent_engine_sdk4.toErrorMessage)(err)}`));
3283
- }
3284
- });
3218
+ return (0, import_server.sendReverseRequest)(
3219
+ {
3220
+ write: this.write,
3221
+ pending: this.reversePending,
3222
+ timeoutMs: this.reverseTimeoutMs,
3223
+ ...this.reverseClock !== void 0 ? { clock: this.reverseClock } : {},
3224
+ nextId: () => `rev-${++this.revSeq}`
3225
+ },
3226
+ method,
3227
+ params
3228
+ );
3285
3229
  }
3286
3230
  /** 反向请求应答落位(ack 两阶段:{ack:true}/{unsupported:true}/{ok:true} 均先 ack 计时面)。 */
3287
3231
  settleReverse(id, frame) {
@@ -3298,13 +3242,9 @@ var EngineProtocolServer = class {
3298
3242
  function probeParamsOf(params) {
3299
3243
  return typeof params === "object" && params !== null ? params : void 0;
3300
3244
  }
3245
+ var RUN_FAILURE_RECOVERY = "Check the engine process logs (engineDataDir/logs/) and rerun; if persistent, reinstall or upgrade the engine package.";
3301
3246
  function toProtocolError(err) {
3302
- if (err instanceof import_subagent_engine_sdk14.EngineSdkError) return err.toStructured();
3303
- return {
3304
- code: "engine_run_failed",
3305
- message: (0, import_subagent_engine_sdk4.toErrorMessage)(err),
3306
- recovery: "Check the engine process logs (engineDataDir/logs/) and rerun; if persistent, reinstall or upgrade the engine package."
3307
- };
3247
+ return (0, import_server.toProtocolError)(err, RUN_FAILURE_RECOVERY);
3308
3248
  }
3309
3249
 
3310
3250
  // src/main.ts
package/dist/main.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  EngineProtocolServer
3
- } from "./chunk-F6YT6OGA.js";
3
+ } from "./chunk-DLLNMF45.js";
4
4
 
5
5
  // src/main.ts
6
6
  import {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zhushanwen/zcode-subagent-cli",
3
- "version": "0.4.3",
3
+ "version": "0.4.4",
4
4
  "description": "zcode subagent engine as an independent CLI package (W5 of subagent-engine-protocolization): speaks engine-protocol v1 over NDJSON stdio, depends only on @zhushanwen/subagent-engine-sdk (never subagent-core)",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -62,7 +62,7 @@
62
62
  "dist/"
63
63
  ],
64
64
  "dependencies": {
65
- "@zhushanwen/subagent-engine-sdk": "0.7.1"
65
+ "@zhushanwen/subagent-engine-sdk": "0.8.0"
66
66
  },
67
67
  "devDependencies": {
68
68
  "@types/node": "^24.0.0",