@moxt-ai/mobius 0.0.299 → 0.0.301

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 (86) hide show
  1. package/dist/acp/harness/claude/endpoint.d.ts.map +1 -1
  2. package/dist/acp/harness/claude/endpoint.js +2 -0
  3. package/dist/acp/harness/claude/endpoint.js.map +1 -1
  4. package/dist/acp/harness/claude/parent-lifeline.d.ts +3 -0
  5. package/dist/acp/harness/claude/parent-lifeline.d.ts.map +1 -0
  6. package/dist/acp/harness/claude/parent-lifeline.js +73 -0
  7. package/dist/acp/harness/claude/parent-lifeline.js.map +1 -0
  8. package/dist/acp/harness/codex/settings.d.ts.map +1 -1
  9. package/dist/acp/harness/codex/settings.js +4 -0
  10. package/dist/acp/harness/codex/settings.js.map +1 -1
  11. package/dist/acp/harness/pi/endpoint.d.ts.map +1 -1
  12. package/dist/acp/harness/pi/endpoint.js +1 -0
  13. package/dist/acp/harness/pi/endpoint.js.map +1 -1
  14. package/dist/acp/native-history/codex/native-history-events.d.ts.map +1 -1
  15. package/dist/acp/native-history/codex/native-history-events.js +10 -0
  16. package/dist/acp/native-history/codex/native-history-events.js.map +1 -1
  17. package/dist/cli.js +604 -60
  18. package/dist/cli.js.map +4 -4
  19. package/dist/generated/acp-session-store-migrations.d.ts +3 -0
  20. package/dist/generated/acp-session-store-migrations.d.ts.map +1 -1
  21. package/dist/generated/acp-session-store-migrations.js +5 -1
  22. package/dist/generated/acp-session-store-migrations.js.map +1 -1
  23. package/dist/runtime/command/registry/prompt.d.ts.map +1 -1
  24. package/dist/runtime/command/registry/prompt.js +6 -0
  25. package/dist/runtime/command/registry/prompt.js.map +1 -1
  26. package/dist/runtime/engine.d.ts +1 -0
  27. package/dist/runtime/engine.d.ts.map +1 -1
  28. package/dist/runtime/engine.js +8 -0
  29. package/dist/runtime/engine.js.map +1 -1
  30. package/dist/runtime/run.d.ts +1 -0
  31. package/dist/runtime/run.d.ts.map +1 -1
  32. package/dist/runtime/run.js +3 -0
  33. package/dist/runtime/run.js.map +1 -1
  34. package/dist/runtime.js +569 -53
  35. package/dist/runtime.js.map +4 -4
  36. package/dist/schema/acp-session-store/execution-receipt.d.ts +136 -0
  37. package/dist/schema/acp-session-store/execution-receipt.d.ts.map +1 -0
  38. package/dist/schema/acp-session-store/execution-receipt.js +12 -0
  39. package/dist/schema/acp-session-store/execution-receipt.js.map +1 -0
  40. package/dist/schema/acp-session-store/index.d.ts +1 -0
  41. package/dist/schema/acp-session-store/index.d.ts.map +1 -1
  42. package/dist/schema/acp-session-store/index.js +1 -0
  43. package/dist/schema/acp-session-store/index.js.map +1 -1
  44. package/dist/session/api/session-api.d.ts +4 -0
  45. package/dist/session/api/session-api.d.ts.map +1 -1
  46. package/dist/session/api/session-api.js.map +1 -1
  47. package/dist/session/api/session-layer.d.ts +2 -0
  48. package/dist/session/api/session-layer.d.ts.map +1 -1
  49. package/dist/session/api/session-layer.js +25 -4
  50. package/dist/session/api/session-layer.js.map +1 -1
  51. package/dist/session/history/session-event-store.d.ts +7 -4
  52. package/dist/session/history/session-event-store.d.ts.map +1 -1
  53. package/dist/session/history/session-event-store.js +13 -7
  54. package/dist/session/history/session-event-store.js.map +1 -1
  55. package/dist/session/history/session-history.d.ts +1 -4
  56. package/dist/session/history/session-history.d.ts.map +1 -1
  57. package/dist/session/history/session-history.js +1 -4
  58. package/dist/session/history/session-history.js.map +1 -1
  59. package/dist/session/live/agent-session-restore.d.ts +1 -0
  60. package/dist/session/live/agent-session-restore.d.ts.map +1 -1
  61. package/dist/session/live/agent-session.d.ts +2 -0
  62. package/dist/session/live/agent-session.d.ts.map +1 -1
  63. package/dist/session/live/agent-session.js +15 -4
  64. package/dist/session/live/agent-session.js.map +1 -1
  65. package/dist/session/live/session-restore.d.ts.map +1 -1
  66. package/dist/session/live/session-restore.js +37 -0
  67. package/dist/session/live/session-restore.js.map +1 -1
  68. package/dist/session/manager/session-manager.d.ts.map +1 -1
  69. package/dist/session/manager/session-manager.js +11 -3
  70. package/dist/session/manager/session-manager.js.map +1 -1
  71. package/dist/session/prompt/execute-prompt.d.ts.map +1 -1
  72. package/dist/session/prompt/execute-prompt.js +6 -1
  73. package/dist/session/prompt/execute-prompt.js.map +1 -1
  74. package/dist/session/prompt/prompt-lifecycle.d.ts +1 -0
  75. package/dist/session/prompt/prompt-lifecycle.d.ts.map +1 -1
  76. package/dist/session/prompt/prompt-lifecycle.js +9 -1
  77. package/dist/session/prompt/prompt-lifecycle.js.map +1 -1
  78. package/dist/session/turn/execution-receipts.d.ts +23 -2
  79. package/dist/session/turn/execution-receipts.d.ts.map +1 -1
  80. package/dist/session/turn/execution-receipts.js +161 -10
  81. package/dist/session/turn/execution-receipts.js.map +1 -1
  82. package/dist/storage/session/execution-receipt-table.d.ts +45 -0
  83. package/dist/storage/session/execution-receipt-table.d.ts.map +1 -0
  84. package/dist/storage/session/execution-receipt-table.js +64 -0
  85. package/dist/storage/session/execution-receipt-table.js.map +1 -0
  86. package/package.json +2 -2
package/dist/cli.js CHANGED
@@ -2086,16 +2086,28 @@ var init_package = __esm({
2086
2086
  "package.json"() {
2087
2087
  package_default = {
2088
2088
  name: "@moxt-ai/mobius",
2089
- version: "0.0.299",
2089
+ version: "0.0.301",
2090
2090
  description: "Mobius CLI for pairing and running local AI agent services.",
2091
2091
  type: "module",
2092
2092
  bin: {
2093
2093
  mobius: "dist/cli.js"
2094
2094
  },
2095
2095
  exports: {
2096
- "./runtime": "./src/runtime.ts",
2097
- "./process": "./src/util/process/executable.ts",
2098
- "./filesystem": "./src/util/filesystem/private-path.ts"
2096
+ "./runtime": {
2097
+ "mobius-source": "./src/runtime.ts",
2098
+ types: "./dist/runtime.d.ts",
2099
+ default: "./dist/runtime.js"
2100
+ },
2101
+ "./process": {
2102
+ "mobius-source": "./src/util/process/executable.ts",
2103
+ types: "./dist/util/process/executable.d.ts",
2104
+ default: "./dist/util/process/executable.js"
2105
+ },
2106
+ "./filesystem": {
2107
+ "mobius-source": "./src/util/filesystem/private-path.ts",
2108
+ types: "./dist/util/filesystem/private-path.d.ts",
2109
+ default: "./dist/util/filesystem/private-path.js"
2110
+ }
2099
2111
  },
2100
2112
  files: [
2101
2113
  "dist"
@@ -5593,6 +5605,84 @@ var init_commander = __esm({
5593
5605
  }
5594
5606
  });
5595
5607
 
5608
+ // src/acp/harness/claude/parent-lifeline.ts
5609
+ import { spawn } from "node:child_process";
5610
+ import { Duplex } from "node:stream";
5611
+ function spawnClaudeWithParentLifeline(options) {
5612
+ options.signal.throwIfAborted();
5613
+ const child = spawn(process.execPath, ["-e", supervisor, "--", options.command, ...options.args], {
5614
+ cwd: options.cwd,
5615
+ env: options.env,
5616
+ stdio: ["pipe", "pipe", "pipe", "pipe"],
5617
+ windowsHide: true
5618
+ });
5619
+ const lifeline = child.stdio[3];
5620
+ if (child.stdin === null || child.stdout === null || child.stderr === null || !(lifeline instanceof Duplex)) {
5621
+ child.kill("SIGKILL");
5622
+ throw new Error("The Claude process supervisor has no parent lifeline");
5623
+ }
5624
+ let termination = "running";
5625
+ const stop = () => {
5626
+ termination = "requested";
5627
+ lifeline.end();
5628
+ return true;
5629
+ };
5630
+ options.signal.addEventListener("abort", stop, { once: true });
5631
+ if (options.signal.aborted) {
5632
+ stop();
5633
+ }
5634
+ child.once("close", () => options.signal.removeEventListener("abort", stop));
5635
+ child.stderr.pipe(process.stderr, { end: false });
5636
+ return {
5637
+ stdin: child.stdin,
5638
+ stdout: child.stdout,
5639
+ get killed() {
5640
+ return termination === "requested";
5641
+ },
5642
+ get exitCode() {
5643
+ return child.exitCode;
5644
+ },
5645
+ get signalCode() {
5646
+ return child.signalCode;
5647
+ },
5648
+ kill: stop,
5649
+ on: child.on.bind(child),
5650
+ once: child.once.bind(child),
5651
+ off: child.off.bind(child)
5652
+ };
5653
+ }
5654
+ var supervisor;
5655
+ var init_parent_lifeline = __esm({
5656
+ "src/acp/harness/claude/parent-lifeline.ts"() {
5657
+ "use strict";
5658
+ supervisor = `
5659
+ const { spawn, spawnSync } = require("node:child_process");
5660
+ const { Socket } = require("node:net");
5661
+ const [command, ...args] = process.argv.slice(1);
5662
+ const child = spawn(command, args, { stdio: ["pipe", "pipe", "pipe"], detached: process.platform !== "win32", windowsHide: true });
5663
+ const lifeline = new Socket({ fd: 3, readable: true, writable: false });
5664
+ let exited = false;
5665
+ function terminate() {
5666
+ if (exited || child.pid === undefined) return;
5667
+ if (process.platform === "win32") {
5668
+ spawnSync("taskkill", ["/pid", String(child.pid), "/T", "/F"], { timeout: 5000, windowsHide: true, stdio: "ignore" });
5669
+ } else {
5670
+ try { process.kill(-child.pid, "SIGKILL"); }
5671
+ catch (error) { if (error.code !== "ESRCH") throw error; }
5672
+ }
5673
+ }
5674
+ lifeline.on("end", terminate).on("error", terminate).resume();
5675
+ process.on("SIGTERM", terminate).on("SIGINT", terminate);
5676
+ process.stdin.pipe(child.stdin);
5677
+ child.stdin.on("error", () => {});
5678
+ child.stdout.pipe(process.stdout);
5679
+ child.stderr.pipe(process.stderr);
5680
+ child.once("error", (error) => { process.stderr.write(error.message); process.exitCode = 1; lifeline.destroy(); process.stdin.destroy(); });
5681
+ child.once("close", (code) => { exited = true; process.exitCode = code ?? 1; lifeline.destroy(); process.stdin.destroy(); });
5682
+ `;
5683
+ }
5684
+ });
5685
+
5596
5686
  // ../../node_modules/.pnpm/@anthropic-ai+claude-agent-sdk@0.3.257_@anthropic-ai+sdk@0.122.0_zod@4.6.5__@modelconte_b0b90ed00d211c5955785f7de7f8dbf4/node_modules/@anthropic-ai/claude-agent-sdk/sdk.mjs
5597
5687
  import { createRequire as $ne } from "node:module";
5598
5688
  import * as xr from "node:fs/promises";
@@ -66545,7 +66635,7 @@ async function runPromptWithCancellation(agent, params, signal) {
66545
66635
  function createClaudeAcpApp(options = {}) {
66546
66636
  let agent = null;
66547
66637
  const app = acpAgent({ name: "claude-code-acp" }).onConnect((connection) => {
66548
- agent = new ClaudeAcpAgent(new ClientConnection(connection.client, options.onSessionUpdate), options.logger, options.environment);
66638
+ agent = new ClaudeAcpAgent(new ClientConnection(connection.client, options.onSessionUpdate), options.logger, options.environment, options.spawnClaudeCodeProcess);
66549
66639
  options.onConnect?.(connection);
66550
66640
  }).onRequest(methods.agent.initialize, (ctx) => requiredAgent(agent).initialize(ctx.params)).onRequest(methods.agent.session.new, (ctx) => requiredAgent(agent).newSession(ctx.params)).onRequest(methods.agent.session.load, (ctx) => requiredAgent(agent).loadSession(ctx.params, ctx.signal)).onRequest(methods.agent.session.fork, (ctx) => requiredAgent(agent).unstable_forkSession(ctx.params, ctx.signal)).onRequest(methods.agent.session.list, (ctx) => requiredAgent(agent).listSessions(ctx.params, ctx.signal)).onRequest(methods.agent.session.delete, (ctx) => requiredAgent(agent).deleteSession(ctx.params)).onRequest(methods.agent.session.resume, (ctx) => requiredAgent(agent).resumeSession(ctx.params)).onRequest(methods.agent.session.close, (ctx) => requiredAgent(agent).closeSession(ctx.params)).onRequest(methods.agent.session.setMode, (ctx) => requiredAgent(agent).setSessionMode(ctx.params)).onRequest(methods.agent.session.setConfigOption, (ctx) => requiredAgent(agent).setSessionConfigOption(ctx.params)).onRequest(methods.agent.authenticate, (ctx) => requiredAgent(agent).authenticate(ctx.params)).onRequest(methods.agent.providers.list, (ctx) => requiredAgent(agent).unstable_listProviders(ctx.params)).onRequest(methods.agent.providers.set, (ctx) => requiredAgent(agent).unstable_setProvider(ctx.params)).onRequest(methods.agent.providers.disable, (ctx) => requiredAgent(agent).unstable_disableProvider(ctx.params)).onRequest(methods.agent.logout, (ctx) => requiredAgent(agent).logout(ctx.params)).onRequest(methods.agent.session.prompt, (ctx) => runPromptWithCancellation(requiredAgent(agent), ctx.params, ctx.signal)).onNotification(methods.agent.session.cancel, (ctx) => requiredAgent(agent).cancel(ctx.params)).onRequest(STEER_METHOD, { parse: parseSteerRequest }, (ctx) => requiredAgent(agent).steer(ctx.params)).onRequest(RENAME_METHOD, { parse: parseRenameRequest }, (ctx) => requiredAgent(agent).renameSession(ctx.params)).onRequest(GOAL_CONTROL_METHOD, { parse: parseGoalRequest }, (ctx) => requiredAgent(agent).goal(ctx.params));
66551
66641
  return { agent: () => agent, app };
@@ -66741,6 +66831,7 @@ var init_acp_agent = __esm({
66741
66831
  };
66742
66832
  mcpAuthentications = /* @__PURE__ */ new WeakMap();
66743
66833
  ClaudeAcpAgent = class {
66834
+ spawnClaudeCodeProcess;
66744
66835
  sessions;
66745
66836
  client;
66746
66837
  clientCapabilities;
@@ -66757,7 +66848,8 @@ var init_acp_agent = __esm({
66757
66848
  * return "cancelled". See {@link DEFAULT_FORCE_CANCEL_GRACE_MS}. Mutable so
66758
66849
  * tests can shrink it. */
66759
66850
  forceCancelGraceMs = DEFAULT_FORCE_CANCEL_GRACE_MS;
66760
- constructor(client2, logger, environment = process.env) {
66851
+ constructor(client2, logger, environment = process.env, spawnClaudeCodeProcess) {
66852
+ this.spawnClaudeCodeProcess = spawnClaudeCodeProcess;
66761
66853
  this.sessions = {};
66762
66854
  this.client = client2;
66763
66855
  this.logger = logger ?? console;
@@ -69334,6 +69426,7 @@ ${message.api_refusal_explanation}` : "";
69334
69426
  supportedDialogKinds: [REFUSAL_FALLBACK_DIALOG_KIND]
69335
69427
  } : {},
69336
69428
  pathToClaudeCodeExecutable: this.environment.CLAUDE_CODE_EXECUTABLE ?? await claudeCliPath(),
69429
+ ...this.spawnClaudeCodeProcess === void 0 ? {} : { spawnClaudeCodeProcess: this.spawnClaudeCodeProcess },
69337
69430
  extraArgs: {
69338
69431
  ...userProvidedOptions?.extraArgs,
69339
69432
  "replay-user-messages": ""
@@ -69609,6 +69702,7 @@ var ClaudeAcpEndpoint;
69609
69702
  var init_endpoint = __esm({
69610
69703
  "src/acp/harness/claude/endpoint.ts"() {
69611
69704
  "use strict";
69705
+ init_parent_lifeline();
69612
69706
  init_lib();
69613
69707
  ClaudeAcpEndpoint = class {
69614
69708
  #agent;
@@ -69622,6 +69716,7 @@ var init_endpoint = __esm({
69622
69716
  this.terminated = termination.promise;
69623
69717
  this.#resolveTermination = termination.resolve;
69624
69718
  const claude = createClaudeAcpApp({
69719
+ spawnClaudeCodeProcess: spawnClaudeWithParentLifeline,
69625
69720
  environment: Object.freeze({
69626
69721
  ...process.env,
69627
69722
  ...options.environment,
@@ -70256,7 +70351,7 @@ var init_platform = __esm({
70256
70351
  });
70257
70352
 
70258
70353
  // src/util/process/executable.ts
70259
- import { spawn as spawn2 } from "node:child_process";
70354
+ import { spawn as spawn3 } from "node:child_process";
70260
70355
  import { stat as stat4 } from "node:fs/promises";
70261
70356
  import { join as join12, resolve as resolve8 } from "node:path";
70262
70357
  async function resolveExecutablePath(requestedPath2, platform2 = process.platform) {
@@ -70422,7 +70517,7 @@ async function runBoundedProcess(options) {
70422
70517
  options.signal.throwIfAborted();
70423
70518
  const outputLimitBytes = options.outputLimitBytes ?? DEFAULT_OUTPUT_LIMIT_BYTES;
70424
70519
  const launch = executableLaunch2(options.command, options.arguments);
70425
- const child = spawn2(launch.command, [...launch.arguments], {
70520
+ const child = spawn3(launch.command, [...launch.arguments], {
70426
70521
  cwd: options.cwd,
70427
70522
  ...hostPlatform.spawnOptions,
70428
70523
  env: { ...options.environment },
@@ -71053,7 +71148,7 @@ var init_app_server_protocol = __esm({
71053
71148
  });
71054
71149
 
71055
71150
  // src/acp/harness/codex/app-server-client.ts
71056
- import { spawn as spawn3 } from "node:child_process";
71151
+ import { spawn as spawn4 } from "node:child_process";
71057
71152
  var INITIALIZE_TIMEOUT_MILLISECONDS, MESSAGE_OUTPUT_LIMIT_BYTES, CodexAppServerError, CodexAppServerClient;
71058
71153
  var init_app_server_client = __esm({
71059
71154
  "src/acp/harness/codex/app-server-client.ts"() {
@@ -71085,7 +71180,7 @@ var init_app_server_client = __esm({
71085
71180
  constructor(options) {
71086
71181
  this.#handlers = options.handlers;
71087
71182
  const launch = executableLaunch2(options.command, ["app-server"]);
71088
- this.#child = spawn3(launch.command, [...launch.arguments], {
71183
+ this.#child = spawn4(launch.command, [...launch.arguments], {
71089
71184
  cwd: options.cwd,
71090
71185
  ...platformSpawnOptions,
71091
71186
  env: { ...process.env, ...options.environment },
@@ -71468,12 +71563,12 @@ function presentToolItem(item) {
71468
71563
  };
71469
71564
  }
71470
71565
  if (item.type === "collabAgentToolCall") {
71471
- const spawn10 = item.tool === "spawnAgent";
71566
+ const spawn11 = item.tool === "spawnAgent";
71472
71567
  return {
71473
71568
  content: [],
71474
71569
  kind: "other",
71475
71570
  locations: [],
71476
- rawInput: spawn10 ? {
71571
+ rawInput: spawn11 ? {
71477
71572
  model: item.model,
71478
71573
  prompt: item.prompt,
71479
71574
  reasoningEffort: item.reasoningEffort,
@@ -71481,10 +71576,10 @@ function presentToolItem(item) {
71481
71576
  } : { receiverThreadIds: item.receiverThreadIds, senderThreadId: item.senderThreadId },
71482
71577
  rawOutput: {
71483
71578
  agentsStates: item.agentsStates,
71484
- ...spawn10 ? { receiverThreadIds: item.receiverThreadIds } : {}
71579
+ ...spawn11 ? { receiverThreadIds: item.receiverThreadIds } : {}
71485
71580
  },
71486
71581
  status: collaborationStatus(item.status),
71487
- title: spawn10 ? "Dispatch subagent" : "Wait for subagent"
71582
+ title: spawn11 ? "Dispatch subagent" : "Wait for subagent"
71488
71583
  };
71489
71584
  }
71490
71585
  if (item.type === "subAgentActivity" && item.kind === "started") {
@@ -73624,6 +73719,9 @@ function decodeSessionPromptCommand(encoded) {
73624
73719
  directoryId: readDirectoryIdentifier(value, "directoryId"),
73625
73720
  disposition,
73626
73721
  images,
73722
+ ...value["historyPolicy"] === void 0 ? {} : {
73723
+ historyPolicy: readHistoryPolicy(value)
73724
+ },
73627
73725
  kind: SESSION_PROMPT_KIND,
73628
73726
  prompt,
73629
73727
  resources,
@@ -73632,6 +73730,13 @@ function decodeSessionPromptCommand(encoded) {
73632
73730
  targetCommandId
73633
73731
  };
73634
73732
  }
73733
+ function readHistoryPolicy(value) {
73734
+ const field = value["historyPolicy"];
73735
+ if (field === SessionHistoryPolicy.Eager || field === SessionHistoryPolicy.ExecutionOnly) {
73736
+ return field;
73737
+ }
73738
+ throw new ProtocolMessageError("Invalid value field: historyPolicy");
73739
+ }
73635
73740
  function decodeSessionCancelCommand(encoded) {
73636
73741
  const value = parseJson(encoded);
73637
73742
  assertKind(value, SESSION_CANCEL_KIND);
@@ -73663,7 +73768,7 @@ function encodeSessionCancelCommand(message) {
73663
73768
  function encodeSessionPromptDispositionCommand(message) {
73664
73769
  return JSON.stringify(decodeSessionPromptDispositionCommand(JSON.stringify(message)));
73665
73770
  }
73666
- var SESSION_PROMPT_KIND, SESSION_PROMPT_DISPOSITION_KIND, SESSION_CANCEL_KIND, SessionPromptDisposition, MAX_PROMPT_LENGTH, MAX_PROMPT_ATTACHMENT_LENGTH, promptImageSchema, promptResourceSchema, decodePromptImagesValue, decodePromptResourcesValue;
73771
+ var SESSION_PROMPT_KIND, SESSION_PROMPT_DISPOSITION_KIND, SESSION_CANCEL_KIND, SessionPromptDisposition, SessionHistoryPolicy, MAX_PROMPT_LENGTH, MAX_PROMPT_ATTACHMENT_LENGTH, promptImageSchema, promptResourceSchema, decodePromptImagesValue, decodePromptResourcesValue;
73667
73772
  var init_commands = __esm({
73668
73773
  "../mobius-sdk/src/protocol/session/prompt/commands.ts"() {
73669
73774
  "use strict";
@@ -73679,6 +73784,10 @@ var init_commands = __esm({
73679
73784
  Reject: "reject",
73680
73785
  Steer: "steer"
73681
73786
  });
73787
+ SessionHistoryPolicy = Object.freeze({
73788
+ Eager: "eager",
73789
+ ExecutionOnly: "execution-only"
73790
+ });
73682
73791
  MAX_PROMPT_LENGTH = 1e5;
73683
73792
  MAX_PROMPT_ATTACHMENT_LENGTH = 6e6;
73684
73793
  promptImageSchema = external_exports.object({
@@ -75236,6 +75345,10 @@ var init_settings3 = __esm({
75236
75345
  approvalPolicy: mode.approvalPolicy,
75237
75346
  approvalsReviewer: mode.approvalsReviewer,
75238
75347
  sandboxPolicy: mode.sandboxPolicy,
75348
+ // Codex only streams its provider-authored reasoning summary when the turn opts in.
75349
+ // Keep the summary channel enabled so Thinking has visible content even when no raw
75350
+ // reasoning text is available.
75351
+ summary: "auto",
75239
75352
  // The collaboration mode rides on the turn: Codex applies it to the
75240
75353
  // thread, where it persists until changed. "Build" is Codex's `default`
75241
75354
  // mode, so it is only sent once a choice exists to apply.
@@ -75862,7 +75975,7 @@ var init_command2 = __esm({
75862
75975
  });
75863
75976
 
75864
75977
  // src/acp/harness/pi/upstream/dist/pi-rpc/process.js
75865
- import { spawn as spawn4 } from "node:child_process";
75978
+ import { spawn as spawn5 } from "node:child_process";
75866
75979
  import * as readline from "node:readline";
75867
75980
  function stripAnsi(s) {
75868
75981
  return s.replace(ANSI_ESCAPE_REGEX, "");
@@ -75966,7 +76079,7 @@ var init_process = __esm({
75966
76079
  args.push("--fork", params.origin.sessionPath);
75967
76080
  break;
75968
76081
  }
75969
- const child = spawn4(cmd, args, {
76082
+ const child = spawn5(cmd, args, {
75970
76083
  cwd: params.cwd,
75971
76084
  stdio: "pipe",
75972
76085
  env: params.environment,
@@ -79406,6 +79519,77 @@ ${JSON.stringify(stats, null, 2)}`;
79406
79519
  }, 0);
79407
79520
  return { sessionId: session.sessionId, configOptions, modes };
79408
79521
  }
79522
+ async resumeSession(params) {
79523
+ if (!isAbsolute11(params.cwd)) {
79524
+ throw RequestError7.invalidParams(`cwd must be an absolute path: ${params.cwd}`);
79525
+ }
79526
+ this.sessions.close(params.sessionId);
79527
+ this.lastSessionCwd = params.cwd;
79528
+ const stored = this.findStoredSession(params.sessionId);
79529
+ if (!stored) {
79530
+ throw RequestError7.invalidParams(`Unknown sessionId: ${params.sessionId}`);
79531
+ }
79532
+ const session = await this.restoreSession(params.sessionId, {
79533
+ cwd: params.cwd,
79534
+ mcpServers: params.mcpServers
79535
+ });
79536
+ let configuration;
79537
+ try {
79538
+ configuration = await getSessionConfiguration(session.proc);
79539
+ } catch (err) {
79540
+ this.sessions.close(session.sessionId);
79541
+ throw err;
79542
+ }
79543
+ const { configOptions, models, modes } = configuration;
79544
+ const enableSkillCommands = getEnableSkillCommands(params.cwd, this.environment);
79545
+ const fileCommands = loadSlashCommands(params.cwd, this.environment);
79546
+ this.sessions.closeAllExcept?.(session.sessionId);
79547
+ this.store.upsert({
79548
+ sessionId: params.sessionId,
79549
+ cwd: params.cwd,
79550
+ sessionFile: stored.sessionFile
79551
+ });
79552
+ const response = {
79553
+ configOptions,
79554
+ models,
79555
+ modes,
79556
+ _meta: {
79557
+ piAcp: {
79558
+ startupInfo: null
79559
+ }
79560
+ }
79561
+ };
79562
+ setTimeout(() => {
79563
+ void (async () => {
79564
+ await session.publishContextUsage();
79565
+ try {
79566
+ const pi2 = await session.proc.getCommands();
79567
+ const { commands } = toAvailableCommandsFromPiGetCommands(pi2, {
79568
+ enableSkillCommands,
79569
+ includeExtensionCommands: false
79570
+ });
79571
+ await this.conn.sessionUpdate({
79572
+ sessionId: session.sessionId,
79573
+ update: {
79574
+ sessionUpdate: "available_commands_update",
79575
+ availableCommands: mergeCommands(commands, builtinAvailableCommands())
79576
+ }
79577
+ });
79578
+ return;
79579
+ } catch {
79580
+ }
79581
+ await this.conn.sessionUpdate({
79582
+ sessionId: session.sessionId,
79583
+ update: {
79584
+ sessionUpdate: "available_commands_update",
79585
+ availableCommands: mergeCommands(toAvailableCommands(fileCommands), builtinAvailableCommands())
79586
+ }
79587
+ });
79588
+ })().catch(() => {
79589
+ });
79590
+ }, 0);
79591
+ return response;
79592
+ }
79409
79593
  async loadSession(params) {
79410
79594
  if (!isAbsolute11(params.cwd)) {
79411
79595
  throw RequestError7.invalidParams(`cwd must be an absolute path: ${params.cwd}`);
@@ -79685,6 +79869,9 @@ var init_endpoint2 = __esm({
79685
79869
  ).onRequest(
79686
79870
  methods5.agent.session.load,
79687
79871
  async (context) => await piAgentOrThrow(piAgent).loadSession(context.params)
79872
+ ).onRequest(
79873
+ methods5.agent.session.resume,
79874
+ async (context) => await piAgentOrThrow(piAgent).resumeSession(context.params)
79688
79875
  ).onRequest(
79689
79876
  methods5.agent.session.list,
79690
79877
  async (context) => await piAgentOrThrow(piAgent).listSessions(context.params)
@@ -80211,7 +80398,7 @@ var init_create_client = __esm({
80211
80398
  });
80212
80399
 
80213
80400
  // src/agent/discovery/acp-readiness-probe.ts
80214
- import { spawn as spawn5 } from "node:child_process";
80401
+ import { spawn as spawn6 } from "node:child_process";
80215
80402
  import {
80216
80403
  methods as methods8,
80217
80404
  ndJsonStream as ndJsonStream2,
@@ -80368,7 +80555,7 @@ async function probeAcpReadiness(specification, agent, environment, defaultWorks
80368
80555
  }
80369
80556
  }
80370
80557
  const launch = executableLaunch2(agent.adapterPath, agent.arguments);
80371
- const child = spawn5(launch.command, [...launch.arguments], {
80558
+ const child = spawn6(launch.command, [...launch.arguments], {
80372
80559
  cwd: defaultWorkspace,
80373
80560
  ...platformSpawnOptions,
80374
80561
  env: { ...environment, ...agent.environment },
@@ -83039,7 +83226,7 @@ var init_worker_lifecycle_log = __esm({
83039
83226
  });
83040
83227
 
83041
83228
  // src/daemon/lifecycle/worker-process.ts
83042
- import { spawn as spawn6 } from "node:child_process";
83229
+ import { spawn as spawn7 } from "node:child_process";
83043
83230
  import { isAbsolute as isAbsolute13, resolve as resolve16 } from "node:path";
83044
83231
  function currentWorkerLaunch(version2) {
83045
83232
  const entry = process.argv[1];
@@ -83099,7 +83286,7 @@ var init_worker_process = __esm({
83099
83286
  constructor(launch, signal, environment) {
83100
83287
  signal.throwIfAborted();
83101
83288
  this.launch = launch;
83102
- this.#child = spawn6(launch.executable, [launch.entry, "__worker"], {
83289
+ this.#child = spawn7(launch.executable, [launch.entry, "__worker"], {
83103
83290
  env: environment,
83104
83291
  windowsHide: true,
83105
83292
  stdio: ["ignore", "pipe", "pipe", "ipc"]
@@ -83432,9 +83619,9 @@ var init_manager2 = __esm({
83432
83619
  });
83433
83620
 
83434
83621
  // src/daemon/lifecycle/manager-client.ts
83435
- import { spawn as spawn7 } from "node:child_process";
83622
+ import { spawn as spawn8 } from "node:child_process";
83436
83623
  async function spawnManager() {
83437
- const child = spawn7(process.execPath, [process.argv[1] ?? "", "__manager"], {
83624
+ const child = spawn8(process.execPath, [process.argv[1] ?? "", "__manager"], {
83438
83625
  detached: true,
83439
83626
  windowsHide: true,
83440
83627
  env: process.env,
@@ -83840,7 +84027,7 @@ var init_history_images = __esm({
83840
84027
  });
83841
84028
 
83842
84029
  // src/acp/native-history/codex/codex-history.ts
83843
- import { spawn as spawn8 } from "node:child_process";
84030
+ import { spawn as spawn9 } from "node:child_process";
83844
84031
  function bounded(value, maximum) {
83845
84032
  return value.slice(0, maximum);
83846
84033
  }
@@ -84216,7 +84403,7 @@ async function readCodexHistoryWithOptions(agent, cwd, nativeSessionId, signal,
84216
84403
  }
84217
84404
  signal.throwIfAborted();
84218
84405
  const launch = executableLaunch2(agent.agentIdentity.realPath, ["app-server"]);
84219
- const child = spawn8(launch.command, [...launch.arguments], {
84406
+ const child = spawn9(launch.command, [...launch.arguments], {
84220
84407
  cwd,
84221
84408
  env: { ...process.env, ...agent.environment },
84222
84409
  ...platformSpawnOptions,
@@ -84561,6 +84748,16 @@ function toolStatus2(value) {
84561
84748
  }
84562
84749
  }
84563
84750
  function activityEvent(activity2) {
84751
+ if (activity2.activityType === "reasoning") {
84752
+ return {
84753
+ payload: {
84754
+ content: { text: activity2.output, type: "text" },
84755
+ messageId: activity2.activityId,
84756
+ sessionUpdate: "agent_thought_chunk"
84757
+ },
84758
+ type: "acp"
84759
+ };
84760
+ }
84564
84761
  return {
84565
84762
  payload: {
84566
84763
  content: activity2.content,
@@ -90219,6 +90416,25 @@ var init_acp_session = __esm({
90219
90416
  }
90220
90417
  });
90221
90418
 
90419
+ // src/schema/acp-session-store/execution-receipt.ts
90420
+ var executionReceipt;
90421
+ var init_execution_receipt = __esm({
90422
+ "src/schema/acp-session-store/execution-receipt.ts"() {
90423
+ "use strict";
90424
+ init_sqlite_core();
90425
+ executionReceipt = sqliteTable("execution_receipt", {
90426
+ commandId: text("command_id").primaryKey(),
90427
+ sessionId: text("session_id").notNull(),
90428
+ commandHash: text("command_hash").notNull(),
90429
+ attemptId: text("attempt_id").notNull(),
90430
+ state: text("state").notNull(),
90431
+ started: integer2("started", { mode: "boolean" }).notNull(),
90432
+ outcome: text("outcome"),
90433
+ updatedAt: text("updated_at").notNull()
90434
+ });
90435
+ }
90436
+ });
90437
+
90222
90438
  // src/schema/acp-session-store/session-live-event-position-allocation.ts
90223
90439
  var sessionLiveEventPositionAllocation;
90224
90440
  var init_session_live_event_position_allocation = __esm({
@@ -90237,6 +90453,7 @@ var init_acp_session_store = __esm({
90237
90453
  "src/schema/acp-session-store/index.ts"() {
90238
90454
  "use strict";
90239
90455
  init_acp_session();
90456
+ init_execution_receipt();
90240
90457
  init_session_live_event_position_allocation();
90241
90458
  }
90242
90459
  });
@@ -90285,6 +90502,71 @@ var init_acp_session_table = __esm({
90285
90502
  }
90286
90503
  });
90287
90504
 
90505
+ // src/storage/session/execution-receipt-table.ts
90506
+ var receiptFields, receiptSchema, ExecutionReceiptTable;
90507
+ var init_execution_receipt_table = __esm({
90508
+ "src/storage/session/execution-receipt-table.ts"() {
90509
+ "use strict";
90510
+ init_drizzle_orm();
90511
+ init_zod();
90512
+ init_acp_session_store();
90513
+ receiptFields = external_exports.object({
90514
+ commandId: external_exports.string(),
90515
+ sessionId: external_exports.string(),
90516
+ commandHash: external_exports.string(),
90517
+ attemptId: external_exports.string(),
90518
+ updatedAt: external_exports.string()
90519
+ });
90520
+ receiptSchema = external_exports.discriminatedUnion("state", [
90521
+ receiptFields.extend({ state: external_exports.literal("dispatching"), started: external_exports.literal(false), outcome: external_exports.null() }),
90522
+ receiptFields.extend({ state: external_exports.literal("running"), started: external_exports.literal(true), outcome: external_exports.string().nullable() }),
90523
+ receiptFields.extend({
90524
+ state: external_exports.enum(["succeeded", "failed", "cancelled"]),
90525
+ started: external_exports.boolean(),
90526
+ outcome: external_exports.string().nullable()
90527
+ })
90528
+ ]).readonly();
90529
+ ExecutionReceiptTable = class {
90530
+ #database;
90531
+ constructor(database) {
90532
+ this.#database = database;
90533
+ }
90534
+ list = () => receiptSchema.array().parse(
90535
+ this.#database.orm.select().from(executionReceipt).orderBy(asc(executionReceipt.updatedAt), asc(executionReceipt.commandId)).all()
90536
+ );
90537
+ save = (receipt) => {
90538
+ this.#database.transaction(() => {
90539
+ this.#database.orm.insert(executionReceipt).values(receipt).onConflictDoUpdate({ target: executionReceipt.commandId, set: receipt }).run();
90540
+ if (receipt.state === "dispatching" || receipt.state === "running") {
90541
+ return;
90542
+ }
90543
+ const retained = this.#database.orm.select({ commandId: executionReceipt.commandId }).from(executionReceipt).where(
90544
+ and(
90545
+ eq2(executionReceipt.sessionId, receipt.sessionId),
90546
+ inArray(executionReceipt.state, ["succeeded", "failed", "cancelled"])
90547
+ )
90548
+ ).orderBy(desc(executionReceipt.updatedAt), desc(executionReceipt.commandId)).limit(1024).all();
90549
+ if (retained.length === 1024) {
90550
+ this.#database.orm.delete(executionReceipt).where(
90551
+ and(
90552
+ eq2(executionReceipt.sessionId, receipt.sessionId),
90553
+ inArray(executionReceipt.state, ["succeeded", "failed", "cancelled"]),
90554
+ notInArray(
90555
+ executionReceipt.commandId,
90556
+ retained.map((row) => row.commandId)
90557
+ )
90558
+ )
90559
+ ).run();
90560
+ }
90561
+ });
90562
+ };
90563
+ remove = (commandId) => {
90564
+ this.#database.orm.delete(executionReceipt).where(eq2(executionReceipt.commandId, commandId)).run();
90565
+ };
90566
+ };
90567
+ }
90568
+ });
90569
+
90288
90570
  // src/storage/session/live-event-position-table.ts
90289
90571
  var allocationRowSchema, LiveEventPositionTable;
90290
90572
  var init_live_event_position_table = __esm({
@@ -90538,6 +90820,10 @@ var init_acp_session_store_migrations = __esm({
90538
90820
  {
90539
90821
  "name": "0006_live_event_position_allocation.sql",
90540
90822
  "sql": "CREATE TABLE `session_live_event_position_allocation` (\n `allocated_position` integer DEFAULT 10000 NOT NULL,\n `session_id` text PRIMARY KEY NOT NULL\n);\n"
90823
+ },
90824
+ {
90825
+ "name": "0007_busy_excalibur.sql",
90826
+ "sql": "CREATE TABLE `execution_receipt` (\n `command_id` text PRIMARY KEY NOT NULL,\n `session_id` text NOT NULL,\n `command_hash` text NOT NULL,\n `attempt_id` text NOT NULL,\n `state` text NOT NULL,\n `started` integer NOT NULL,\n `outcome` text,\n `updated_at` text NOT NULL\n);\n"
90541
90827
  }
90542
90828
  ];
90543
90829
  }
@@ -91156,12 +91442,12 @@ var init_session_event_id_allocator = __esm({
91156
91442
 
91157
91443
  // src/session/history/session-event-store.ts
91158
91444
  import { randomUUID as randomUUID12 } from "node:crypto";
91159
- function liveEvent(sessionId, sessionGenerationId, eventId, position, event) {
91445
+ function liveEvent(sessionId, sessionGenerationId, eventId, position, event, recordedAt = (/* @__PURE__ */ new Date()).toISOString()) {
91160
91446
  return {
91161
91447
  eventId,
91162
91448
  ...event,
91163
91449
  position: position.toString(),
91164
- recordedAt: (/* @__PURE__ */ new Date()).toISOString(),
91450
+ recordedAt,
91165
91451
  sessionGenerationId,
91166
91452
  sessionId
91167
91453
  };
@@ -91322,7 +91608,7 @@ var init_session_event_store = __esm({
91322
91608
  }
91323
91609
  return resolved;
91324
91610
  };
91325
- append = (sessionId, event) => {
91611
+ append = (sessionId, event, recordedAt) => {
91326
91612
  const session = this.#session(sessionId);
91327
91613
  const allocatedPosition = this.#allocatedPositionBySession.get(sessionId) ?? 9999;
91328
91614
  if (allocatedPosition === Number.MAX_SAFE_INTEGER) {
@@ -91335,7 +91621,8 @@ var init_session_event_store = __esm({
91335
91621
  session.sessionGenerationId,
91336
91622
  this.#eventIds.allocate(sessionId, session.sessionGenerationId),
91337
91623
  position,
91338
- event
91624
+ event,
91625
+ recordedAt
91339
91626
  );
91340
91627
  session.apply(recorded, this.#resolver(session));
91341
91628
  return recorded;
@@ -91376,12 +91663,14 @@ var init_session_event_store = __esm({
91376
91663
  };
91377
91664
  };
91378
91665
  CachedSessionEventStore = class {
91666
+ #terminalOutcomes;
91379
91667
  #cacheTable;
91380
91668
  #eventIds;
91381
91669
  #liveEventPositions;
91382
91670
  #sessions = /* @__PURE__ */ new Map();
91383
91671
  #flushSchedule = { kind: "idle" };
91384
- constructor(cacheTable, liveEventPositions, eventIds = new InMemorySessionEventIdAllocator()) {
91672
+ constructor(cacheTable, liveEventPositions, eventIds = new InMemorySessionEventIdAllocator(), terminalOutcomes = () => []) {
91673
+ this.#terminalOutcomes = terminalOutcomes;
91385
91674
  this.#eventIds = eventIds;
91386
91675
  this.#liveEventPositions = liveEventPositions;
91387
91676
  this.#cacheTable = cacheTable;
@@ -91414,7 +91703,7 @@ var init_session_event_store = __esm({
91414
91703
  }
91415
91704
  return resolved;
91416
91705
  };
91417
- append = (sessionId, event) => {
91706
+ append = (sessionId, event, recordedAt) => {
91418
91707
  if (this.#flushSchedule.kind === "closed") {
91419
91708
  throw new Error("The V2 Session event store is closed");
91420
91709
  }
@@ -91425,7 +91714,8 @@ var init_session_event_store = __esm({
91425
91714
  session.sessionGenerationId,
91426
91715
  this.#eventIds.allocate(sessionId, session.sessionGenerationId),
91427
91716
  position,
91428
- event
91717
+ event,
91718
+ recordedAt
91429
91719
  );
91430
91720
  session.apply(recorded, this.#resolver(sessionId, session));
91431
91721
  this.#sessions.set(sessionId, session);
@@ -91514,6 +91804,9 @@ var init_session_event_store = __esm({
91514
91804
  this.#deletePersisted(sessionId, previous?.sessionGenerationId);
91515
91805
  const sessionGenerationId = randomUUID12();
91516
91806
  this.#sessions.set(sessionId, new SessionEvents(sessionGenerationId));
91807
+ for (const { event, recordedAt } of this.#terminalOutcomes(sessionId)) {
91808
+ this.append(sessionId, event, recordedAt);
91809
+ }
91517
91810
  };
91518
91811
  materializedEventCount = (sessionId) => this.#sessions.get(sessionId)?.materializedCount ?? 0;
91519
91812
  close = () => {
@@ -91634,7 +91927,7 @@ var init_prompt_content = __esm({
91634
91927
  });
91635
91928
 
91636
91929
  // src/acp/connection/agent-connection.ts
91637
- import { spawn as spawn9 } from "node:child_process";
91930
+ import { spawn as spawn10 } from "node:child_process";
91638
91931
  import { ndJsonStream as ndJsonStream3, RequestError as RequestError9 } from "@agentclientprotocol/sdk";
91639
91932
  function requestErrorMessage(error62) {
91640
91933
  const fallback = truncate2(error62.message, 500);
@@ -91753,7 +92046,7 @@ var init_agent_connection = __esm({
91753
92046
  return;
91754
92047
  }
91755
92048
  const launch = executableLaunch2(agent.adapterPath, agent.arguments);
91756
- const child = spawn9(launch.command, [...launch.arguments], {
92049
+ const child = spawn10(launch.command, [...launch.arguments], {
91757
92050
  cwd,
91758
92051
  ...platformSpawnOptions,
91759
92052
  env: { ...process.env, ...agent.environment },
@@ -93107,6 +93400,19 @@ var init_agent_turn = __esm({
93107
93400
 
93108
93401
  // src/session/live/session-restore.ts
93109
93402
  import { methods as methods10 } from "@agentclientprotocol/sdk";
93403
+ function hasMethodNotFoundCode(cause) {
93404
+ const visited = /* @__PURE__ */ new Set();
93405
+ let current = cause;
93406
+ while ((current instanceof Error || typeof current === "object" && current !== null) && !visited.has(current)) {
93407
+ visited.add(current);
93408
+ const code = Reflect.get(current, "code");
93409
+ if (code === -32601 || code === "METHOD_NOT_FOUND" || code === "method_not_found") {
93410
+ return true;
93411
+ }
93412
+ current = current instanceof Error ? current.cause : void 0;
93413
+ }
93414
+ return false;
93415
+ }
93110
93416
  async function restoreSession(session, signal, recovery, origin) {
93111
93417
  if (origin !== void 0) {
93112
93418
  session.setSessionTitle(origin.title);
@@ -93173,6 +93479,9 @@ async function restoreSession(session, signal, recovery, origin) {
93173
93479
  }
93174
93480
  session.setPrompted(true);
93175
93481
  session.setRestored(true);
93482
+ if (recovery.kind === "execution-only") {
93483
+ session.startExecutionOnlyCapture();
93484
+ }
93176
93485
  lifecycleResponse2 = forked;
93177
93486
  } else if (stored instanceof FoundStoredSession && stored.session.agentId === session.agentId && stored.session.cwd === session.cwd && arraysEqual(stored.session.additionalDirectories, session.additionalDirectories)) {
93178
93487
  session.selectNativeSession(stored.session.nativeSessionId);
@@ -93191,6 +93500,37 @@ async function restoreSession(session, signal, recovery, origin) {
93191
93500
  "session-load",
93192
93501
  async () => (await session.loadSession(signal, "ACP agent exited while loading a session")).response
93193
93502
  );
93503
+ } else if (recovery.kind === "execution-only") {
93504
+ try {
93505
+ lifecycleResponse2 = await session.metrics.measure(
93506
+ "session-resume",
93507
+ async () => await session.race(
93508
+ session.agentRequest(
93509
+ methods10.agent.session.resume,
93510
+ {
93511
+ additionalDirectories: [...session.additionalDirectories],
93512
+ cwd: session.cwd,
93513
+ mcpServers: [],
93514
+ sessionId: session.nativeSessionId()
93515
+ },
93516
+ { cancellationSignal: signal }
93517
+ ),
93518
+ "ACP agent exited while resuming a session",
93519
+ signal
93520
+ )
93521
+ );
93522
+ } catch (cause) {
93523
+ signal.throwIfAborted();
93524
+ if (cause instanceof AcpExecutionError && !hasMethodNotFoundCode(cause)) {
93525
+ throw cause;
93526
+ }
93527
+ throw new AcpExecutionError(
93528
+ "This Agent cannot continue a persisted session without replaying native history",
93529
+ { cause },
93530
+ "execution_only_unsupported"
93531
+ );
93532
+ }
93533
+ session.startExecutionOnlyCapture();
93194
93534
  } else if (session.capabilities.resumeSession) {
93195
93535
  lifecycleResponse2 = await session.metrics.measure(
93196
93536
  "session-resume",
@@ -93250,6 +93590,9 @@ async function restoreSession(session, signal, recovery, origin) {
93250
93590
  );
93251
93591
  session.selectNativeSession(created.sessionId);
93252
93592
  session.setNativeHistoryOwnership({ kind: "fresh-session" });
93593
+ if (recovery.kind === "execution-only") {
93594
+ session.startExecutionOnlyCapture();
93595
+ }
93253
93596
  lifecycleResponse2 = created;
93254
93597
  }
93255
93598
  session.restrictSessionCapabilities(lifecycleResponse2);
@@ -93565,6 +93908,16 @@ var init_agent_session = __esm({
93565
93908
  }
93566
93909
  await this.#completedHistory(signal, "ACP agent exited while loading history");
93567
93910
  };
93911
+ /** Starts live event capture without asking the native Agent to replay its persisted history. */
93912
+ startExecutionOnlyCapture = () => {
93913
+ if (this.#sessionLoad.kind !== "not-requested") {
93914
+ return;
93915
+ }
93916
+ this.#sessionLoad = {
93917
+ history: new HistoryReplayCapture(this.#store.events, this.#mobiusSessionId),
93918
+ kind: "execution-only"
93919
+ };
93920
+ };
93568
93921
  loadHistoryEvents = async (eventLimit, cursor, signal) => {
93569
93922
  if (!this.#capabilities.loadSession) {
93570
93923
  throw new AcpExecutionError(
@@ -93815,7 +94168,7 @@ var init_agent_session = __esm({
93815
94168
  response: {}
93816
94169
  };
93817
94170
  }
93818
- if (this.#capabilities.loadSession) {
94171
+ if (this.#capabilities.loadSession && this.#sessionLoad.kind !== "execution-only") {
93819
94172
  await this.#completedHistory(options.signal, "ACP agent exited while loading history before a prompt");
93820
94173
  }
93821
94174
  const prompt = this.buildPrompt(options);
@@ -94014,14 +94367,14 @@ var init_agent_session = __esm({
94014
94367
  onElicitationComplete = (notification) => this.#interactions.onElicitationComplete(notification);
94015
94368
  onUpdate = (notification) => this.#updates.receive(notification);
94016
94369
  recordControlEvent = async (event) => {
94017
- if (this.#sessionLoad.kind !== "loaded") {
94370
+ if (this.#sessionLoad.kind !== "loaded" && this.#sessionLoad.kind !== "execution-only") {
94018
94371
  return false;
94019
94372
  }
94020
94373
  await this.recordLifecycleEvent(event);
94021
94374
  return true;
94022
94375
  };
94023
94376
  recordLifecycleEvent = async (event) => {
94024
- if (event.type !== "lifecycle-metadata" || this.#sessionLoad.kind !== "loaded") {
94377
+ if (event.type !== "lifecycle-metadata" || this.#sessionLoad.kind !== "loaded" && this.#sessionLoad.kind !== "execution-only") {
94025
94378
  return;
94026
94379
  }
94027
94380
  const liveEvent2 = this.#sessionLoad.history.recordLifecycle(event);
@@ -94042,7 +94395,7 @@ var init_agent_session = __esm({
94042
94395
  const rawUpdate = decodeAcpSessionUpdate(JSON.stringify(externalized.event));
94043
94396
  if (this.#sessionLoad.kind === "capturing") {
94044
94397
  await this.#sessionLoad.history.record(update, rawUpdate);
94045
- } else if (this.#sessionLoad.kind === "loaded") {
94398
+ } else if (this.#sessionLoad.kind === "loaded" || this.#sessionLoad.kind === "execution-only") {
94046
94399
  const onSessionEvent = this.#getObserver().onSessionEvent;
94047
94400
  await this.#sessionLoad.history.record(update, rawUpdate, async (liveEvent2) => {
94048
94401
  await onSessionEvent?.(liveEvent2);
@@ -95029,13 +95382,14 @@ var init_session_manager = __esm({
95029
95382
  }
95030
95383
  async #replaceExecutionPreparation(existing, options) {
95031
95384
  const desiredConfigOptions = existing.prepared().configOptions;
95385
+ const recovery = options.recovery ?? { kind: "interactive-only" };
95032
95386
  return await this.#executionProcesses.prepare(options.sessionId, async () => {
95033
95387
  await this.#retireSessionProcess(options.sessionId, existing, async () => await existing.close());
95034
95388
  const runtime = await this.#startRetainedSessionProcess(
95035
95389
  options,
95036
95390
  async () => await AgentSession.start(
95037
95391
  options,
95038
- { kind: "interactive-only" },
95392
+ recovery,
95039
95393
  () => this.#observer,
95040
95394
  this.#store,
95041
95395
  unmeasuredOperationMetrics,
@@ -95213,6 +95567,7 @@ var init_session_manager = __esm({
95213
95567
  });
95214
95568
  });
95215
95569
  prepareExecutionSession = async (options) => this.#operations.run(options, async (options2) => {
95570
+ const recovery = options2.recovery ?? { kind: "interactive-only" };
95216
95571
  this.#assertOpen(options2.sessionId);
95217
95572
  const pending = this.#executionProcesses.pending(options2.sessionId);
95218
95573
  if (pending !== void 0) {
@@ -95221,7 +95576,7 @@ var init_session_manager = __esm({
95221
95576
  }
95222
95577
  const existing = this.#executionProcesses.get(options2.sessionId);
95223
95578
  if (existing === void 0) {
95224
- return (await this.#startPreparation(options2, { kind: "interactive-only" })).prepared();
95579
+ return (await this.#startPreparation(options2, recovery)).prepared();
95225
95580
  }
95226
95581
  if (!existing.belongsTo(options2.agent.id, options2.cwd, options2.additionalDirectories)) {
95227
95582
  throw new AcpExecutionError(
@@ -95231,6 +95586,9 @@ var init_session_manager = __esm({
95231
95586
  );
95232
95587
  }
95233
95588
  if (existing.usesEnvironment(options2.agent.environment)) {
95589
+ if (recovery.kind === "execution-only") {
95590
+ existing.startExecutionOnlyCapture();
95591
+ }
95234
95592
  this.#executionProcesses.touch(options2.sessionId, existing);
95235
95593
  return existing.prepared();
95236
95594
  }
@@ -95525,10 +95883,13 @@ var init_session_manager = __esm({
95525
95883
  "session_identity_mismatch"
95526
95884
  );
95527
95885
  }
95886
+ if (options2.recovery?.kind === "execution-only") {
95887
+ existing.startExecutionOnlyCapture();
95888
+ }
95528
95889
  this.#executionProcesses.touch(options2.sessionId, existing);
95529
95890
  return existing;
95530
95891
  }
95531
- await this.prepareSession(options2);
95892
+ await this.#prepareSession(options2, options2.recovery ?? { kind: "interactive-only" }, "reopen");
95532
95893
  const started = this.#executionProcesses.get(options2.sessionId);
95533
95894
  if (started === void 0) {
95534
95895
  throw new AcpExecutionError("ACP session did not start");
@@ -96086,6 +96447,7 @@ var PromptLifecycle;
96086
96447
  var init_prompt_lifecycle = __esm({
96087
96448
  "src/session/prompt/prompt-lifecycle.ts"() {
96088
96449
  "use strict";
96450
+ init_protocol();
96089
96451
  PromptLifecycle = class {
96090
96452
  #sink;
96091
96453
  #terminal = /* @__PURE__ */ new Map();
@@ -96167,6 +96529,13 @@ var init_prompt_lifecycle = __esm({
96167
96529
  }
96168
96530
  this.#queued.delete(commandId);
96169
96531
  };
96532
+ replayOutcome = async (sessionId, event) => {
96533
+ if (event.type !== "lifecycle-metadata" || !("commandId" in event.payload)) {
96534
+ return;
96535
+ }
96536
+ await this.#recordLifecycle(sessionId, event);
96537
+ this.publishTerminal(sessionId, event.payload.commandId);
96538
+ };
96170
96539
  queueChanged = async (sessionId) => {
96171
96540
  await this.#recordLifecycle(sessionId, {
96172
96541
  type: "lifecycle-metadata",
@@ -96200,7 +96569,7 @@ var init_prompt_lifecycle = __esm({
96200
96569
  type: "lifecycle-metadata",
96201
96570
  payload: { kind: "prompt.failed-before-start", commandId, code, message }
96202
96571
  });
96203
- if (!recorded) {
96572
+ if (!recorded || code === SESSION_CLOSED_ERROR_CODE) {
96204
96573
  this.#sink.publishOperationFailure(sessionId, commandId, code, message);
96205
96574
  }
96206
96575
  };
@@ -96225,21 +96594,154 @@ var MAX_TERMINAL_RECEIPTS, ExecutionReceipts;
96225
96594
  var init_execution_receipts = __esm({
96226
96595
  "src/session/turn/execution-receipts.ts"() {
96227
96596
  "use strict";
96597
+ init_protocol();
96598
+ init_zod();
96228
96599
  MAX_TERMINAL_RECEIPTS = 1024;
96229
96600
  ExecutionReceipts = class {
96230
96601
  #executions = /* @__PURE__ */ new Map();
96602
+ #recoveredCommands = /* @__PURE__ */ new Set();
96231
96603
  #terminalCountBySession = /* @__PURE__ */ new Map();
96604
+ #table;
96605
+ #closing = false;
96606
+ #activeCount = 0;
96607
+ #onCount;
96608
+ constructor(table, onCount = () => void 0) {
96609
+ this.#onCount = onCount;
96610
+ this.#table = table;
96611
+ for (const row of table?.list() ?? []) {
96612
+ this.#executions.set(row.commandId, row);
96613
+ this.#recoveredCommands.add(row.commandId);
96614
+ if (!isTerminal(row.state)) {
96615
+ this.#activeCount += 1;
96616
+ }
96617
+ if (isTerminal(row.state)) {
96618
+ this.#terminalCountBySession.set(
96619
+ row.sessionId,
96620
+ (this.#terminalCountBySession.get(row.sessionId) ?? 0) + 1
96621
+ );
96622
+ }
96623
+ }
96624
+ }
96625
+ #save = (commandId, receipt) => {
96626
+ if (!this.#closing) {
96627
+ this.#table?.save({ ...receipt, commandId, updatedAt: (/* @__PURE__ */ new Date()).toISOString() });
96628
+ }
96629
+ const previous = this.#executions.get(commandId);
96630
+ const wasActive = previous !== void 0 && !isTerminal(previous.state);
96631
+ if (isTerminal(receipt.state)) {
96632
+ this.#executions.delete(commandId);
96633
+ }
96634
+ this.#executions.set(commandId, receipt);
96635
+ this.#activeCount += Number(!isTerminal(receipt.state)) - Number(wasActive);
96636
+ this.#onCount(this.#activeCount);
96637
+ if (isTerminal(receipt.state) && (previous === void 0 || !isTerminal(previous.state))) {
96638
+ this.#terminalCountBySession.set(
96639
+ receipt.sessionId,
96640
+ (this.#terminalCountBySession.get(receipt.sessionId) ?? 0) + 1
96641
+ );
96642
+ this.pruneTerminalReceipts(receipt.sessionId);
96643
+ }
96644
+ };
96645
+ beginShutdown = () => {
96646
+ this.#closing = true;
96647
+ };
96648
+ outcome = (commandId) => {
96649
+ const receipt = this.#executions.get(commandId);
96650
+ return receipt?.outcome === null || receipt === void 0 ? void 0 : sessionEventPayloadSchema.parse(JSON.parse(receipt.outcome));
96651
+ };
96652
+ recordOutcome = (event) => {
96653
+ if (event.type !== "lifecycle-metadata") {
96654
+ return;
96655
+ }
96656
+ const payload = event.payload;
96657
+ if (payload.kind !== "prompt.completed" && payload.kind !== "prompt.failed" && payload.kind !== "prompt.failed-before-start") {
96658
+ return;
96659
+ }
96660
+ const receipt = this.#executions.get(payload.commandId);
96661
+ if (receipt === void 0) {
96662
+ return;
96663
+ }
96664
+ const sanitized = payload.kind === "prompt.completed" ? payload : { ...payload, message: "The local Agent could not complete the request" };
96665
+ this.#save(payload.commandId, {
96666
+ ...receipt,
96667
+ state: payload.kind === "prompt.completed" ? payload.stopReason === "cancelled" ? "cancelled" : "succeeded" : "failed",
96668
+ outcome: JSON.stringify({ type: "lifecycle-metadata", payload: sanitized, recordedAt: event.recordedAt })
96669
+ });
96670
+ };
96671
+ recover = () => {
96672
+ const recovered = [];
96673
+ for (const [commandId, receipt] of [...this.#executions]) {
96674
+ const event = receipt.outcome === null ? {
96675
+ type: "lifecycle-metadata",
96676
+ payload: receipt.started ? {
96677
+ kind: "prompt.failed",
96678
+ commandId,
96679
+ attemptId: receipt.attemptId,
96680
+ code: "runtime_restarted",
96681
+ message: "The local runtime restarted while this request was running"
96682
+ } : {
96683
+ kind: "prompt.failed-before-start",
96684
+ commandId,
96685
+ code: "runtime_restarted",
96686
+ message: "The local runtime restarted before this request started"
96687
+ }
96688
+ } : sessionEventPayloadSchema.parse(JSON.parse(receipt.outcome));
96689
+ const recordedAt = receipt.outcome === null ? (/* @__PURE__ */ new Date()).toISOString() : external_exports.object({ recordedAt: external_exports.string() }).parse(JSON.parse(receipt.outcome)).recordedAt;
96690
+ recovered.push({ sessionId: receipt.sessionId, event, recordedAt });
96691
+ if (!isTerminal(receipt.state)) {
96692
+ const state = event.type === "lifecycle-metadata" && event.payload.kind === "prompt.completed" ? event.payload.stopReason === "cancelled" ? "cancelled" : "succeeded" : "failed";
96693
+ this.#save(commandId, { ...receipt, state, outcome: JSON.stringify({ ...event, recordedAt }) });
96694
+ }
96695
+ }
96696
+ return recovered;
96697
+ };
96698
+ terminalOutcomes = (sessionId) => [...this.#executions.values()].flatMap((receipt) => {
96699
+ if (receipt.sessionId !== sessionId || receipt.outcome === null) {
96700
+ return [];
96701
+ }
96702
+ const decoded = JSON.parse(receipt.outcome);
96703
+ return [
96704
+ {
96705
+ event: sessionEventPayloadSchema.parse(decoded),
96706
+ recordedAt: external_exports.object({ recordedAt: external_exports.string() }).parse(decoded).recordedAt
96707
+ }
96708
+ ];
96709
+ });
96232
96710
  claimExecution = (commandId, sessionId, commandJson) => {
96233
96711
  const commandHash = createHash7("sha256").update(commandJson).digest("hex");
96234
- const existing = this.#executions.get(commandId);
96712
+ let existing = this.#executions.get(commandId);
96713
+ const previous = this.outcome(commandId);
96714
+ if (existing?.sessionId === sessionId && !existing.started && previous?.type === "lifecycle-metadata" && previous.payload.kind === "prompt.failed-before-start" && previous.payload.code === "runtime_restarted") {
96715
+ this.#executions.delete(commandId);
96716
+ this.#recoveredCommands.delete(commandId);
96717
+ this.#table?.remove(commandId);
96718
+ this.#terminalCountBySession.set(
96719
+ sessionId,
96720
+ Math.max(0, (this.#terminalCountBySession.get(sessionId) ?? 1) - 1)
96721
+ );
96722
+ existing = void 0;
96723
+ }
96235
96724
  if (existing !== void 0) {
96236
96725
  if (existing.sessionId !== sessionId || existing.commandHash !== commandHash) {
96237
96726
  return { kind: "conflict" };
96238
96727
  }
96239
- return { attemptId: existing.attemptId, commandId, kind: "duplicate", state: existing.state };
96728
+ return {
96729
+ attemptId: existing.attemptId,
96730
+ commandId,
96731
+ kind: "duplicate",
96732
+ state: existing.state,
96733
+ outcome: this.#recoveredCommands.has(commandId) ? this.outcome(commandId) : void 0
96734
+ };
96240
96735
  }
96241
96736
  const attemptId = randomUUID14();
96242
- this.#executions.set(commandId, { attemptId, commandHash, sessionId, state: "dispatching" });
96737
+ this.#save(commandId, {
96738
+ attemptId,
96739
+ commandHash,
96740
+ sessionId,
96741
+ state: "dispatching",
96742
+ started: false,
96743
+ outcome: null
96744
+ });
96243
96745
  return { attemptId, commandId, kind: "accepted", state: "dispatching" };
96244
96746
  };
96245
96747
  transitionExecution = (commandId, state) => {
@@ -96254,16 +96756,13 @@ var init_execution_receipts = __esm({
96254
96756
  if (!allowed) {
96255
96757
  throw new Error("The runtime execution transition is invalid");
96256
96758
  }
96257
- this.#executions.set(commandId, { ...current, state });
96258
- if (isTerminal(state)) {
96259
- this.#terminalCountBySession.set(
96260
- current.sessionId,
96261
- (this.#terminalCountBySession.get(current.sessionId) ?? 0) + 1
96262
- );
96263
- this.pruneTerminalReceipts(current.sessionId);
96759
+ if (state === "running") {
96760
+ this.#save(commandId, { ...current, state, started: true });
96761
+ } else if (isTerminal(state)) {
96762
+ this.#save(commandId, { ...current, state });
96264
96763
  }
96265
96764
  };
96266
- /** Receipts disappear when the runtime process exits. */
96765
+ /** Only commands without a terminal result can still be cancelled. */
96267
96766
  findUnsettledAttemptId = (commandId, sessionId) => {
96268
96767
  const receipt = this.#executions.get(commandId);
96269
96768
  return receipt?.sessionId === sessionId && !isTerminal(receipt.state) ? receipt.attemptId : null;
@@ -96274,7 +96773,9 @@ var init_execution_receipts = __esm({
96274
96773
  };
96275
96774
  close = () => {
96276
96775
  this.#executions.clear();
96776
+ this.#recoveredCommands.clear();
96277
96777
  this.#terminalCountBySession.clear();
96778
+ this.#activeCount = 0;
96278
96779
  };
96279
96780
  pruneTerminalReceipts = (sessionId) => {
96280
96781
  if ((this.#terminalCountBySession.get(sessionId) ?? 0) <= MAX_TERMINAL_RECEIPTS) {
@@ -96283,6 +96784,8 @@ var init_execution_receipts = __esm({
96283
96784
  for (const [commandId, receipt] of this.#executions) {
96284
96785
  if (receipt.sessionId === sessionId && isTerminal(receipt.state)) {
96285
96786
  this.#executions.delete(commandId);
96787
+ this.#recoveredCommands.delete(commandId);
96788
+ this.#table?.remove(commandId);
96286
96789
  const remaining = (this.#terminalCountBySession.get(sessionId) ?? 1) - 1;
96287
96790
  if (remaining > 0) {
96288
96791
  this.#terminalCountBySession.set(sessionId, remaining);
@@ -96833,10 +97336,14 @@ function buildSessionLayer(options) {
96833
97336
  const databases = channelSessionDatabasePaths(stateDirectory, channelId);
96834
97337
  const sessionDatabase = openAcpSessionDatabase(databases.sessions);
96835
97338
  let events;
97339
+ let operations;
96836
97340
  try {
97341
+ operations = new ExecutionReceipts(new ExecutionReceiptTable(sessionDatabase), options.onExecutionCountChange);
96837
97342
  events = new CachedSessionEventStore(
96838
97343
  new SessionEventCacheTable(openSessionEventCacheDatabase(databases.events)),
96839
- new SqliteSessionLiveEventPosition(new LiveEventPositionTable(sessionDatabase))
97344
+ new SqliteSessionLiveEventPosition(new LiveEventPositionTable(sessionDatabase)),
97345
+ void 0,
97346
+ (sessionId) => operations.terminalOutcomes(sessionId)
96840
97347
  );
96841
97348
  } catch (error62) {
96842
97349
  sessionDatabase.close();
@@ -96844,11 +97351,13 @@ function buildSessionLayer(options) {
96844
97351
  }
96845
97352
  const sessionStore = new SqliteSessionStore(new AcpSessionTable(sessionDatabase), events);
96846
97353
  const externalContent = new LocalExternalContentStore(stateDirectory);
96847
- const operations = new ExecutionReceipts();
96848
97354
  const activeSessions = new SessionTurns(operations, options.turnActivity);
96849
97355
  const directories = new WorkspaceDirectoryService(bindingId, defaultWorkspace);
96850
97356
  const manager = new SessionManager2({
96851
- observer: new SessionLayerObserver((event) => eventProjection.record(event), sink.publishInfo),
97357
+ observer: new SessionLayerObserver((event) => {
97358
+ operations.recordOutcome(event);
97359
+ eventProjection.record(event);
97360
+ }, sink.publishInfo),
96852
97361
  store: sessionStore,
96853
97362
  adapters: harnessAdapters,
96854
97363
  sessionIdentity: "native",
@@ -96869,7 +97378,15 @@ function buildSessionLayer(options) {
96869
97378
  });
96870
97379
  const eventProjection = new PromptLifecycle(
96871
97380
  sink,
96872
- (sessionId, event) => manager.recordLifecycleEvent(sessionId, event),
97381
+ async (sessionId, event) => {
97382
+ if (await manager.recordLifecycleEvent(sessionId, event)) {
97383
+ return true;
97384
+ }
97385
+ const recorded = events.append(sessionId, event);
97386
+ operations.recordOutcome(recorded);
97387
+ eventProjection.record(recorded);
97388
+ return true;
97389
+ },
96873
97390
  activeSessions.recordSessionEvent
96874
97391
  );
96875
97392
  const nativeSessions = new NativeSessionService(
@@ -96892,7 +97409,13 @@ function buildSessionLayer(options) {
96892
97409
  );
96893
97410
  })
96894
97411
  );
97412
+ const recoveredEvents = operations.recover().map(({ sessionId, event, recordedAt }) => events.append(sessionId, event, recordedAt));
96895
97413
  return {
97414
+ publishRecoveredOutcomes: () => {
97415
+ for (const event of recoveredEvents) {
97416
+ sink.publish(event);
97417
+ }
97418
+ },
96896
97419
  activeSessions,
96897
97420
  directories,
96898
97421
  eventProjection,
@@ -96910,6 +97433,7 @@ var init_session_layer = __esm({
96910
97433
  init_registry();
96911
97434
  init_content_externalizer();
96912
97435
  init_acp_session_table();
97436
+ init_execution_receipt_table();
96913
97437
  init_live_event_position_table();
96914
97438
  init_session_event_cache_table();
96915
97439
  init_local_databases();
@@ -98790,12 +99314,14 @@ async function executePrompt({
98790
99314
  const appliedSettings = command.sessionConfigurations === void 0 ? void 0 : agentForSessionConfiguration(agent, command.sessionConfigurations);
98791
99315
  const executionAgent = appliedSettings?.agent ?? agent;
98792
99316
  const sessionConfigurations = appliedSettings?.sessionConfigurations;
99317
+ const recovery = command.historyPolicy === SessionHistoryPolicy.ExecutionOnly ? { kind: "execution-only" } : { kind: "interactive-only" };
98793
99318
  const preparation = {
98794
99319
  additionalDirectories: resolved.additionalDirectories,
98795
99320
  agent: executionAgent,
98796
99321
  cwd: resolved.cwd,
98797
99322
  sessionId: command.sessionId,
98798
- signal
99323
+ signal,
99324
+ recovery
98799
99325
  };
98800
99326
  let prepared = await sessions.prepareExecutionSession(preparation);
98801
99327
  if (command.sessionConfigurations !== void 0) {
@@ -98864,7 +99390,8 @@ async function executePrompt({
98864
99390
  resources: attachments.resources,
98865
99391
  sessionId: command.sessionId,
98866
99392
  signal,
98867
- targetCommandId: command.targetCommandId
99393
+ targetCommandId: command.targetCommandId,
99394
+ recovery
98868
99395
  });
98869
99396
  stopReason = result.stopReason;
98870
99397
  }
@@ -99062,6 +99589,12 @@ var init_prompt2 = __esm({
99062
99589
  return;
99063
99590
  }
99064
99591
  if (receipt.kind === "duplicate") {
99592
+ const outcome = receipt.outcome;
99593
+ if (outcome !== void 0) {
99594
+ void context.eventProjection.replayOutcome(message.sessionId, outcome).catch((cause) => {
99595
+ console.error("Could not replay the persisted execution outcome", cause);
99596
+ });
99597
+ }
99065
99598
  return;
99066
99599
  }
99067
99600
  const turn = context.sessionTurns.start(message, receipt.attemptId);
@@ -100268,7 +100801,8 @@ async function runRuntime(config2, parentSignal, timer = systemTimer, options =
100268
100801
  resolveAgent: (agentId, resolveSignal) => resolveCatalogAgent(config2, agentId, resolveSignal),
100269
100802
  sink: publisher,
100270
100803
  stateDirectory: config2.localContext.stateDirectory,
100271
- timer
100804
+ timer,
100805
+ onExecutionCountChange: options.onExecutionCountChange ?? (() => void 0)
100272
100806
  });
100273
100807
  const {
100274
100808
  activeSessions,
@@ -100338,6 +100872,7 @@ async function runRuntime(config2, parentSignal, timer = systemTimer, options =
100338
100872
  reportUpgradeAvailability,
100339
100873
  diagnostics,
100340
100874
  onConnected: () => {
100875
+ layer.publishRecoveredOutcomes();
100341
100876
  if (catalogPublished) {
100342
100877
  options.onConnectionStatus?.("online");
100343
100878
  }
@@ -100360,6 +100895,7 @@ async function runRuntime(config2, parentSignal, timer = systemTimer, options =
100360
100895
  }
100361
100896
  } finally {
100362
100897
  shutdown.abort();
100898
+ operations.beginShutdown();
100363
100899
  await activeSessions.close();
100364
100900
  try {
100365
100901
  await catalogPublication;
@@ -100454,6 +100990,10 @@ var init_engine = __esm({
100454
100990
  MobiusRuntimeEngine = class {
100455
100991
  #config;
100456
100992
  #options;
100993
+ #activeTurnCount = 0;
100994
+ get activeTurnCount() {
100995
+ return this.#activeTurnCount;
100996
+ }
100457
100997
  #state = new IdleMobiusRuntimeState();
100458
100998
  constructor(config2, options = {}) {
100459
100999
  validateRuntimeConfiguration(config2);
@@ -100469,11 +101009,15 @@ var init_engine = __esm({
100469
101009
  try {
100470
101010
  await runRuntime(this.#config, signal, void 0, {
100471
101011
  ...this.#options.turnActivity === void 0 ? {} : { turnActivity: this.#options.turnActivity },
101012
+ onExecutionCountChange: (count) => {
101013
+ this.#activeTurnCount = count;
101014
+ },
100472
101015
  ...this.#options.onConnectionStatus === void 0 ? {} : { onConnectionStatus: this.#options.onConnectionStatus },
100473
101016
  ...this.#options.reportUpgradeAvailability === void 0 ? {} : { reportUpgradeAvailability: this.#options.reportUpgradeAvailability },
100474
101017
  ...this.#options.processLogsDirectory === void 0 ? {} : { processLogsDirectory: this.#options.processLogsDirectory }
100475
101018
  });
100476
101019
  } finally {
101020
+ this.#activeTurnCount = 0;
100477
101021
  this.#state = new FinishedMobiusRuntimeState();
100478
101022
  }
100479
101023
  };