acpx 0.14.0 → 0.15.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 (32) hide show
  1. package/README.md +3 -3
  2. package/dist/{cli-DSwJ-0g-.js → cli-Cen2Rb6S.js} +4 -4
  3. package/dist/{cli-DSwJ-0g-.js.map → cli-Cen2Rb6S.js.map} +1 -1
  4. package/dist/cli.d.ts +1 -1
  5. package/dist/cli.js +8 -7
  6. package/dist/cli.js.map +1 -1
  7. package/dist/{client-IfFkZz0S.d.ts → client-Cvz6msGc.d.ts} +6 -2
  8. package/dist/client-Cvz6msGc.d.ts.map +1 -0
  9. package/dist/{flags-ftdtbXWd.js → flags-CRh8BJre.js} +3 -3
  10. package/dist/{flags-ftdtbXWd.js.map → flags-CRh8BJre.js.map} +1 -1
  11. package/dist/{flows-DEook1GU.js → flows-D-F3Y2o9.js} +52 -11
  12. package/dist/flows-D-F3Y2o9.js.map +1 -0
  13. package/dist/flows.d.ts +4 -2
  14. package/dist/flows.d.ts.map +1 -1
  15. package/dist/flows.js +1 -1
  16. package/dist/{live-checkpoint-BW9JivEG.js → live-checkpoint-CYRs-D9t.js} +260 -85
  17. package/dist/live-checkpoint-CYRs-D9t.js.map +1 -0
  18. package/dist/{output-jb0298L8.js → output-CIVecnHU.js} +41 -9
  19. package/dist/output-CIVecnHU.js.map +1 -0
  20. package/dist/runtime.d.ts +10 -3
  21. package/dist/runtime.d.ts.map +1 -1
  22. package/dist/runtime.js +45 -7
  23. package/dist/runtime.js.map +1 -1
  24. package/dist/{session-options-DwRDODlr.d.ts → session-options-DyIGRNfu.d.ts} +48 -2
  25. package/dist/session-options-DyIGRNfu.d.ts.map +1 -0
  26. package/package.json +2 -2
  27. package/skills/acpx/SKILL.md +2 -0
  28. package/dist/client-IfFkZz0S.d.ts.map +0 -1
  29. package/dist/flows-DEook1GU.js.map +0 -1
  30. package/dist/live-checkpoint-BW9JivEG.js.map +0 -1
  31. package/dist/output-jb0298L8.js.map +0 -1
  32. package/dist/session-options-DwRDODlr.d.ts.map +0 -1
@@ -454,6 +454,7 @@ const AGENT_REGISTRY = {
454
454
  kilocode: "npx -y @kilocode/cli acp",
455
455
  kimi: "kimi acp",
456
456
  kiro: "kiro-cli-chat acp",
457
+ mcode: "mcode acp",
457
458
  mux: `npx -y mux@${ACP_ADAPTER_PACKAGE_RANGES.mux} acp`,
458
459
  opencode: "npx -y opencode-ai acp",
459
460
  pool: "pool acp",
@@ -507,6 +508,7 @@ const AGENT_ARGV_REGISTRY = {
507
508
  ],
508
509
  kimi: ["kimi", "acp"],
509
510
  kiro: ["kiro-cli-chat", "acp"],
511
+ mcode: ["mcode", "acp"],
510
512
  mux: [
511
513
  "npx",
512
514
  "-y",
@@ -3145,14 +3147,18 @@ function promotePrefixedAuthEnvironment(env) {
3145
3147
  }
3146
3148
  return protectedKeys;
3147
3149
  }
3148
- function buildAgentEnvironment(authCredentials, sessionEnv) {
3150
+ function validateAgentProcessEnv(agentProcessEnv) {
3151
+ for (const [key, value] of Object.entries(agentProcessEnv ?? {})) if (typeof value !== "string" || key.includes("=") || key.includes("\0") || value.includes("\0")) throw new Error("Invalid agentProcessEnv: environment entries cannot contain NUL or names with '='");
3152
+ }
3153
+ function buildAgentEnvironment(authCredentials, sessionEnv, agentProcessEnv) {
3154
+ validateAgentProcessEnv(agentProcessEnv);
3149
3155
  const env = { ...process.env };
3150
3156
  const protectedAuthEnvKeys = promotePrefixedAuthEnvironment(env);
3151
3157
  if (authCredentials) for (const [methodId, credential] of Object.entries(authCredentials)) {
3152
3158
  addAuthCredentialEnvKeys(protectedAuthEnvKeys, methodId, credential);
3153
3159
  assignAuthCredentialEnv(env, methodId, credential);
3154
3160
  }
3155
- if (sessionEnv) for (const [key, value] of Object.entries(sessionEnv)) {
3161
+ for (const overlay of [sessionEnv, agentProcessEnv]) for (const [key, value] of Object.entries(overlay ?? {})) {
3156
3162
  if (typeof value !== "string" || protectedAuthEnvKeys.has(protectedEnvKey(key))) continue;
3157
3163
  assignSessionEnv(env, key, value);
3158
3164
  }
@@ -3188,10 +3194,10 @@ function resolveConfiguredAuthCredential(methodId, authCredentials) {
3188
3194
  const configCredentials = authCredentials ?? {};
3189
3195
  return configCredentials[methodId] ?? configCredentials[toEnvToken(methodId)];
3190
3196
  }
3191
- function buildAgentSpawnOptions(cwd, authCredentials, sessionEnv) {
3197
+ function buildAgentSpawnOptions(cwd, authCredentials, sessionEnv, agentProcessEnv) {
3192
3198
  return {
3193
3199
  cwd,
3194
- env: buildAgentEnvironment(authCredentials, sessionEnv),
3200
+ env: buildAgentEnvironment(authCredentials, sessionEnv, agentProcessEnv),
3195
3201
  stdio: [
3196
3202
  "pipe",
3197
3203
  "pipe",
@@ -3320,6 +3326,93 @@ function assertRequestedModelSupported(params) {
3320
3326
  }
3321
3327
  }
3322
3328
  //#endregion
3329
+ //#region src/acp/ndjson-stream.ts
3330
+ var AcpMessageLimitError = class extends AcpxOperationalError {
3331
+ constructor(limit) {
3332
+ super(`ACP message exceeded ACPX_MAX_ACP_MESSAGE_BYTES (${limit} bytes)`, {
3333
+ outputCode: "RUNTIME",
3334
+ detailCode: "ACP_MESSAGE_TOO_LARGE",
3335
+ origin: "acp",
3336
+ retryable: false
3337
+ });
3338
+ }
3339
+ };
3340
+ function readMaxAcpMessageBytes(raw = process.env.ACPX_MAX_ACP_MESSAGE_BYTES) {
3341
+ const value = raw?.trim();
3342
+ if (!value) return;
3343
+ const bytes = Number(value);
3344
+ if (!/^\d+$/.test(value) || !Number.isSafeInteger(bytes)) throw new Error("ACPX_MAX_ACP_MESSAGE_BYTES must be a non-negative safe integer; zero is unlimited");
3345
+ return bytes === 0 ? void 0 : bytes;
3346
+ }
3347
+ function countLineBytes(chunk, retained, limit) {
3348
+ let start = 0;
3349
+ while (start < chunk.length) {
3350
+ const newline = chunk.indexOf(10, start);
3351
+ const end = newline < 0 ? chunk.length : newline;
3352
+ retained += end - start;
3353
+ if (retained > limit) throw new AcpMessageLimitError(limit);
3354
+ if (newline < 0) return retained;
3355
+ retained = 0;
3356
+ start = end + 1;
3357
+ }
3358
+ return retained;
3359
+ }
3360
+ function parseAcpJsonMessageLine(line) {
3361
+ const message = JSON.parse(line);
3362
+ return isAcpMessageObject(message) ? message : void 0;
3363
+ }
3364
+ function enqueueNdJsonLine(agentCommand, line, controller) {
3365
+ const trimmedLine = line.trim();
3366
+ if (!trimmedLine || shouldIgnoreNonJsonAgentOutputLine(agentCommand, trimmedLine)) return;
3367
+ try {
3368
+ const message = parseAcpJsonMessageLine(trimmedLine);
3369
+ if (message) controller.enqueue(message);
3370
+ } catch (err) {
3371
+ console.error("Failed to parse JSON message:", trimmedLine, err);
3372
+ }
3373
+ }
3374
+ function enqueueNdJsonLines(agentCommand, lines, controller) {
3375
+ for (const line of lines) enqueueNdJsonLine(agentCommand, line, controller);
3376
+ }
3377
+ function createNdJsonMessageStream(agentCommand, output, input, maxMessageBytes, onReadError) {
3378
+ const textEncoder = new TextEncoder();
3379
+ const textDecoder = new TextDecoder();
3380
+ return {
3381
+ readable: new ReadableStream({ async start(controller) {
3382
+ let content = "";
3383
+ let retainedBytes = 0;
3384
+ const reader = input.getReader();
3385
+ try {
3386
+ while (true) {
3387
+ const { value, done } = await reader.read();
3388
+ if (done) break;
3389
+ if (maxMessageBytes !== void 0) retainedBytes = countLineBytes(value, retainedBytes, maxMessageBytes);
3390
+ content += textDecoder.decode(value, { stream: true });
3391
+ const lines = content.split("\n");
3392
+ content = lines.pop() || "";
3393
+ enqueueNdJsonLines(agentCommand, lines, controller);
3394
+ }
3395
+ controller.close();
3396
+ } catch (err) {
3397
+ const error = err instanceof Error ? err : new Error(String(err));
3398
+ controller.error(error);
3399
+ onReadError?.(error);
3400
+ } finally {
3401
+ reader.releaseLock();
3402
+ }
3403
+ } }),
3404
+ writable: new WritableStream({ async write(message) {
3405
+ const content = JSON.stringify(message) + "\n";
3406
+ const writer = output.getWriter();
3407
+ try {
3408
+ await writer.write(textEncoder.encode(content));
3409
+ } finally {
3410
+ writer.releaseLock();
3411
+ }
3412
+ } })
3413
+ };
3414
+ }
3415
+ //#endregion
3323
3416
  //#region src/acp/session-control-errors.ts
3324
3417
  const SESSION_CONTROL_UNSUPPORTED_ACP_CODES = /* @__PURE__ */ new Set([-32601, -32602]);
3325
3418
  function asRecord$1(value) {
@@ -4006,6 +4099,17 @@ function snapshotPermissionPolicy(policy) {
4006
4099
  ...policy.defaultAction ? { defaultAction: policy.defaultAction } : {}
4007
4100
  };
4008
4101
  }
4102
+ function snapshotProcessLaunchScope(scope) {
4103
+ if (!scope || scope.kind === "client") return Object.freeze({ kind: "client" });
4104
+ if (scope.kind === "runtime-session") return Object.freeze({
4105
+ kind: "runtime-session",
4106
+ sessionKey: scope.sessionKey
4107
+ });
4108
+ return Object.freeze({
4109
+ kind: "runtime-probe",
4110
+ agent: scope.agent
4111
+ });
4112
+ }
4009
4113
  function childProcessIsRunning(agent) {
4010
4114
  if (!agent) return false;
4011
4115
  return agent.exitCode == null && agent.signalCode == null && !agent.killed;
@@ -4027,56 +4131,6 @@ function installSdkConsoleErrorSuppression() {
4027
4131
  console.error = originalConsoleError;
4028
4132
  };
4029
4133
  }
4030
- function enqueueNdJsonLine(agentCommand, line, controller) {
4031
- const trimmedLine = line.trim();
4032
- if (!trimmedLine || shouldIgnoreNonJsonAgentOutputLine(agentCommand, trimmedLine)) return;
4033
- try {
4034
- const message = parseAcpJsonMessageLine(trimmedLine);
4035
- if (message) controller.enqueue(message);
4036
- } catch (err) {
4037
- console.error("Failed to parse JSON message:", trimmedLine, err);
4038
- }
4039
- }
4040
- function parseAcpJsonMessageLine(line) {
4041
- const message = JSON.parse(line);
4042
- return isAcpMessageObject(message) ? message : void 0;
4043
- }
4044
- function enqueueNdJsonLines(agentCommand, lines, controller) {
4045
- for (const line of lines) enqueueNdJsonLine(agentCommand, line, controller);
4046
- }
4047
- function createNdJsonMessageStream(agentCommand, output, input) {
4048
- const textEncoder = new TextEncoder();
4049
- const textDecoder = new TextDecoder();
4050
- return {
4051
- readable: new ReadableStream({ async start(controller) {
4052
- let content = "";
4053
- const reader = input.getReader();
4054
- try {
4055
- while (true) {
4056
- const { value, done } = await reader.read();
4057
- if (done) break;
4058
- if (!value) continue;
4059
- content += textDecoder.decode(value, { stream: true });
4060
- const lines = content.split("\n");
4061
- content = lines.pop() || "";
4062
- enqueueNdJsonLines(agentCommand, lines, controller);
4063
- }
4064
- } finally {
4065
- reader.releaseLock();
4066
- controller.close();
4067
- }
4068
- } }),
4069
- writable: new WritableStream({ async write(message) {
4070
- const content = JSON.stringify(message) + "\n";
4071
- const writer = output.getWriter();
4072
- try {
4073
- await writer.write(textEncoder.encode(content));
4074
- } finally {
4075
- writer.releaseLock();
4076
- }
4077
- } })
4078
- };
4079
- }
4080
4134
  var AcpClient = class {
4081
4135
  options;
4082
4136
  connection;
@@ -4113,6 +4167,7 @@ var AcpClient = class {
4113
4167
  this.options = {
4114
4168
  ...options,
4115
4169
  cwd: asAbsoluteCwd(options.cwd),
4170
+ agentProcessEnv: options.agentProcessEnv ? { ...options.agentProcessEnv } : void 0,
4116
4171
  authPolicy: options.authPolicy ?? "skip",
4117
4172
  permissionPolicy: snapshotPermissionPolicy(options.permissionPolicy),
4118
4173
  elicitationModes: normalizeElicitationModes(options.elicitationModes)
@@ -4217,29 +4272,41 @@ var AcpClient = class {
4217
4272
  async start() {
4218
4273
  if (this.connection && this.agent && isChildProcessRunning(this.agent)) return;
4219
4274
  if (this.connection || this.agent) await this.close();
4275
+ const maxMessageBytes = readMaxAcpMessageBytes();
4220
4276
  const launch = await this.resolveAgentLaunchPlan();
4221
4277
  this.logAgentLaunch(launch);
4222
4278
  await this.ensureLaunchSupport(launch);
4223
- const child = await this.spawnAgentProcess(launch);
4279
+ const { child, process: startedProcess } = await this.spawnAgentProcess(launch);
4224
4280
  this.closing = false;
4225
- this.agentStartedAt = isoNow$1();
4281
+ this.agentStartedAt = startedProcess.startedAt;
4226
4282
  this.lastAgentExit = void 0;
4227
- this.lastKnownPid = child.pid ?? void 0;
4228
- this.attachAgentLifecycleObservers(child);
4283
+ this.lastKnownPid = startedProcess.pid;
4229
4284
  const startupStderr = [];
4230
4285
  child.stderr.on("data", (chunk) => {
4231
4286
  this.captureStartupStderr(startupStderr, chunk);
4232
4287
  if (!this.options.verbose) return;
4233
4288
  process.stderr.write(chunk);
4234
4289
  });
4290
+ const startupFailure = this.createStartupFailureWatcher(child, startupStderr);
4291
+ try {
4292
+ await this.admitAndObserveSpawnedProcess(child, startedProcess);
4293
+ const admissionExit = startupFailure.getError();
4294
+ if (admissionExit) throw admissionExit;
4295
+ } catch (error) {
4296
+ startupFailure.dispose();
4297
+ throw error;
4298
+ }
4235
4299
  const input = Writable.toWeb(child.stdin);
4236
4300
  const output = Readable.toWeb(child.stdout);
4237
- const stream = this.createTappedStream(createNdJsonMessageStream(this.options.agentCommand, input, output));
4238
- const connection = this.createConnection(stream, launch);
4301
+ let connection;
4302
+ const stream = this.createTappedStream(createNdJsonMessageStream(this.options.agentCommand, input, output, maxMessageBytes, (error) => {
4303
+ this.rejectPendingConnectionRequests(error);
4304
+ connection?.close?.(error);
4305
+ }));
4306
+ connection = this.createConnection(stream, launch);
4239
4307
  connection.signal.addEventListener("abort", () => {
4240
4308
  this.recordAgentExit("connection_close", child.exitCode ?? null, child.signalCode ?? null);
4241
4309
  }, { once: true });
4242
- const startupFailure = this.createStartupFailureWatcher(child, startupStderr);
4243
4310
  await this.initializeAgentConnection({
4244
4311
  child,
4245
4312
  connection,
@@ -4263,7 +4330,7 @@ var AcpClient = class {
4263
4330
  geminiAcp: isGeminiAcpCommand(spawnCommand, args),
4264
4331
  copilotAcp: isCopilotAcpCommand(spawnCommand, args),
4265
4332
  claudeAcp: isClaudeAcpCommand(spawnCommand, args),
4266
- spawnOptions: buildAgentSpawnOptions(this.options.cwd, this.options.authCredentials, this.options.sessionOptions?.env)
4333
+ spawnOptions: buildAgentSpawnOptions(this.options.cwd, this.options.authCredentials, this.options.sessionOptions?.env, this.options.agentProcessEnv)
4267
4334
  };
4268
4335
  }
4269
4336
  logAgentLaunch(plan) {
@@ -4289,16 +4356,57 @@ var AcpClient = class {
4289
4356
  }
4290
4357
  async spawnAgentProcess(plan) {
4291
4358
  const spawnCommand = buildAgentSpawnCommand(plan.spawnCommand, plan.args, process.platform, plan.spawnOptions.env);
4292
- const spawnedChild = spawn(spawnCommand.command, spawnCommand.args, {
4293
- ...plan.spawnOptions,
4294
- windowsVerbatimArguments: spawnCommand.windowsVerbatimArguments
4359
+ const launch = Object.freeze({
4360
+ launchId: randomUUID(),
4361
+ scope: snapshotProcessLaunchScope(this.options.processLaunchScope),
4362
+ command: spawnCommand.command,
4363
+ args: Object.freeze([...spawnCommand.args]),
4364
+ cwd: this.options.cwd
4295
4365
  });
4366
+ await this.options.processLifecycle?.onBeforeSpawn?.(launch);
4367
+ let spawnedChild;
4296
4368
  try {
4369
+ spawnedChild = spawn(spawnCommand.command, spawnCommand.args, {
4370
+ ...plan.spawnOptions,
4371
+ windowsVerbatimArguments: spawnCommand.windowsVerbatimArguments
4372
+ });
4297
4373
  await waitForSpawn$1(spawnedChild);
4298
4374
  } catch (error) {
4299
- throw new AgentSpawnError(this.options.agentCommand, error);
4375
+ const spawnError = new AgentSpawnError(this.options.agentCommand, error);
4376
+ this.notifyProcessSpawnFailure(launch, spawnError);
4377
+ throw spawnError;
4378
+ }
4379
+ const child = requireAgentStdio(spawnedChild);
4380
+ const pid = child.pid;
4381
+ if (pid === void 0) {
4382
+ const spawnError = new AgentSpawnError(this.options.agentCommand, /* @__PURE__ */ new Error("spawned agent process did not expose a PID"));
4383
+ this.notifyProcessSpawnFailure(launch, spawnError);
4384
+ await this.terminateAgentProcess(child);
4385
+ throw spawnError;
4386
+ }
4387
+ return {
4388
+ child,
4389
+ process: Object.freeze({
4390
+ ...launch,
4391
+ pid,
4392
+ startedAt: isoNow$1()
4393
+ })
4394
+ };
4395
+ }
4396
+ async admitAndObserveSpawnedProcess(child, process) {
4397
+ let releaseExitNotification = () => {};
4398
+ const exitNotificationBarrier = new Promise((resolve) => {
4399
+ releaseExitNotification = resolve;
4400
+ });
4401
+ this.attachAgentLifecycleObservers(child, process, exitNotificationBarrier);
4402
+ try {
4403
+ await this.options.processLifecycle?.onSpawned?.(process);
4404
+ } catch (error) {
4405
+ await this.terminateAgentProcess(child);
4406
+ throw error;
4407
+ } finally {
4408
+ releaseExitNotification();
4300
4409
  }
4301
- return requireAgentStdio(spawnedChild);
4302
4410
  }
4303
4411
  createConnection(stream, launch) {
4304
4412
  const app = client({ name: "acpx" }).onNotification(methods.client.session.update, async ({ params }) => {
@@ -4357,7 +4465,7 @@ var AcpClient = class {
4357
4465
  }
4358
4466
  async handleInitializeFailure(params, error) {
4359
4467
  params.startupFailure.dispose();
4360
- const normalizedError = await this.normalizeInitializeError(error, params.child, params.startupStderr);
4468
+ const normalizedError = error instanceof AcpMessageLimitError ? error : await this.normalizeInitializeError(error, params.child, params.startupStderr);
4361
4469
  try {
4362
4470
  params.child.kill();
4363
4471
  } catch {}
@@ -4822,6 +4930,7 @@ var AcpClient = class {
4822
4930
  }
4823
4931
  createStartupFailureWatcher(child, startupStderr) {
4824
4932
  let settled = false;
4933
+ let failure;
4825
4934
  let rejectPromise;
4826
4935
  const cleanup = () => {
4827
4936
  child.off("error", onError);
@@ -4832,7 +4941,10 @@ var AcpClient = class {
4832
4941
  if (settled) return;
4833
4942
  settled = true;
4834
4943
  cleanup();
4835
- if (error) rejectPromise(error);
4944
+ if (error) {
4945
+ failure = error;
4946
+ rejectPromise(error);
4947
+ }
4836
4948
  };
4837
4949
  const createError = (params) => new AgentStartupError({
4838
4950
  agentCommand: this.options.agentCommand,
@@ -4856,14 +4968,18 @@ var AcpClient = class {
4856
4968
  signal
4857
4969
  }));
4858
4970
  };
4971
+ const promise = new Promise((_resolve, reject) => {
4972
+ rejectPromise = reject;
4973
+ child.once("error", onError);
4974
+ child.once("exit", onExit);
4975
+ child.once("close", onClose);
4976
+ if (child.exitCode !== null || child.signalCode !== null) onExit(child.exitCode, child.signalCode);
4977
+ });
4978
+ promise.catch(() => {});
4859
4979
  return {
4860
- promise: new Promise((_resolve, reject) => {
4861
- rejectPromise = reject;
4862
- child.once("error", onError);
4863
- child.once("exit", onExit);
4864
- child.once("close", onClose);
4865
- }),
4866
- dispose: () => finish()
4980
+ promise,
4981
+ dispose: () => finish(),
4982
+ getError: () => failure
4867
4983
  };
4868
4984
  }
4869
4985
  async normalizeInitializeError(error, child, startupStderr) {
@@ -5043,10 +5159,19 @@ var AcpClient = class {
5043
5159
  recorded: true
5044
5160
  };
5045
5161
  }
5046
- attachAgentLifecycleObservers(child) {
5047
- child.once("exit", (exitCode, signal) => {
5162
+ attachAgentLifecycleObservers(child, startedProcess, exitNotificationBarrier) {
5163
+ const onExit = (exitCode, signal) => {
5164
+ const exitedAt = isoNow$1();
5048
5165
  this.recordAgentExit("process_exit", exitCode, signal);
5049
- });
5166
+ exitNotificationBarrier.then(() => {
5167
+ this.notifyProcessExit(startedProcess, exitCode, signal, exitedAt);
5168
+ });
5169
+ };
5170
+ child.once("exit", onExit);
5171
+ if (child.exitCode !== null || child.signalCode !== null) {
5172
+ child.off("exit", onExit);
5173
+ onExit(child.exitCode, child.signalCode);
5174
+ }
5050
5175
  child.once("close", (exitCode, signal) => {
5051
5176
  this.recordAgentExit("process_close", exitCode, signal);
5052
5177
  });
@@ -5054,6 +5179,43 @@ var AcpClient = class {
5054
5179
  this.recordAgentExit("pipe_close", child.exitCode ?? null, child.signalCode ?? null);
5055
5180
  });
5056
5181
  }
5182
+ notifyProcessSpawnFailure(launch, error) {
5183
+ const handler = this.options.processLifecycle?.onSpawnFailed;
5184
+ if (!handler) return;
5185
+ const event = Object.freeze({
5186
+ ...launch,
5187
+ error,
5188
+ failedAt: isoNow$1()
5189
+ });
5190
+ try {
5191
+ Promise.resolve(handler(event)).catch((observerError) => {
5192
+ this.logProcessLifecycleError("onSpawnFailed", observerError);
5193
+ });
5194
+ } catch (observerError) {
5195
+ this.logProcessLifecycleError("onSpawnFailed", observerError);
5196
+ }
5197
+ }
5198
+ notifyProcessExit(startedProcess, exitCode, signal, exitedAt) {
5199
+ const handler = this.options.processLifecycle?.onExit;
5200
+ if (!handler) return;
5201
+ const event = Object.freeze({
5202
+ ...startedProcess,
5203
+ exitCode,
5204
+ signal,
5205
+ exitedAt
5206
+ });
5207
+ try {
5208
+ Promise.resolve(handler(event)).catch((error) => {
5209
+ this.logProcessLifecycleError("onExit", error);
5210
+ });
5211
+ } catch (error) {
5212
+ this.logProcessLifecycleError("onExit", error);
5213
+ }
5214
+ }
5215
+ logProcessLifecycleError(hook, error) {
5216
+ const message = error instanceof Error ? error.message : String(error);
5217
+ this.log(`process lifecycle ${hook} hook failed: ${message}`);
5218
+ }
5057
5219
  recordAgentExit(reason, exitCode, signal) {
5058
5220
  if (this.lastAgentExit) return;
5059
5221
  this.lastAgentExit = {
@@ -6482,9 +6644,24 @@ async function withConnectedSession(options) {
6482
6644
  //#region src/runtime/engine/prompt-turn.ts
6483
6645
  const SESSION_REPLY_IDLE_MS = 1e3;
6484
6646
  const SESSION_REPLY_DRAIN_TIMEOUT_MS = 5e3;
6647
+ function responseMetaField(meta) {
6648
+ return meta === void 0 ? {} : { _meta: meta };
6649
+ }
6650
+ function recoveredSessionResult(response, conversation, promptMessageId) {
6651
+ recordPromptResponseUsage(conversation, response?.usage, promptMessageId);
6652
+ return {
6653
+ stopReason: "end_turn",
6654
+ source: "session",
6655
+ ...responseMetaField(response?._meta)
6656
+ };
6657
+ }
6485
6658
  async function runPromptTurn(params) {
6659
+ let settledResponse;
6486
6660
  try {
6487
6661
  const promptPromise = params.client.prompt(params.sessionId, params.prompt, params.onPromptRequestWritten, params.onElicitation);
6662
+ promptPromise.then((response) => {
6663
+ settledResponse = response;
6664
+ }, () => {});
6488
6665
  await params.onPromptStarted?.();
6489
6666
  const response = await withTimeout(promptPromise, params.timeoutMs);
6490
6667
  await params.client.waitForSessionUpdatesIdle?.({
@@ -6494,7 +6671,8 @@ async function runPromptTurn(params) {
6494
6671
  recordPromptResponseUsage(params.conversation, response.usage, params.promptMessageId);
6495
6672
  return {
6496
6673
  stopReason: response.stopReason,
6497
- source: "rpc"
6674
+ source: "rpc",
6675
+ ...responseMetaField(response._meta)
6498
6676
  };
6499
6677
  } catch (error) {
6500
6678
  if (!(error instanceof TimeoutError) || !params.promptMessageId) throw error;
@@ -6502,10 +6680,7 @@ async function runPromptTurn(params) {
6502
6680
  idleMs: SESSION_REPLY_IDLE_MS,
6503
6681
  timeoutMs: SESSION_REPLY_DRAIN_TIMEOUT_MS
6504
6682
  }).catch(() => {});
6505
- if (hasAgentReplyAfterPrompt(params.conversation, params.promptMessageId)) return {
6506
- stopReason: "end_turn",
6507
- source: "session"
6508
- };
6683
+ if (hasAgentReplyAfterPrompt(params.conversation, params.promptMessageId)) return recoveredSessionResult(settledResponse, params.conversation, params.promptMessageId);
6509
6684
  throw error;
6510
6685
  }
6511
6686
  }
@@ -6565,4 +6740,4 @@ var LiveSessionCheckpoint = class {
6565
6740
  //#endregion
6566
6741
  export { formatPerfMetric as $, AgentSpawnError as $t, RequestedModelUnsupportedError as A, DEFAULT_AGENT_NAME as At, absolutePath as B, extractAcpError as Bt, sessionOptionsFromRecord as C, parsePromptSource as Ct, AcpClient as D, TimeoutError as Dt, reconcileAgentSessionId as E, InterruptedError as Et, runTimedExecFile as F, resolveCanonicalAgentName as Ft, listSessions as G, NON_INTERACTIVE_PERMISSION_POLICIES as Gt, findSession as H, toAcpErrorPayload as Ht, splitCommandLine as I, exitCodeForOutputErrorCode as It, pruneSessions as J, OUTPUT_FORMATS as Jt, listSessionsForAgent as K, OUTPUT_ERROR_CODES as Kt, getAcpxVersion as L, formatErrorMessage as Lt, modelStateFromConfigOptions as M, normalizeAgentName$1 as Mt, normalizeAgentCommandInput as N, resolveAgentArgv as Nt, REQUESTED_MODEL_UNSUPPORTED_ERROR_CODE as O, withInterrupt as Ot, renderArgvIdentity as P, resolveAgentCommand as Pt, assertPersistedKeyPolicy as Q, AcpxOperationalError as Qt, permissionModeSatisfies as R, isRetryablePromptError as Rt, persistSessionOptions as S, mergePromptSourceWithText as St, applyLifecycleSnapshotToRecord as T, textPrompt as Tt, findSessionByDirectoryWalk as U, AUTH_POLICIES as Ut, findGitRepositoryRoot as V, isAcpResourceNotFoundError as Vt, isoNow$2 as W, EXIT_CODES as Wt, writeSessionRecord as X, PERMISSION_POLICY_ACTIONS as Xt, resolveSessionRecord as Y, PERMISSION_MODES as Yt, createAtomicWriteTempPath as Z, SESSION_RECORD_SCHEMA as Zt, recordPromptSubmission as _, isAcpJsonRpcMessage as _t, applyConfigOptionSelection as a, setPerfGauge as at, advertisedModelState as b, PromptInputValidationError as bt, applyRequestedModelIfAdvertised as c, serializeSessionRecordForDisk as ct, setDesiredModeId as d, defaultSessionEventLog as dt, QueueConnectionError as en, getPerfMetricsSnapshot as et, syncAdvertisedModelState as f, sessionBaseDir$1 as ft, recordClientOperation as g, extractSessionUpdateNotification as gt, createSessionConversation as h, sessionEventSegmentPath as ht, connectAndLoadSession as i, resetPerfMetrics as it, isRequestedModelUnsupportedError as j, listBuiltInAgents as jt, REQUESTED_MODEL_UNSUPPORTED_REASONS as k, withTimeout as kt, currentModelIdFromSetModelResponse as l, normalizeRuntimeSessionId as lt, cloneSessionConversation as m, sessionEventLockPath as mt, runPromptTurn as n, measurePerf as nt, applyConfigOptionsToRecord as o, startPerfTimer as ot, cloneSessionAcpxState as p, sessionEventActivePath as pt, normalizeName as q, OUTPUT_ERROR_ORIGINS as qt, withConnectedSession as r, recordPerfDuration as rt, applyModelSelection as s, parseSessionRecord as st, LiveSessionCheckpoint as t, QueueProtocolError as tn, incrementPerfCounter as tt, setCurrentModelId as u, DEFAULT_EVENT_SEGMENT_MAX_BYTES as ut, recordSessionUpdate as v, parseJsonRpcErrorMessage as vt, applyConversation as w, promptToDisplayText as wt, mergeSessionOptions as x, isPromptInput as xt, trimConversationForRuntime as y, parsePromptStopReason as yt, DEFAULT_HISTORY_LIMIT as z, normalizeOutputError as zt };
6567
6742
 
6568
- //# sourceMappingURL=live-checkpoint-BW9JivEG.js.map
6743
+ //# sourceMappingURL=live-checkpoint-CYRs-D9t.js.map