@moxt-ai/mobius 0.0.5 → 0.0.7

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 (87) hide show
  1. package/dist/acp/activity.d.ts +7 -2
  2. package/dist/acp/activity.d.ts.map +1 -1
  3. package/dist/acp/activity.js +95 -7
  4. package/dist/acp/activity.js.map +1 -1
  5. package/dist/acp/native-session.d.ts +30 -0
  6. package/dist/acp/native-session.d.ts.map +1 -0
  7. package/dist/acp/native-session.js +25 -0
  8. package/dist/acp/native-session.js.map +1 -0
  9. package/dist/acp/session-history.d.ts +9 -0
  10. package/dist/acp/session-history.d.ts.map +1 -0
  11. package/dist/acp/session-history.js +69 -0
  12. package/dist/acp/session-history.js.map +1 -0
  13. package/dist/acp/session-manager.d.ts +16 -5
  14. package/dist/acp/session-manager.d.ts.map +1 -1
  15. package/dist/acp/session-manager.js +210 -25
  16. package/dist/acp/session-manager.js.map +1 -1
  17. package/dist/acp/session-store.d.ts +9 -0
  18. package/dist/acp/session-store.d.ts.map +1 -1
  19. package/dist/acp/session-store.js +43 -0
  20. package/dist/acp/session-store.js.map +1 -1
  21. package/dist/agent-catalog/discover-local-agents.d.ts +1 -1
  22. package/dist/agent-catalog/discover-local-agents.d.ts.map +1 -1
  23. package/dist/agent-catalog/discover-local-agents.js +19 -30
  24. package/dist/agent-catalog/discover-local-agents.js.map +1 -1
  25. package/dist/agent-installation/automatic-adapter-provisioner.d.ts +1 -1
  26. package/dist/agent-installation/automatic-adapter-provisioner.d.ts.map +1 -1
  27. package/dist/agent-installation/automatic-adapter-provisioner.js +1 -1
  28. package/dist/agent-installation/automatic-adapter-provisioner.js.map +1 -1
  29. package/dist/agent-installation/fixed-installation-executor.d.ts +1 -1
  30. package/dist/agent-installation/fixed-installation-executor.d.ts.map +1 -1
  31. package/dist/agent-installation/fixed-installation-executor.js +9 -18
  32. package/dist/agent-installation/fixed-installation-executor.js.map +1 -1
  33. package/dist/agent-installation/installation-grants.d.ts.map +1 -1
  34. package/dist/agent-installation/installation-grants.js +1 -2
  35. package/dist/agent-installation/installation-grants.js.map +1 -1
  36. package/dist/agent-installation/managed-adapter-installer.d.ts +0 -1
  37. package/dist/agent-installation/managed-adapter-installer.d.ts.map +1 -1
  38. package/dist/agent-installation/managed-adapter-installer.js +1 -3
  39. package/dist/agent-installation/managed-adapter-installer.js.map +1 -1
  40. package/dist/authorization/local-authorization-error.d.ts +5 -0
  41. package/dist/authorization/local-authorization-error.d.ts.map +1 -0
  42. package/dist/authorization/local-authorization-error.js +8 -0
  43. package/dist/authorization/local-authorization-error.js.map +1 -0
  44. package/dist/authorization/workspace-directory.d.ts +16 -5
  45. package/dist/authorization/workspace-directory.d.ts.map +1 -1
  46. package/dist/authorization/workspace-directory.js +109 -119
  47. package/dist/authorization/workspace-directory.js.map +1 -1
  48. package/dist/cli.js +2881 -739
  49. package/dist/cli.js.map +4 -4
  50. package/dist/config.d.ts +3 -3
  51. package/dist/config.d.ts.map +1 -1
  52. package/dist/config.js +8 -6
  53. package/dist/config.js.map +1 -1
  54. package/dist/index.d.ts +1 -1
  55. package/dist/index.d.ts.map +1 -1
  56. package/dist/index.js +2895 -788
  57. package/dist/index.js.map +4 -4
  58. package/dist/native-sessions/codex-history.d.ts +11 -0
  59. package/dist/native-sessions/codex-history.d.ts.map +1 -0
  60. package/dist/native-sessions/codex-history.js +223 -0
  61. package/dist/native-sessions/codex-history.js.map +1 -0
  62. package/dist/native-sessions/service.d.ts +14 -0
  63. package/dist/native-sessions/service.d.ts.map +1 -0
  64. package/dist/native-sessions/service.js +254 -0
  65. package/dist/native-sessions/service.js.map +1 -0
  66. package/dist/pairing/pair-local-machine.d.ts.map +1 -1
  67. package/dist/pairing/pair-local-machine.js +41 -31
  68. package/dist/pairing/pair-local-machine.js.map +1 -1
  69. package/dist/process/executable.d.ts +1 -1
  70. package/dist/process/executable.d.ts.map +1 -1
  71. package/dist/process/executable.js +3 -11
  72. package/dist/process/executable.js.map +1 -1
  73. package/dist/relay-connection/liveness.d.ts.map +1 -1
  74. package/dist/relay-connection/liveness.js +1 -2
  75. package/dist/relay-connection/liveness.js.map +1 -1
  76. package/dist/relay-connection/session-event-outbox.d.ts +19 -0
  77. package/dist/relay-connection/session-event-outbox.d.ts.map +1 -0
  78. package/dist/relay-connection/session-event-outbox.js +182 -0
  79. package/dist/relay-connection/session-event-outbox.js.map +1 -0
  80. package/dist/run-daemon.d.ts.map +1 -1
  81. package/dist/run-daemon.js +340 -244
  82. package/dist/run-daemon.js.map +1 -1
  83. package/package.json +3 -2
  84. package/dist/authorization/authorize-binding.d.ts +0 -6
  85. package/dist/authorization/authorize-binding.d.ts.map +0 -1
  86. package/dist/authorization/authorize-binding.js +0 -30
  87. package/dist/authorization/authorize-binding.js.map +0 -1
@@ -1,10 +1,12 @@
1
1
  import { spawn } from "node:child_process";
2
2
  import { methods, ndJsonStream, PROTOCOL_VERSION, } from "@agentclientprotocol/sdk";
3
- import { AGENT_CONTENT_KIND, MOBIUS_PROTOCOL_VERSION, SESSION_COMMANDS_UPDATED_KIND, SESSION_CONFIG_UPDATED_KIND, SESSION_ELICITATION_REQUESTED_KIND, SESSION_ELICITATION_RESOLVED_KIND, SESSION_INFO_UPDATED_KIND, SESSION_PERMISSION_REQUESTED_KIND, SESSION_PERMISSION_RESOLVED_KIND, SESSION_USAGE_UPDATED_KIND, } from "@moxt-ai/mobius-protocol";
3
+ import { AGENT_CONTENT_KIND, decodeAgentPromptResponse, SESSION_COMMANDS_UPDATED_KIND, SESSION_CONFIG_UPDATED_KIND, SESSION_ELICITATION_REQUESTED_KIND, SESSION_ELICITATION_RESOLVED_KIND, SESSION_INFO_UPDATED_KIND, SESSION_PERMISSION_REQUESTED_KIND, SESSION_PERMISSION_RESOLVED_KIND, SESSION_USAGE_UPDATED_KIND, } from "@moxt-ai/mobius-protocol";
4
4
  import { revalidateExecutable, stopProcessTree, } from "../process/executable.js";
5
5
  import { AcpActivityTracker, isProgressMessage, normalizeContentBlock, } from "./activity.js";
6
6
  import { createAcpClient } from "./create-client.js";
7
- import { AcpStoredSession, FoundAcpStoredSession, MemoryAcpSessionStore, } from "./session-store.js";
7
+ import { nativeSessionIdSchema, nativeSessionPageSchema, } from "./native-session.js";
8
+ import { AcpHistoryReplay } from "./session-history.js";
9
+ import { AcpStoredSession, DeletedAcpStoredSession, FoundAcpStoredSession, MemoryAcpSessionStore, } from "./session-store.js";
8
10
  const PROCESS_STOP_TIMEOUT_MILLISECONDS = 1_000;
9
11
  const SESSION_CONTROL_COMMAND_ID = "session-control";
10
12
  export class NullAcpSessionObserver {
@@ -274,6 +276,7 @@ function normalizeCapabilities(capabilities) {
274
276
  listSessions: session?.list != null,
275
277
  loadSession: capabilities.loadSession === true,
276
278
  resumeSession: session?.resume != null,
279
+ unstableForkSession: session?.fork != null,
277
280
  };
278
281
  }
279
282
  function elicitationFieldType(value) {
@@ -582,14 +585,17 @@ class AcpProcessSession {
582
585
  listSessions: false,
583
586
  loadSession: false,
584
587
  resumeSession: false,
588
+ unstableForkSession: false,
585
589
  };
586
590
  #commands = [];
587
591
  #configOptions = [];
588
592
  #nativeSessionId = "";
589
593
  #prompted = false;
590
- #replaying = false;
594
+ #replay = {
595
+ kind: "idle",
596
+ };
591
597
  #restored = false;
592
- #sessionTitle = "";
598
+ #sessionTitle = null;
593
599
  #sessionUpdatedAt = "";
594
600
  #turn = new IdleAcpTurn();
595
601
  #updateTail = Promise.resolve();
@@ -637,11 +643,12 @@ class AcpProcessSession {
637
643
  }
638
644
  const runtime = new AcpProcessSession(options.agent, options.cwd, options.additionalDirectories, options.sessionId, getObserver, store);
639
645
  try {
640
- await runtime.initialize(options.signal);
646
+ await runtime.initialize(options.signal, options.origin);
641
647
  return runtime;
642
648
  }
643
649
  catch (error) {
644
650
  await runtime.closeProcess();
651
+ options.signal.throwIfAborted();
645
652
  if (error instanceof AcpExecutionError) {
646
653
  throw error;
647
654
  }
@@ -655,7 +662,27 @@ class AcpProcessSession {
655
662
  arraysEqual(this.#additionalDirectories, additionalDirectories);
656
663
  canRebind = () => !this.#prompted && !this.#turn.running;
657
664
  prepared = () => new AcpPreparedSession(this.#agentName, this.#agentVersion, this.#capabilities, this.#commands, this.#configOptions, this.#restored);
658
- initialize = async (signal) => {
665
+ loadHistory = async (signal) => {
666
+ if (!this.#capabilities.loadSession)
667
+ return { status: "unavailable" };
668
+ const history = new AcpHistoryReplay();
669
+ this.#replay = { kind: "capture", history };
670
+ try {
671
+ await this.race(this.#connection.agent.request(methods.agent.session.load, {
672
+ additionalDirectories: [...this.#additionalDirectories],
673
+ cwd: this.#cwd,
674
+ mcpServers: [],
675
+ sessionId: this.#nativeSessionId,
676
+ }, { cancellationSignal: signal }), "ACP agent exited while loading history", signal);
677
+ await this.#updateTail;
678
+ signal.throwIfAborted();
679
+ return history.snapshot();
680
+ }
681
+ finally {
682
+ this.#replay = { kind: "idle" };
683
+ }
684
+ };
685
+ initialize = async (signal, origin) => {
659
686
  const initialized = await this.race(this.#connection.agent.request(methods.agent.initialize, {
660
687
  clientCapabilities: {
661
688
  elicitation: { form: {}, url: {} },
@@ -674,9 +701,31 @@ class AcpProcessSession {
674
701
  initialized.agentInfo?.name ??
675
702
  this.#agentId, 255);
676
703
  this.#agentVersion = truncate(initialized.agentInfo?.version ?? "", 128);
677
- const stored = this.#store.read(this.#mobiusSessionId);
704
+ const stored = origin?.kind === "import"
705
+ ? new FoundAcpStoredSession(new AcpStoredSession(this.#mobiusSessionId, this.#agentId, nativeSessionIdSchema.parse(origin.nativeSessionId), this.#cwd, this.#additionalDirectories, true))
706
+ : this.#store.read(this.#mobiusSessionId);
707
+ if (stored instanceof DeletedAcpStoredSession)
708
+ throw new AcpExecutionError("The native Agent session was deleted. Start a new chat.", {}, "native_session_deleted");
678
709
  let lifecycleResponse;
679
- if (stored instanceof FoundAcpStoredSession &&
710
+ if (origin?.kind === "fork") {
711
+ if (!this.#capabilities.unstableForkSession)
712
+ throw new AcpExecutionError("This Agent does not support session forking", {}, "native_session_unsupported");
713
+ const forked = await this.race(this.#connection.agent.request(methods.agent.session.fork, {
714
+ sessionId: nativeSessionIdSchema.parse(origin.nativeSessionId),
715
+ cwd: this.#cwd,
716
+ additionalDirectories: [...this.#additionalDirectories],
717
+ mcpServers: [],
718
+ }, { cancellationSignal: signal }), "ACP agent exited while forking a session", signal);
719
+ this.#nativeSessionId = nativeSessionIdSchema.parse(forked.sessionId);
720
+ if (this.#nativeSessionId === origin.nativeSessionId ||
721
+ this.#store.findNative(this.#agentId, this.#nativeSessionId).length > 0) {
722
+ throw new AcpExecutionError("The Agent did not create an independent fork", {}, "invalid_native_session_response");
723
+ }
724
+ this.#prompted = true;
725
+ this.#restored = true;
726
+ lifecycleResponse = forked;
727
+ }
728
+ else if (stored instanceof FoundAcpStoredSession &&
680
729
  stored.session.agentId === this.#agentId &&
681
730
  stored.session.cwd === this.#cwd &&
682
731
  arraysEqual(stored.session.additionalDirectories, this.#additionalDirectories)) {
@@ -692,7 +741,7 @@ class AcpProcessSession {
692
741
  }, { cancellationSignal: signal }), "ACP agent exited while resuming a session", signal);
693
742
  }
694
743
  else if (this.#capabilities.loadSession) {
695
- this.#replaying = true;
744
+ this.#replay = { kind: "discard" };
696
745
  try {
697
746
  lifecycleResponse = await this.race(this.#connection.agent.request(methods.agent.session.load, {
698
747
  additionalDirectories: [...this.#additionalDirectories],
@@ -702,7 +751,8 @@ class AcpProcessSession {
702
751
  }, { cancellationSignal: signal }), "ACP agent exited while loading a session", signal);
703
752
  }
704
753
  finally {
705
- this.#replaying = false;
754
+ await this.#updateTail;
755
+ this.#replay = { kind: "idle" };
706
756
  }
707
757
  }
708
758
  else {
@@ -731,7 +781,23 @@ class AcpProcessSession {
731
781
  this.#configOptions = normalizeConfigOptions(lifecycleRecord["configOptions"], lifecycleRecord["modes"]);
732
782
  await this.#updateTail;
733
783
  signal.throwIfAborted();
784
+ this.#store.write(new AcpStoredSession(this.#mobiusSessionId, this.#agentId, this.#nativeSessionId, this.#cwd, this.#additionalDirectories, this.#prompted));
785
+ };
786
+ listNativeSessions = async (cursor, signal) => {
787
+ if (!this.#capabilities.listSessions)
788
+ throw new AcpExecutionError("This Agent does not support native session listing", {}, "native_session_unsupported");
789
+ const response = await this.race(this.#connection.agent.request(methods.agent.session.list, cursor === null ? {} : { cursor }, { cancellationSignal: signal }), "ACP agent exited while listing sessions", signal);
790
+ const decoded = nativeSessionPageSchema.safeParse(response);
791
+ if (!decoded.success)
792
+ throw new AcpExecutionError("The Agent returned an invalid native session list", { cause: decoded.error }, "invalid_native_session_response");
793
+ return decoded.data;
734
794
  };
795
+ deleteNativeSession = async (nativeSessionId, signal) => {
796
+ if (!this.#capabilities.deleteSession || !this.#capabilities.listSessions)
797
+ throw new AcpExecutionError("This Agent does not support native session deletion", {}, "native_session_unsupported");
798
+ await this.race(this.#connection.agent.request(methods.agent.session.delete, { sessionId: nativeSessionIdSchema.parse(nativeSessionId) }, { cancellationSignal: signal }), "ACP agent exited while deleting a session", signal);
799
+ };
800
+ nativeSessionId = () => this.#nativeSessionId;
735
801
  configure = async (options) => {
736
802
  const existing = this.#configOptions.find((option) => option.id === options.configId);
737
803
  if (existing === undefined || existing.type !== options.valueType) {
@@ -821,7 +887,24 @@ class AcpProcessSession {
821
887
  const response = await this.race(this.#connection.agent.request(methods.agent.session.prompt, { prompt, sessionId: this.#nativeSessionId }, { cancellationSignal: options.signal }), "ACP agent exited during a prompt", options.signal);
822
888
  await this.#updateTail;
823
889
  await running.activities.finish();
824
- return { stopReason: response.stopReason };
890
+ let result;
891
+ try {
892
+ result = decodeAgentPromptResponse(response);
893
+ }
894
+ catch (cause) {
895
+ throw new AcpExecutionError("ACP agent returned an invalid prompt response", { cause }, "acp_invalid_prompt_response");
896
+ }
897
+ if (result.usage != null || result._meta?.quota !== undefined) {
898
+ await this.#getObserver().onUsage({
899
+ _meta: result._meta ?? null,
900
+ commandId: options.commandId,
901
+ kind: SESSION_USAGE_UPDATED_KIND,
902
+ sessionId: this.#mobiusSessionId,
903
+ source: "prompt",
904
+ usage: result.usage ?? null,
905
+ });
906
+ }
907
+ return result;
825
908
  }
826
909
  catch (error) {
827
910
  await running.activities.finish();
@@ -866,7 +949,6 @@ class AcpProcessSession {
866
949
  kind: SESSION_PERMISSION_RESOLVED_KIND,
867
950
  optionId: options.outcome === "selected" ? options.optionId : "",
868
951
  outcome: options.outcome,
869
- protocolVersion: MOBIUS_PROTOCOL_VERSION,
870
952
  sessionId: this.#mobiusSessionId,
871
953
  });
872
954
  };
@@ -901,7 +983,6 @@ class AcpProcessSession {
901
983
  action: options.action,
902
984
  interactionId: options.interactionId,
903
985
  kind: SESSION_ELICITATION_RESOLVED_KIND,
904
- protocolVersion: MOBIUS_PROTOCOL_VERSION,
905
986
  sessionId: this.#mobiusSessionId,
906
987
  });
907
988
  };
@@ -930,7 +1011,6 @@ class AcpProcessSession {
930
1011
  interactionId,
931
1012
  kind: SESSION_PERMISSION_REQUESTED_KIND,
932
1013
  options,
933
- protocolVersion: MOBIUS_PROTOCOL_VERSION,
934
1014
  sessionId: this.#mobiusSessionId,
935
1015
  title: truncate(request.toolCall.title ?? "Permission required", 500),
936
1016
  toolCallId: truncate(request.toolCall.toolCallId, 255),
@@ -975,7 +1055,6 @@ class AcpProcessSession {
975
1055
  kind: SESSION_ELICITATION_REQUESTED_KIND,
976
1056
  message: truncate(request.message, 2_000),
977
1057
  mode: request.mode,
978
- protocolVersion: MOBIUS_PROTOCOL_VERSION,
979
1058
  sessionId: this.#mobiusSessionId,
980
1059
  url: request.mode === "url" &&
981
1060
  typeof Reflect.get(request, "url") === "string"
@@ -999,7 +1078,6 @@ class AcpProcessSession {
999
1078
  action: "complete",
1000
1079
  interactionId,
1001
1080
  kind: SESSION_ELICITATION_RESOLVED_KIND,
1002
- protocolVersion: MOBIUS_PROTOCOL_VERSION,
1003
1081
  sessionId: this.#mobiusSessionId,
1004
1082
  });
1005
1083
  };
@@ -1010,7 +1088,9 @@ class AcpProcessSession {
1010
1088
  processUpdate = async (notification) => {
1011
1089
  this.assertNativeSession(notification.sessionId);
1012
1090
  const update = notification.update;
1013
- if (this.#replaying &&
1091
+ if (this.#replay.kind === "capture")
1092
+ this.#replay.history.record(update);
1093
+ if (this.#replay.kind !== "idle" &&
1014
1094
  (update.sessionUpdate === "user_message_chunk" ||
1015
1095
  update.sessionUpdate === "agent_message_chunk" ||
1016
1096
  update.sessionUpdate === "agent_thought_chunk" ||
@@ -1039,7 +1119,6 @@ class AcpProcessSession {
1039
1119
  contentId: `content-${crypto.randomUUID()}`,
1040
1120
  kind: AGENT_CONTENT_KIND,
1041
1121
  messageId: truncate(update.messageId ?? "", 255),
1042
- protocolVersion: MOBIUS_PROTOCOL_VERSION,
1043
1122
  sessionId: this.#mobiusSessionId,
1044
1123
  });
1045
1124
  }
@@ -1084,7 +1163,6 @@ class AcpProcessSession {
1084
1163
  await this.#getObserver().onCommands({
1085
1164
  commands,
1086
1165
  kind: SESSION_COMMANDS_UPDATED_KIND,
1087
- protocolVersion: MOBIUS_PROTOCOL_VERSION,
1088
1166
  sessionId: this.#mobiusSessionId,
1089
1167
  });
1090
1168
  return;
@@ -1110,7 +1188,6 @@ class AcpProcessSession {
1110
1188
  }
1111
1189
  await this.#getObserver().onInfo({
1112
1190
  kind: SESSION_INFO_UPDATED_KIND,
1113
- protocolVersion: MOBIUS_PROTOCOL_VERSION,
1114
1191
  sessionId: this.#mobiusSessionId,
1115
1192
  title: this.#sessionTitle,
1116
1193
  updatedAt: this.#sessionUpdatedAt,
@@ -1123,9 +1200,9 @@ class AcpProcessSession {
1123
1200
  costCurrency: truncate(update.cost?.currency ?? "", 16),
1124
1201
  hasCost: update.cost !== undefined && update.cost !== null,
1125
1202
  kind: SESSION_USAGE_UPDATED_KIND,
1126
- protocolVersion: MOBIUS_PROTOCOL_VERSION,
1127
1203
  sessionId: this.#mobiusSessionId,
1128
1204
  size: Math.max(0, Math.trunc(update.size)),
1205
+ source: "context",
1129
1206
  used: Math.max(0, Math.trunc(update.used)),
1130
1207
  });
1131
1208
  }
@@ -1182,7 +1259,6 @@ class AcpProcessSession {
1182
1259
  await this.#getObserver().onConfig({
1183
1260
  configOptions: this.#configOptions,
1184
1261
  kind: SESSION_CONFIG_UPDATED_KIND,
1185
- protocolVersion: MOBIUS_PROTOCOL_VERSION,
1186
1262
  requestId: `agent-update-${crypto.randomUUID()}`,
1187
1263
  sessionId: this.#mobiusSessionId,
1188
1264
  });
@@ -1198,7 +1274,6 @@ class AcpProcessSession {
1198
1274
  kind: SESSION_PERMISSION_RESOLVED_KIND,
1199
1275
  optionId: "",
1200
1276
  outcome: "cancelled",
1201
- protocolVersion: MOBIUS_PROTOCOL_VERSION,
1202
1277
  sessionId: this.#mobiusSessionId,
1203
1278
  });
1204
1279
  };
@@ -1212,7 +1287,6 @@ class AcpProcessSession {
1212
1287
  action: "cancel",
1213
1288
  interactionId,
1214
1289
  kind: SESSION_ELICITATION_RESOLVED_KIND,
1215
- protocolVersion: MOBIUS_PROTOCOL_VERSION,
1216
1290
  sessionId: this.#mobiusSessionId,
1217
1291
  });
1218
1292
  };
@@ -1232,13 +1306,13 @@ class AcpProcessSession {
1232
1306
  action: "cancel",
1233
1307
  interactionId,
1234
1308
  kind: SESSION_ELICITATION_RESOLVED_KIND,
1235
- protocolVersion: MOBIUS_PROTOCOL_VERSION,
1236
1309
  sessionId: this.#mobiusSessionId,
1237
1310
  });
1238
1311
  }
1239
1312
  };
1240
1313
  }
1241
1314
  export class AcpSessionManager {
1315
+ #nativeOperations = new Set();
1242
1316
  #activeSessionIds = new Set();
1243
1317
  #cancellationRequests = new Set();
1244
1318
  #preparing = new Map();
@@ -1284,6 +1358,12 @@ export class AcpSessionManager {
1284
1358
  return await operation;
1285
1359
  }
1286
1360
  prepareSession = async (options) => {
1361
+ const stored = this.#store.read(options.sessionId);
1362
+ if (stored instanceof DeletedAcpStoredSession)
1363
+ throw new AcpExecutionError("The native Agent session was deleted. Start a new chat.", {}, "native_session_deleted");
1364
+ if (stored instanceof FoundAcpStoredSession &&
1365
+ this.#nativeOperations.has(`${stored.session.agentId}:${stored.session.nativeSessionId}`))
1366
+ throw new AcpExecutionError("The native session is being managed", {}, "session_busy");
1287
1367
  const pending = this.#preparing.get(options.sessionId);
1288
1368
  if (pending !== undefined) {
1289
1369
  const runtime = await pending;
@@ -1318,6 +1398,11 @@ export class AcpSessionManager {
1318
1398
  }
1319
1399
  };
1320
1400
  runPrompt = async (options) => {
1401
+ const stored = this.#store.read(options.sessionId);
1402
+ if (stored instanceof FoundAcpStoredSession &&
1403
+ this.#nativeOperations.has(`${stored.session.agentId}:${stored.session.nativeSessionId}`)) {
1404
+ throw new AcpExecutionError("The native session is being managed", {}, "session_busy");
1405
+ }
1321
1406
  if (this.#activeSessionIds.has(options.sessionId)) {
1322
1407
  throw new AcpExecutionError("Another prompt is already running in this conversation", {}, "session_busy");
1323
1408
  }
@@ -1327,6 +1412,8 @@ export class AcpSessionManager {
1327
1412
  return { stopReason: "cancelled" };
1328
1413
  }
1329
1414
  const runtime = await this.ensureSession(options);
1415
+ if (this.#nativeOperations.has(`${options.agent.id}:${runtime.nativeSessionId()}`))
1416
+ throw new AcpExecutionError("The native session is being managed", {}, "session_busy");
1330
1417
  if (this.#cancellationRequests.has(options.sessionId)) {
1331
1418
  return { stopReason: "cancelled" };
1332
1419
  }
@@ -1384,5 +1471,103 @@ export class AcpSessionManager {
1384
1471
  }
1385
1472
  return started;
1386
1473
  };
1474
+ listNativeSessions = async (options, cursor) => await (await this.ensureSession(options)).listNativeSessions(cursor, options.signal);
1475
+ openNativeSession = async (options, origin) => {
1476
+ const key = `${options.agent.id}:${origin.nativeSessionId}`;
1477
+ if (this.#nativeOperations.has(key))
1478
+ throw new AcpExecutionError("The native session is being managed", {}, "session_busy");
1479
+ const linked = this.#store.findNative(options.agent.id, origin.nativeSessionId);
1480
+ if (linked.some((entry) => this.#activeSessionIds.has(entry.sessionId) ||
1481
+ this.#preparing.has(entry.sessionId)))
1482
+ throw new AcpExecutionError("Wait for the native session's running operation to finish", {}, "session_busy");
1483
+ const existing = linked[0];
1484
+ if (origin.kind === "import" && existing !== undefined) {
1485
+ const runtime = await this.ensureSession({
1486
+ ...options,
1487
+ sessionId: existing.sessionId,
1488
+ });
1489
+ if (this.#activeSessionIds.has(existing.sessionId) ||
1490
+ this.#nativeOperations.has(key))
1491
+ throw new AcpExecutionError("Wait for the native session's running operation to finish", {}, "session_busy");
1492
+ this.#nativeOperations.add(key);
1493
+ try {
1494
+ const history = await runtime.loadHistory(options.signal);
1495
+ return {
1496
+ prepared: runtime.prepared(),
1497
+ sessionId: existing.sessionId,
1498
+ history,
1499
+ };
1500
+ }
1501
+ catch (error) {
1502
+ this.#sessions.delete(existing.sessionId);
1503
+ await runtime.closeProcess();
1504
+ throw error;
1505
+ }
1506
+ finally {
1507
+ this.#nativeOperations.delete(key);
1508
+ }
1509
+ }
1510
+ if (this.#sessions.has(options.sessionId) ||
1511
+ this.#preparing.has(options.sessionId) ||
1512
+ this.#store.read(options.sessionId) instanceof FoundAcpStoredSession ||
1513
+ this.#store.read(options.sessionId) instanceof DeletedAcpStoredSession)
1514
+ throw new AcpExecutionError("The destination conversation already exists", {}, "session_identity_mismatch");
1515
+ this.#nativeOperations.add(key);
1516
+ try {
1517
+ const runtime = await this.#startPreparation({ ...options, origin });
1518
+ const openedKey = `${options.agent.id}:${runtime.nativeSessionId()}`;
1519
+ this.#nativeOperations.add(openedKey);
1520
+ try {
1521
+ const history = await runtime.loadHistory(options.signal);
1522
+ return {
1523
+ sessionId: options.sessionId,
1524
+ prepared: runtime.prepared(),
1525
+ history,
1526
+ };
1527
+ }
1528
+ catch (error) {
1529
+ this.#sessions.delete(options.sessionId);
1530
+ this.#store.remove(options.sessionId);
1531
+ await runtime.closeProcess();
1532
+ throw error;
1533
+ }
1534
+ finally {
1535
+ this.#nativeOperations.delete(openedKey);
1536
+ }
1537
+ }
1538
+ finally {
1539
+ this.#nativeOperations.delete(key);
1540
+ }
1541
+ };
1542
+ deleteNativeSession = async (options, nativeSessionId) => {
1543
+ const runtime = await this.ensureSession(options);
1544
+ const key = `${options.agent.id}:${nativeSessionId}`;
1545
+ const linked = this.#store.findNative(options.agent.id, nativeSessionId);
1546
+ if (this.#nativeOperations.has(key) ||
1547
+ linked.some((entry) => this.#activeSessionIds.has(entry.sessionId) ||
1548
+ this.#preparing.has(entry.sessionId)))
1549
+ throw new AcpExecutionError("Wait for the native session's running operation to finish", {}, "session_busy");
1550
+ this.#nativeOperations.add(key);
1551
+ try {
1552
+ for (const entry of linked) {
1553
+ const active = this.#sessions.get(entry.sessionId);
1554
+ if (active !== undefined && active !== runtime) {
1555
+ this.#sessions.delete(entry.sessionId);
1556
+ await active.close();
1557
+ }
1558
+ }
1559
+ options.signal.throwIfAborted();
1560
+ await runtime.deleteNativeSession(nativeSessionId, options.signal);
1561
+ const deleted = this.#store.markDeleted(options.agent.id, nativeSessionId);
1562
+ if (runtime.nativeSessionId() === nativeSessionId) {
1563
+ this.#sessions.delete(options.sessionId);
1564
+ await runtime.close();
1565
+ }
1566
+ return deleted;
1567
+ }
1568
+ finally {
1569
+ this.#nativeOperations.delete(key);
1570
+ }
1571
+ };
1387
1572
  }
1388
1573
  //# sourceMappingURL=session-manager.js.map