@moxt-ai/mobius 0.0.150 → 0.0.153

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 (61) hide show
  1. package/dist/acp/agent-runtime-manager.d.ts.map +1 -1
  2. package/dist/acp/agent-runtime-manager.js +8 -1
  3. package/dist/acp/agent-runtime-manager.js.map +1 -1
  4. package/dist/acp/agent-session.d.ts.map +1 -1
  5. package/dist/acp/agent-session.js +8 -4
  6. package/dist/acp/agent-session.js.map +1 -1
  7. package/dist/acp/session-contracts.d.ts +2 -1
  8. package/dist/acp/session-contracts.d.ts.map +1 -1
  9. package/dist/acp/session-contracts.js +3 -1
  10. package/dist/acp/session-contracts.js.map +1 -1
  11. package/dist/acp/session-store.d.ts +2 -1
  12. package/dist/acp/session-store.d.ts.map +1 -1
  13. package/dist/acp/session-store.js +6 -2
  14. package/dist/acp/session-store.js.map +1 -1
  15. package/dist/cli.js +274 -76
  16. package/dist/cli.js.map +3 -3
  17. package/dist/daemon-active-turn.d.ts +1 -0
  18. package/dist/daemon-active-turn.d.ts.map +1 -1
  19. package/dist/daemon-active-turn.js +1 -0
  20. package/dist/daemon-active-turn.js.map +1 -1
  21. package/dist/daemon-command-handler.d.ts.map +1 -1
  22. package/dist/daemon-command-handler.js +1 -0
  23. package/dist/daemon-command-handler.js.map +1 -1
  24. package/dist/daemon-prompt-executor.d.ts.map +1 -1
  25. package/dist/daemon-prompt-executor.js +28 -8
  26. package/dist/daemon-prompt-executor.js.map +1 -1
  27. package/dist/daemon-turn-registry.d.ts +15 -14
  28. package/dist/daemon-turn-registry.d.ts.map +1 -1
  29. package/dist/daemon-turn-registry.js +32 -34
  30. package/dist/daemon-turn-registry.js.map +1 -1
  31. package/dist/generated/acp-session-store-migrations.d.ts +3 -0
  32. package/dist/generated/acp-session-store-migrations.d.ts.map +1 -1
  33. package/dist/generated/acp-session-store-migrations.js +5 -1
  34. package/dist/generated/acp-session-store-migrations.js.map +1 -1
  35. package/dist/index.js +264 -73
  36. package/dist/index.js.map +3 -3
  37. package/dist/native-sessions/handle-native-requests.d.ts +2 -0
  38. package/dist/native-sessions/handle-native-requests.d.ts.map +1 -1
  39. package/dist/native-sessions/handle-native-requests.js +12 -1
  40. package/dist/native-sessions/handle-native-requests.js.map +1 -1
  41. package/dist/native-sessions/live-history-page.d.ts.map +1 -1
  42. package/dist/native-sessions/live-history-page.js +2 -0
  43. package/dist/native-sessions/live-history-page.js.map +1 -1
  44. package/dist/native-sessions/service.d.ts.map +1 -1
  45. package/dist/native-sessions/service.js +47 -0
  46. package/dist/native-sessions/service.js.map +1 -1
  47. package/dist/relay-connection/session-event-outbox.d.ts +1 -0
  48. package/dist/relay-connection/session-event-outbox.d.ts.map +1 -1
  49. package/dist/relay-connection/session-event-outbox.js +37 -22
  50. package/dist/relay-connection/session-event-outbox.js.map +1 -1
  51. package/dist/relay-connection/session-event-publisher.d.ts +1 -0
  52. package/dist/relay-connection/session-event-publisher.d.ts.map +1 -1
  53. package/dist/relay-connection/session-event-publisher.js +10 -2
  54. package/dist/relay-connection/session-event-publisher.js.map +1 -1
  55. package/dist/runtime.js +266 -75
  56. package/dist/runtime.js.map +3 -3
  57. package/dist/schema/acp-session-store/acp-session.d.ts +19 -0
  58. package/dist/schema/acp-session-store/acp-session.d.ts.map +1 -1
  59. package/dist/schema/acp-session-store/acp-session.js +1 -0
  60. package/dist/schema/acp-session-store/acp-session.js.map +1 -1
  61. package/package.json +10 -3
package/dist/runtime.js CHANGED
@@ -20964,6 +20964,11 @@ var assistantHistoryMessageSchema = external_exports.strictObject({
20964
20964
  }).readonly();
20965
20965
  var historyMessage = external_exports.discriminatedUnion("role", [userHistoryMessage, assistantHistoryMessageSchema]);
20966
20966
  var availableSessionHistoryObjectSchema = external_exports.strictObject({
20967
+ streamPosition: external_exports.strictObject({
20968
+ commandId: identifierStringSchema,
20969
+ epoch: identifierStringSchema,
20970
+ sequence: external_exports.number().int().nonnegative()
20971
+ }).readonly().optional(),
20967
20972
  status: external_exports.literal("available"),
20968
20973
  messages: external_exports.array(historyMessage).max(SESSION_HISTORY_MESSAGE_LIMIT).readonly(),
20969
20974
  truncated: external_exports.boolean(),
@@ -21082,6 +21087,12 @@ var nativeSessionRequestSchema = external_exports.discriminatedUnion("action", [
21082
21087
  entryId: identifierStringSchema,
21083
21088
  targetSessionId: identifierStringSchema
21084
21089
  }).readonly(),
21090
+ external_exports.strictObject({
21091
+ ...identity,
21092
+ action: external_exports.literal("fork-recorded"),
21093
+ targetSessionId: identifierStringSchema,
21094
+ throughCommandId: identifierStringSchema
21095
+ }).readonly(),
21085
21096
  external_exports.strictObject({
21086
21097
  ...identity,
21087
21098
  action: external_exports.literal("delete"),
@@ -21105,6 +21116,12 @@ var nativeSessionCommandSchema = external_exports.discriminatedUnion("action", [
21105
21116
  entryId: identifierStringSchema,
21106
21117
  targetSessionId: identifierStringSchema
21107
21118
  }).readonly(),
21119
+ external_exports.strictObject({
21120
+ ...identity,
21121
+ action: external_exports.literal("fork-recorded"),
21122
+ targetSessionId: identifierStringSchema,
21123
+ throughCommandId: identifierStringSchema
21124
+ }).readonly(),
21108
21125
  external_exports.strictObject({
21109
21126
  ...identity,
21110
21127
  action: external_exports.literal("delete"),
@@ -21154,7 +21171,7 @@ var nativeSessionResultSchema = external_exports.discriminatedUnion("action", [
21154
21171
  }).readonly(),
21155
21172
  external_exports.strictObject({
21156
21173
  ...resultEnvelope,
21157
- action: external_exports.enum(["import", "fork"]),
21174
+ action: external_exports.enum(["import", "fork", "fork-recorded"]),
21158
21175
  targetSessionId: identifierStringSchema,
21159
21176
  ready: sessionReadyEventSchema,
21160
21177
  title: external_exports.string().max(500)
@@ -21203,6 +21220,7 @@ var SESSION_EVENT_KIND = "session.event";
21203
21220
  var SESSION_EVENT_ACK_KIND = "session.event.ack";
21204
21221
  var SESSION_EVENT_DEFERRED_KIND = "session.event.deferred";
21205
21222
  var SESSION_EVENT_REJECTED_KIND = "session.event.rejected";
21223
+ var SESSION_FORKED_KIND = "session.forked";
21206
21224
  var SessionEventRejectionCode = {
21207
21225
  IdempotencyConflict: "idempotency_conflict",
21208
21226
  InvalidEvent: "invalid_event",
@@ -21220,13 +21238,13 @@ var reliableDeliverySchema = external_exports.strictObject({
21220
21238
  sourceSeq: external_exports.string().regex(/^(?:0|[1-9][0-9]*)$/u).max(40),
21221
21239
  streamId: identifierStringSchema
21222
21240
  }).readonly();
21223
- var reliableEventEnvelopeSchema = external_exports.strictObject({
21241
+ var reliableSessionEventEnvelopeSchema = external_exports.strictObject({
21224
21242
  delivery: reliableDeliverySchema,
21225
21243
  kind: external_exports.literal(SESSION_EVENT_KIND),
21226
21244
  payload: external_exports.string().min(2).max(MAX_RECORDED_EVENT_LENGTH),
21227
21245
  sessionId: identifierStringSchema
21228
21246
  }).readonly();
21229
- var eventEnvelopeSchema = external_exports.union([ephemeralEventEnvelopeSchema, reliableEventEnvelopeSchema]).readonly();
21247
+ var eventEnvelopeSchema = external_exports.union([ephemeralEventEnvelopeSchema, reliableSessionEventEnvelopeSchema]).readonly();
21230
21248
  var acknowledgementOutcomeSchema = external_exports.discriminatedUnion("kind", [
21231
21249
  external_exports.strictObject({ kind: external_exports.literal("relayed") }).readonly(),
21232
21250
  external_exports.strictObject({
@@ -21255,6 +21273,12 @@ var eventRejectedSchema = external_exports.strictObject({
21255
21273
  }).readonly();
21256
21274
  var SESSION_QUEUE_CHANGED_KIND = "session.queue.changed";
21257
21275
  var sessionQueueChangedSchema = external_exports.strictObject({ kind: external_exports.literal(SESSION_QUEUE_CHANGED_KIND), sessionId: identifierStringSchema }).readonly();
21276
+ var sessionForkedSchema = external_exports.strictObject({
21277
+ kind: external_exports.literal(SESSION_FORKED_KIND),
21278
+ sessionId: identifierStringSchema,
21279
+ sourceSessionId: identifierStringSchema,
21280
+ throughCommandId: identifierStringSchema
21281
+ }).readonly();
21258
21282
  function decode5(encoded, schema) {
21259
21283
  let value;
21260
21284
  try {
@@ -21292,6 +21316,8 @@ function decodeRecordedSessionEvent(encoded) {
21292
21316
  switch (kind) {
21293
21317
  case SESSION_QUEUE_CHANGED_KIND:
21294
21318
  return decode5(encoded, sessionQueueChangedSchema);
21319
+ case SESSION_FORKED_KIND:
21320
+ return decode5(encoded, sessionForkedSchema);
21295
21321
  case AGENT_ACTIVITY_KIND:
21296
21322
  return decodeAgentActivityEvent(encoded);
21297
21323
  case AGENT_ACTIVITY_NARRATION_KIND:
@@ -28332,13 +28358,15 @@ var AcpPreparedSession = class {
28332
28358
  capabilities;
28333
28359
  commands;
28334
28360
  configOptions;
28361
+ prompted;
28335
28362
  restored;
28336
- constructor(agentName, agentVersion, capabilities, commands, configOptions, restored) {
28363
+ constructor(agentName, agentVersion, capabilities, commands, configOptions, prompted, restored) {
28337
28364
  this.agentName = agentName;
28338
28365
  this.agentVersion = agentVersion;
28339
28366
  this.capabilities = capabilities;
28340
28367
  this.commands = commands;
28341
28368
  this.configOptions = configOptions;
28369
+ this.prompted = prompted;
28342
28370
  this.restored = restored;
28343
28371
  }
28344
28372
  };
@@ -34508,6 +34536,10 @@ var acpSessionStoreMigrations = [
34508
34536
  {
34509
34537
  "name": "0000_slimy_captain_midlands.sql",
34510
34538
  "sql": "CREATE TABLE `acp_session` (\n `session_id` text PRIMARY KEY NOT NULL,\n `agent_id` text NOT NULL,\n `native_session_id` text NOT NULL,\n `cwd` text NOT NULL,\n `additional_directories` text NOT NULL,\n `prompted` integer NOT NULL,\n `title` text NOT NULL,\n `updated_at` text NOT NULL\n);\n--> statement-breakpoint\nCREATE TABLE `deleted_acp_session` (\n `session_id` text PRIMARY KEY NOT NULL\n);\n"
34539
+ },
34540
+ {
34541
+ "name": "0001_regular_ultimates.sql",
34542
+ "sql": "ALTER TABLE `acp_session` ADD `last_terminal_command_id` text;"
34511
34543
  }
34512
34544
  ];
34513
34545
 
@@ -34525,6 +34557,7 @@ var acpSession = sqliteTable("acp_session", {
34525
34557
  nativeSessionId: text("native_session_id").notNull(),
34526
34558
  cwd: text("cwd").notNull(),
34527
34559
  additionalDirectories: text("additional_directories").notNull(),
34560
+ lastTerminalCommandId: text("last_terminal_command_id"),
34528
34561
  prompted: integer2("prompted", { mode: "boolean" }).notNull(),
34529
34562
  title: text("title").notNull(),
34530
34563
  updatedAt: text("updated_at").notNull()
@@ -34540,15 +34573,17 @@ var AcpStoredSession = class {
34540
34573
  additionalDirectories;
34541
34574
  agentId;
34542
34575
  cwd;
34576
+ lastTerminalCommandId;
34543
34577
  nativeSessionId;
34544
34578
  prompted;
34545
34579
  sessionId;
34546
34580
  title;
34547
34581
  updatedAt;
34548
- constructor(sessionId, agentId, nativeSessionId, cwd, additionalDirectories, prompted, title2, updatedAt = (/* @__PURE__ */ new Date()).toISOString()) {
34582
+ constructor(sessionId, agentId, nativeSessionId, cwd, additionalDirectories, prompted, title2, updatedAt = (/* @__PURE__ */ new Date()).toISOString(), lastTerminalCommandId = null) {
34549
34583
  this.additionalDirectories = [...additionalDirectories];
34550
34584
  this.agentId = agentId;
34551
34585
  this.cwd = cwd;
34586
+ this.lastTerminalCommandId = lastTerminalCommandId;
34552
34587
  this.nativeSessionId = nativeSessionId;
34553
34588
  this.prompted = prompted;
34554
34589
  this.sessionId = sessionId;
@@ -34609,6 +34644,7 @@ var storedSessionRowSchema = external_exports.object({
34609
34644
  additionalDirectories: external_exports.string(),
34610
34645
  agentId: external_exports.string(),
34611
34646
  cwd: external_exports.string(),
34647
+ lastTerminalCommandId: external_exports.string().nullable(),
34612
34648
  nativeSessionId: external_exports.string(),
34613
34649
  prompted: external_exports.boolean(),
34614
34650
  sessionId: external_exports.string(),
@@ -34628,7 +34664,8 @@ function decodeStoredSession(value) {
34628
34664
  additionalDirectories,
34629
34665
  row.prompted,
34630
34666
  row.title,
34631
- row.updatedAt
34667
+ row.updatedAt,
34668
+ row.lastTerminalCommandId
34632
34669
  );
34633
34670
  }
34634
34671
  var SqliteAcpSessionStore = class {
@@ -34695,6 +34732,7 @@ var SqliteAcpSessionStore = class {
34695
34732
  additionalDirectories: JSON.stringify(session.additionalDirectories),
34696
34733
  agentId: session.agentId,
34697
34734
  cwd: session.cwd,
34735
+ lastTerminalCommandId: session.lastTerminalCommandId,
34698
34736
  nativeSessionId: session.nativeSessionId,
34699
34737
  prompted: session.prompted,
34700
34738
  sessionId: session.sessionId,
@@ -34747,6 +34785,7 @@ var AgentSession = class _AgentSession {
34747
34785
  #commands = [];
34748
34786
  #configRevision = 0;
34749
34787
  #configOptions = [];
34788
+ #lastTerminalCommandId = null;
34750
34789
  #prompted = false;
34751
34790
  #nativePrompt = null;
34752
34791
  #sessionLoad = { kind: "not-requested" };
@@ -34850,6 +34889,7 @@ var AgentSession = class _AgentSession {
34850
34889
  this.#capabilities,
34851
34890
  this.#commands,
34852
34891
  this.#configOptions,
34892
+ this.#prompted,
34853
34893
  this.#restored
34854
34894
  );
34855
34895
  loadHistory = async (signal) => {
@@ -35083,6 +35123,7 @@ var AgentSession = class _AgentSession {
35083
35123
  } else if (stored instanceof FoundAcpStoredSession && stored.session.agentId === this.#agentId && stored.session.cwd === this.#cwd && arraysEqual(stored.session.additionalDirectories, this.#additionalDirectories)) {
35084
35124
  this.selectNativeSession(stored.session.nativeSessionId);
35085
35125
  this.#prompted = stored.session.prompted;
35126
+ this.#lastTerminalCommandId = stored.session.lastTerminalCommandId;
35086
35127
  this.#sessionTitle = stored.session.title;
35087
35128
  this.#restored = true;
35088
35129
  if (this.#capabilities.resumeSession) {
@@ -35156,7 +35197,9 @@ var AgentSession = class _AgentSession {
35156
35197
  this.#cwd,
35157
35198
  this.#additionalDirectories,
35158
35199
  this.#prompted,
35159
- this.#sessionTitle ?? ""
35200
+ this.#sessionTitle ?? "",
35201
+ (/* @__PURE__ */ new Date()).toISOString(),
35202
+ this.#lastTerminalCommandId
35160
35203
  )
35161
35204
  );
35162
35205
  };
@@ -35356,7 +35399,9 @@ var AgentSession = class _AgentSession {
35356
35399
  this.#cwd,
35357
35400
  this.#additionalDirectories,
35358
35401
  true,
35359
- this.#sessionTitle
35402
+ this.#sessionTitle,
35403
+ (/* @__PURE__ */ new Date()).toISOString(),
35404
+ this.#lastTerminalCommandId
35360
35405
  )
35361
35406
  );
35362
35407
  this.#prompted = true;
@@ -35408,6 +35453,20 @@ var AgentSession = class _AgentSession {
35408
35453
  usage: result.usage ?? null
35409
35454
  });
35410
35455
  }
35456
+ this.#lastTerminalCommandId = options.commandId;
35457
+ this.#store.write(
35458
+ new AcpStoredSession(
35459
+ this.#mobiusSessionId,
35460
+ this.#agentId,
35461
+ this.#updates.sessionId(),
35462
+ this.#cwd,
35463
+ this.#additionalDirectories,
35464
+ true,
35465
+ this.#sessionTitle ?? "",
35466
+ (/* @__PURE__ */ new Date()).toISOString(),
35467
+ this.#lastTerminalCommandId
35468
+ )
35469
+ );
35411
35470
  return result;
35412
35471
  } catch (error62) {
35413
35472
  await running.activities.finish();
@@ -35600,7 +35659,9 @@ var AgentSession = class _AgentSession {
35600
35659
  this.#cwd,
35601
35660
  this.#additionalDirectories,
35602
35661
  this.#prompted,
35603
- this.#sessionTitle ?? ""
35662
+ this.#sessionTitle ?? "",
35663
+ (/* @__PURE__ */ new Date()).toISOString(),
35664
+ this.#lastTerminalCommandId
35604
35665
  )
35605
35666
  );
35606
35667
  }
@@ -36646,9 +36707,17 @@ var AgentRuntimeManager = class {
36646
36707
  const openedKey = `${options2.agent.id}:${runtime.nativeSessionId()}`;
36647
36708
  this.#nativeOperations.add(openedKey);
36648
36709
  try {
36710
+ const prepared = runtime.prepared();
36711
+ if (origin.kind === "fork" && options2.agent.id === "claude") {
36712
+ await this.#retireSessionProcess(
36713
+ options2.sessionId,
36714
+ runtime,
36715
+ async () => await runtime.closeProcess()
36716
+ );
36717
+ }
36649
36718
  return {
36650
36719
  sessionId: options2.sessionId,
36651
- prepared: runtime.prepared()
36720
+ prepared
36652
36721
  };
36653
36722
  } finally {
36654
36723
  this.#nativeOperations.delete(openedKey);
@@ -38169,6 +38238,7 @@ var ActiveDaemonTurn = class {
38169
38238
  commandId: decodeIdentifier(this.command.commandId),
38170
38239
  epoch: this.#epoch,
38171
38240
  messages: this.timelineMessages(),
38241
+ sequence: this.#sequence,
38172
38242
  state: "running",
38173
38243
  truncated: false
38174
38244
  };
@@ -38196,7 +38266,7 @@ var ActiveDaemonTurn = class {
38196
38266
  };
38197
38267
 
38198
38268
  // src/daemon-turn-registry.ts
38199
- var COMPLETED_TURN_RECOVERY_LIMIT = 32;
38269
+ var MAX_SESSIONS_WITH_COMPLETED_RECOVERY = 32;
38200
38270
  var waitForTurnCompletion = (turn, waitSignal) => {
38201
38271
  waitSignal.throwIfAborted();
38202
38272
  return new Promise((resolve9, reject) => {
@@ -38222,46 +38292,46 @@ var waitForTurnCompletion = (turn, waitSignal) => {
38222
38292
  });
38223
38293
  };
38224
38294
  var DaemonTurnRegistry = class {
38225
- #turns = /* @__PURE__ */ new Map();
38226
- #completed = /* @__PURE__ */ new Map();
38295
+ #inFlightByCommandId = /* @__PURE__ */ new Map();
38296
+ #latestCompletedBySessionId = /* @__PURE__ */ new Map();
38227
38297
  #operations;
38228
38298
  constructor(operations) {
38229
38299
  this.#operations = operations;
38230
38300
  }
38231
38301
  start = (command, attemptId) => {
38232
38302
  const turn = new ActiveDaemonTurn(command, attemptId);
38233
- this.#turns.set(command.commandId, turn);
38303
+ this.#inFlightByCommandId.set(command.commandId, turn);
38234
38304
  return turn;
38235
38305
  };
38236
- get = (commandId) => this.#turns.get(commandId);
38306
+ get = (commandId) => this.#inFlightByCommandId.get(commandId);
38237
38307
  finish = (turn) => {
38238
38308
  const recovery = turn.recovery();
38239
- this.#turns.delete(turn.command.commandId);
38309
+ this.#inFlightByCommandId.delete(turn.command.commandId);
38240
38310
  if (recovery !== null) {
38241
- this.#completed.delete(turn.command.sessionId);
38242
- this.#completed.set(turn.command.sessionId, {
38243
- command: turn.command,
38244
- recovery: { ...recovery, state: "completed" }
38245
- });
38246
- while (this.#completed.size > COMPLETED_TURN_RECOVERY_LIMIT) {
38247
- const oldestSessionId = this.#completed.keys().next().value;
38248
- if (oldestSessionId === void 0) {
38249
- break;
38250
- }
38251
- this.#completed.delete(oldestSessionId);
38252
- }
38311
+ this.retainLatestCompletedRecovery(turn.command, { ...recovery, state: "completed" });
38253
38312
  }
38254
38313
  turn.finish();
38255
38314
  };
38315
+ retainLatestCompletedRecovery = (command, recovery) => {
38316
+ this.#latestCompletedBySessionId.delete(command.sessionId);
38317
+ this.#latestCompletedBySessionId.set(command.sessionId, { command, recovery });
38318
+ while (this.#latestCompletedBySessionId.size > MAX_SESSIONS_WITH_COMPLETED_RECOVERY) {
38319
+ const oldestSessionId = this.#latestCompletedBySessionId.keys().next().value;
38320
+ if (oldestSessionId === void 0) {
38321
+ break;
38322
+ }
38323
+ this.#latestCompletedBySessionId.delete(oldestSessionId);
38324
+ }
38325
+ };
38256
38326
  recordEvent = (event) => {
38257
38327
  if ("commandId" in event) {
38258
- const turn = this.#turns.get(event.commandId);
38328
+ const turn = this.#inFlightByCommandId.get(event.commandId);
38259
38329
  if (turn !== void 0 && turn.command.sessionId === event.sessionId) {
38260
38330
  return turn.recordEvent(event);
38261
38331
  }
38262
38332
  }
38263
38333
  if (event.kind === SESSION_PERMISSION_RESOLVED_KIND || event.kind === SESSION_ELICITATION_RESOLVED_KIND) {
38264
- for (const turn of this.#turns.values()) {
38334
+ for (const turn of this.#inFlightByCommandId.values()) {
38265
38335
  if (turn.matchesInteraction(event.interactionId, event.sessionId)) {
38266
38336
  return turn.recordEvent(event);
38267
38337
  }
@@ -38270,17 +38340,17 @@ var DaemonTurnRegistry = class {
38270
38340
  return event;
38271
38341
  };
38272
38342
  recordSteeringPrompt = (command) => {
38273
- const target = this.#turns.get(command.targetCommandId);
38343
+ const target = this.#inFlightByCommandId.get(command.targetCommandId);
38274
38344
  return target?.recordSteeringPrompt(command) ?? false;
38275
38345
  };
38276
38346
  executionSnapshot = async (matches) => {
38277
38347
  const matching = [];
38278
- for (const turn of this.#turns.values()) {
38348
+ for (const turn of this.#inFlightByCommandId.values()) {
38279
38349
  if (await matches(turn.command)) {
38280
38350
  matching.push(turn);
38281
38351
  }
38282
38352
  }
38283
- const current = matching.filter((turn) => this.#turns.get(turn.command.commandId) === turn);
38353
+ const current = matching.filter((turn) => this.#inFlightByCommandId.get(turn.command.commandId) === turn);
38284
38354
  return {
38285
38355
  turn: current.map((turn) => turn.snapshot()).find((snapshot) => snapshot !== null) ?? null,
38286
38356
  queued: current.filter((turn) => turn.isQueued()).map(({ command }) => ({
@@ -38291,7 +38361,7 @@ var DaemonTurnRegistry = class {
38291
38361
  };
38292
38362
  };
38293
38363
  snapshot = (matches) => {
38294
- for (const turn of this.#turns.values()) {
38364
+ for (const turn of this.#inFlightByCommandId.values()) {
38295
38365
  if (!matches(turn.command)) {
38296
38366
  continue;
38297
38367
  }
@@ -38303,7 +38373,7 @@ var DaemonTurnRegistry = class {
38303
38373
  return null;
38304
38374
  };
38305
38375
  recovery = (matches) => {
38306
- for (const turn of this.#turns.values()) {
38376
+ for (const turn of this.#inFlightByCommandId.values()) {
38307
38377
  if (!matches(turn.command)) {
38308
38378
  continue;
38309
38379
  }
@@ -38312,7 +38382,7 @@ var DaemonTurnRegistry = class {
38312
38382
  return recovery;
38313
38383
  }
38314
38384
  }
38315
- for (const completed of this.#completed.values()) {
38385
+ for (const completed of this.#latestCompletedBySessionId.values()) {
38316
38386
  if (matches(completed.command)) {
38317
38387
  return completed.recovery;
38318
38388
  }
@@ -38320,17 +38390,17 @@ var DaemonTurnRegistry = class {
38320
38390
  return null;
38321
38391
  };
38322
38392
  close = async () => {
38323
- const turns = [...this.#turns.values()];
38393
+ const turns = [...this.#inFlightByCommandId.values()];
38324
38394
  for (const turn of turns) {
38325
38395
  turn.abortDaemon();
38326
38396
  }
38327
38397
  await Promise.all(turns.map((turn) => turn.completion));
38328
- this.#completed.clear();
38398
+ this.#latestCompletedBySessionId.clear();
38329
38399
  };
38330
38400
  admitAndWait = async (turn, waitSignal, onQueued) => {
38331
38401
  const command = turn.command;
38332
38402
  waitSignal.throwIfAborted();
38333
- const head = () => [...this.#turns.values()].find(
38403
+ const head = () => [...this.#inFlightByCommandId.values()].find(
38334
38404
  (turn2) => turn2.command.sessionId === command.sessionId && turn2.command.disposition !== SessionPromptDisposition.Steer
38335
38405
  );
38336
38406
  if (command.disposition === SessionPromptDisposition.Queue) {
@@ -39059,6 +39129,7 @@ var readCodexFullHistory = async (agent, cwd, nativeSessionId, signal, nativeTur
39059
39129
 
39060
39130
  // src/native-sessions/service.ts
39061
39131
  import { randomUUID as randomUUID2 } from "node:crypto";
39132
+ import { basename as basename4 } from "node:path";
39062
39133
 
39063
39134
  // src/native-sessions/acp-history.ts
39064
39135
  async function readAcpHistory(sessions, directories, bindingId, options, nativeSessionId) {
@@ -39199,6 +39270,64 @@ var NativeSessionService = class {
39199
39270
  sessionId: command.sessionId
39200
39271
  };
39201
39272
  }
39273
+ if (command.action === "fork-recorded") {
39274
+ const source = this.#sessions.findSessions([command.sessionId])[0];
39275
+ if (source === void 0 || !source.prompted) {
39276
+ throw new AcpExecutionError(
39277
+ "The source conversation has no resumable native Agent session",
39278
+ {},
39279
+ "native_session_not_found"
39280
+ );
39281
+ }
39282
+ if (source.agentId !== command.agentId || source.cwd !== cwd || source.additionalDirectories.length !== additionalDirectories.length || source.additionalDirectories.some((path2, index) => path2 !== additionalDirectories[index])) {
39283
+ throw new AcpExecutionError(
39284
+ "The source conversation execution target does not match the fork request",
39285
+ {},
39286
+ "native_session_target_changed"
39287
+ );
39288
+ }
39289
+ if (source.lastTerminalCommandId !== command.throughCommandId) {
39290
+ throw new AcpExecutionError(
39291
+ "The selected Turn is no longer the source conversation head",
39292
+ {},
39293
+ "fork_point_stale"
39294
+ );
39295
+ }
39296
+ const opened2 = await this.#sessions.openNativeSession(
39297
+ { ...options, sessionId: command.targetSessionId },
39298
+ { kind: "fork", nativeSessionId: source.nativeSessionId }
39299
+ );
39300
+ signal.throwIfAborted();
39301
+ const directory = await this.#directories.list(this.#config.bindingId, command.directoryId, signal);
39302
+ const ready2 = {
39303
+ additionalDirectories: additionalDirectories.map((path2, index) => ({
39304
+ directoryId: command.additionalDirectoryIds[index] ?? command.directoryId,
39305
+ name: basename4(path2) || path2
39306
+ })),
39307
+ agentId: command.agentId,
39308
+ agentName: opened2.prepared.agentName,
39309
+ agentVersion: opened2.prepared.agentVersion,
39310
+ capabilities: opened2.prepared.capabilities,
39311
+ commands: opened2.prepared.commands,
39312
+ configOptions: opened2.prepared.configOptions,
39313
+ directoryId: command.directoryId,
39314
+ directoryLabel: directory.directoryLabel,
39315
+ kind: "session.ready",
39316
+ requestId: command.requestId,
39317
+ restored: true,
39318
+ sessionId: opened2.sessionId
39319
+ };
39320
+ this.record(command, "native_recorded_session_forked");
39321
+ return {
39322
+ action: "fork-recorded",
39323
+ kind: "native.session.result",
39324
+ ready: ready2,
39325
+ requestId: command.requestId,
39326
+ sessionId: command.sessionId,
39327
+ targetSessionId: command.targetSessionId,
39328
+ title: source.title || "Untitled session"
39329
+ };
39330
+ }
39202
39331
  const prepared = await this.#sessions.prepareNativeSessionBrowser(options);
39203
39332
  if (!prepared.capabilities.listSessions) {
39204
39333
  throw new AcpExecutionError(
@@ -40520,7 +40649,7 @@ function createAgentSettingsDiscoveryHandler(dependencies) {
40520
40649
  // src/artifacts/local-file-streamer.ts
40521
40650
  import { createReadStream as createReadStream2 } from "node:fs";
40522
40651
  import { realpath as realpath8, stat as stat7 } from "node:fs/promises";
40523
- import { basename as basename4, isAbsolute as isAbsolute10, normalize as normalize4, resolve as resolve5 } from "node:path";
40652
+ import { basename as basename5, isAbsolute as isAbsolute10, normalize as normalize4, resolve as resolve5 } from "node:path";
40524
40653
  import { fileURLToPath as fileURLToPath2 } from "node:url";
40525
40654
  var CHUNK_BYTES = 192 * 1024;
40526
40655
  function requestedPath(value) {
@@ -40571,7 +40700,7 @@ async function streamLocalFile(command, send2, signal, workingDirectory) {
40571
40700
  kind: FILE_BEGIN_KIND,
40572
40701
  mediaType: raster?.mimeType ?? "application/octet-stream",
40573
40702
  modifiedAt: before.mtime.toISOString(),
40574
- name: basename4(target) || "file",
40703
+ name: basename5(target) || "file",
40575
40704
  requestId: command.requestId,
40576
40705
  sessionId: command.sessionId
40577
40706
  });
@@ -40601,7 +40730,7 @@ async function streamLocalFile(command, send2, signal, workingDirectory) {
40601
40730
  }
40602
40731
 
40603
40732
  // src/authorization/resolve-session-directories.ts
40604
- import { basename as basename5 } from "node:path";
40733
+ import { basename as basename6 } from "node:path";
40605
40734
  var ResolvedSessionDirectories = class {
40606
40735
  additionalDirectories;
40607
40736
  additionalDirectoryEntries;
@@ -40626,7 +40755,7 @@ async function resolveSessionDirectories(directories, bindingId, directoryId2, a
40626
40755
  additionalDirectories.push(directory);
40627
40756
  additionalDirectoryEntries.push({
40628
40757
  directoryId: additionalDirectoryId,
40629
- name: basename5(directory)
40758
+ name: basename6(directory)
40630
40759
  });
40631
40760
  }
40632
40761
  return new ResolvedSessionDirectories(cwd, additionalDirectories, additionalDirectoryEntries);
@@ -40841,6 +40970,7 @@ function paginateActiveTurn(history, activeTurn, sessionId, endIndex, limit) {
40841
40970
  historicalCharacterLimit
40842
40971
  ) : null;
40843
40972
  return {
40973
+ streamPosition: { commandId: activeTurn.commandId, epoch: activeTurn.epoch, sequence: activeTurn.sequence },
40844
40974
  coveredCommandIds: historical?.coveredCommandIds ?? [],
40845
40975
  coveredMessageIds: [
40846
40976
  ...historical?.coveredMessageIds ?? [],
@@ -40873,6 +41003,7 @@ function mergeLiveSessionHistory(history, activeTurn, sessionId) {
40873
41003
  }
40874
41004
  return {
40875
41005
  coveredCommandIds: page.coveredCommandIds,
41006
+ ...page.streamPosition === void 0 ? {} : { streamPosition: page.streamPosition },
40876
41007
  coveredMessageIds: page.coveredMessageIds,
40877
41008
  messages: page.messages,
40878
41009
  status: "available",
@@ -41363,14 +41494,15 @@ async function executePrompt({
41363
41494
  const appliedSettings = command.sessionConfigurations === void 0 ? void 0 : agentForSessionConfiguration(agent, command.sessionConfigurations);
41364
41495
  const executionAgent = appliedSettings?.agent ?? agent;
41365
41496
  const sessionConfigurations = appliedSettings?.sessionConfigurations;
41497
+ const preparation = {
41498
+ additionalDirectories: resolved.additionalDirectories,
41499
+ agent: executionAgent,
41500
+ cwd: resolved.cwd,
41501
+ sessionId: command.sessionId,
41502
+ signal
41503
+ };
41504
+ let prepared = await sessions.prepareExecutionSession(preparation);
41366
41505
  if (command.sessionConfigurations !== void 0) {
41367
- const prepared = await sessions.prepareExecutionSession({
41368
- additionalDirectories: resolved.additionalDirectories,
41369
- agent: executionAgent,
41370
- cwd: resolved.cwd,
41371
- sessionId: command.sessionId,
41372
- signal
41373
- });
41374
41506
  if (availability.disposition === SessionPromptDisposition.Steer) {
41375
41507
  assertAppliedSessionConfiguration(prepared.configOptions, sessionConfigurations ?? []);
41376
41508
  } else {
@@ -41386,6 +41518,7 @@ async function executePrompt({
41386
41518
  command.sessionId,
41387
41519
  signal
41388
41520
  );
41521
+ prepared = await sessions.prepareExecutionSession(preparation);
41389
41522
  }
41390
41523
  }
41391
41524
  audit.record({
@@ -41404,6 +41537,24 @@ async function executePrompt({
41404
41537
  }
41405
41538
  }
41406
41539
  const stream = activateAttempt();
41540
+ if (!prepared.prompted) {
41541
+ const listing = await directories.list(config2.bindingId, command.directoryId, signal);
41542
+ publisher.publish(command.sessionId, {
41543
+ additionalDirectories: resolved.additionalDirectoryEntries,
41544
+ agentId: command.agentId,
41545
+ agentName: prepared.agentName,
41546
+ agentVersion: prepared.agentVersion,
41547
+ capabilities: prepared.capabilities,
41548
+ commands: prepared.commands,
41549
+ configOptions: prepared.configOptions,
41550
+ directoryId: command.directoryId,
41551
+ directoryLabel: listing.directoryLabel,
41552
+ kind: SESSION_READY_KIND,
41553
+ requestId: command.commandId,
41554
+ restored: prepared.restored,
41555
+ sessionId: command.sessionId
41556
+ });
41557
+ }
41407
41558
  publisher.publish(command.sessionId, {
41408
41559
  commandId: command.commandId,
41409
41560
  epoch: stream.epoch,
@@ -41657,7 +41808,7 @@ async function executeSessionConfigure(publisher, socket, command, config2, dire
41657
41808
  // src/native-sessions/handle-native-requests.ts
41658
41809
  import { WebSocket as WebSocket5 } from "undici";
41659
41810
  function createNativeSessionRequestHandler(dependencies) {
41660
- const { audit, diagnostics, nativeSessions, signal, socket, timer } = dependencies;
41811
+ const { audit, diagnostics, nativeSessions, publisher, signal, socket, timer } = dependencies;
41661
41812
  const pending = /* @__PURE__ */ new Map();
41662
41813
  const cancel = (command) => {
41663
41814
  const request = pending.get(command.requestId);
@@ -41709,6 +41860,17 @@ function createNativeSessionRequestHandler(dependencies) {
41709
41860
  }
41710
41861
  operationSignal.throwIfAborted();
41711
41862
  const result = await nativeSessions.execute(command, operationSignal);
41863
+ if (command.action === "fork-recorded" && result.action === "fork-recorded") {
41864
+ publisher.publishBatch(result.ready.sessionId, [
41865
+ result.ready,
41866
+ {
41867
+ kind: "session.forked",
41868
+ sessionId: result.ready.sessionId,
41869
+ sourceSessionId: command.sessionId,
41870
+ throughCommandId: command.throughCommandId
41871
+ }
41872
+ ]);
41873
+ }
41712
41874
  if (socket.readyState === WebSocket5.OPEN) {
41713
41875
  send(socket, result);
41714
41876
  }
@@ -41794,6 +41956,7 @@ function createDaemonCommandHandler({
41794
41956
  audit,
41795
41957
  diagnostics,
41796
41958
  nativeSessions,
41959
+ publisher,
41797
41960
  signal,
41798
41961
  socket,
41799
41962
  timer
@@ -42566,6 +42729,16 @@ var SessionEventOutbox = class {
42566
42729
  this.#database.close();
42567
42730
  };
42568
42731
  enqueue = (sessionId, payload, critical) => {
42732
+ const envelope2 = this.enqueueBatch(sessionId, [payload], critical)[0];
42733
+ if (envelope2 === void 0) {
42734
+ throw new Error("The Session event outbox did not enqueue the event");
42735
+ }
42736
+ return envelope2;
42737
+ };
42738
+ enqueueBatch = (sessionId, payloads, critical) => {
42739
+ if (payloads.length < 1 || payloads.length > 32) {
42740
+ throw new Error("A Session event batch must contain between 1 and 32 events");
42741
+ }
42569
42742
  this.#database.exec("BEGIN IMMEDIATE");
42570
42743
  try {
42571
42744
  const state = this.#database.prepare(
@@ -42574,39 +42747,52 @@ var SessionEventOutbox = class {
42574
42747
  WHERE singleton = 1`
42575
42748
  ).get();
42576
42749
  const sourceSeq = rowNumber(state, "next_source_seq");
42577
- if (sourceSeq < 1 || !Number.isSafeInteger(sourceSeq + 1)) {
42750
+ if (sourceSeq < 1 || !Number.isSafeInteger(sourceSeq + payloads.length)) {
42578
42751
  throw new Error("The Session event source sequence is exhausted");
42579
42752
  }
42580
- const envelope2 = {
42581
- delivery: {
42582
- eventId: randomUUID6(),
42583
- kind: "reliable",
42584
- sourceSeq: sourceSeq.toString(),
42585
- streamId: rowString(state, "stream_id")
42586
- },
42587
- kind: SESSION_EVENT_KIND,
42588
- payload,
42589
- sessionId
42590
- };
42591
- const encoded = encodeSessionEventEnvelope(envelope2);
42592
- const byteLength = Buffer.byteLength(encoded, "utf8");
42753
+ const streamId = rowString(state, "stream_id");
42754
+ const stored = payloads.map((payload, index) => {
42755
+ const envelope2 = {
42756
+ delivery: {
42757
+ eventId: randomUUID6(),
42758
+ kind: "reliable",
42759
+ sourceSeq: (sourceSeq + index).toString(),
42760
+ streamId
42761
+ },
42762
+ kind: SESSION_EVENT_KIND,
42763
+ payload,
42764
+ sessionId
42765
+ };
42766
+ const encoded = encodeSessionEventEnvelope(envelope2);
42767
+ return { byteLength: Buffer.byteLength(encoded, "utf8"), encoded, envelope: envelope2 };
42768
+ });
42769
+ const byteLength = stored.reduce((total, entry) => total + entry.byteLength, 0);
42593
42770
  const maximumBytes = critical ? this.#limits.criticalEventBytes : this.#limits.standardEventBytes;
42594
42771
  if (rowNumber(state, "total_bytes") + byteLength > maximumBytes) {
42595
42772
  throw new SessionEventOutboxCapacityError();
42596
42773
  }
42597
- this.#database.prepare(
42774
+ const insert = this.#database.prepare(
42598
42775
  `INSERT INTO relay_session_event_outbox (
42599
- event_id, session_id, source_seq, byte_length, envelope_json
42600
- ) VALUES (?, ?, ?, ?, ?)`
42601
- ).run(envelope2.delivery.eventId, sessionId, sourceSeq, byteLength, encoded);
42776
+ event_id, session_id, source_seq, byte_length, envelope_json
42777
+ ) VALUES (?, ?, ?, ?, ?)`
42778
+ );
42779
+ for (const entry of stored) {
42780
+ insert.run(
42781
+ entry.envelope.delivery.eventId,
42782
+ sessionId,
42783
+ Number(entry.envelope.delivery.sourceSeq),
42784
+ entry.byteLength,
42785
+ entry.encoded
42786
+ );
42787
+ }
42602
42788
  this.#database.prepare(
42603
42789
  `UPDATE relay_session_event_outbox_state
42604
- SET next_source_seq = next_source_seq + 1,
42790
+ SET next_source_seq = next_source_seq + ?,
42605
42791
  total_bytes = total_bytes + ?
42606
42792
  WHERE singleton = 1`
42607
- ).run(byteLength);
42793
+ ).run(stored.length, byteLength);
42608
42794
  this.#database.exec("COMMIT");
42609
- return envelope2;
42795
+ return stored.map((entry) => entry.envelope);
42610
42796
  } catch (error62) {
42611
42797
  this.#database.exec("ROLLBACK");
42612
42798
  throw error62;
@@ -42707,7 +42893,7 @@ import { WebSocket as WebSocket9 } from "undici";
42707
42893
  var SESSION_EVENT_REPLAY_WINDOW = 16;
42708
42894
  var SESSION_EVENT_REPLAY_BYTE_LIMIT = 32 * 1024 * 1024;
42709
42895
  function reservesSessionEventCapacity(event) {
42710
- if (event.kind === SESSION_COMPLETED_KIND || event.kind === SESSION_FAILED_KIND) {
42896
+ if (event.kind === SESSION_COMPLETED_KIND || event.kind === SESSION_FAILED_KIND || event.kind === SESSION_FORKED_KIND || event.kind === SESSION_READY_KIND) {
42711
42897
  return true;
42712
42898
  }
42713
42899
  return event.kind === AGENT_ACTIVITY_KIND && (event.activityType === "progress" || event.activityType === "reasoning") && (event.status === "completed" || event.status === "failed");
@@ -42780,6 +42966,11 @@ var DaemonSessionEventPublisher = class {
42780
42966
  }
42781
42967
  this.#publishNextBatch();
42782
42968
  };
42969
+ publishBatch = (sessionId, events) => {
42970
+ const critical = events.some(reservesSessionEventCapacity);
42971
+ this.#outbox.enqueueBatch(sessionId, events.map(encodeRecordedSessionEvent), critical);
42972
+ this.#publishNextBatch();
42973
+ };
42783
42974
  quarantine = (rejection) => {
42784
42975
  if (!this.#outbox.quarantine(rejection)) {
42785
42976
  return;
@@ -43128,7 +43319,7 @@ async function runDaemon(config2, audit, signal, timer = systemDaemonTimer, opti
43128
43319
  // src/pairing/pair-local-machine.ts
43129
43320
  import { mkdir as mkdir5, realpath as realpath9, stat as stat8 } from "node:fs/promises";
43130
43321
  import { hostname as hostname3 } from "node:os";
43131
- import { basename as basename6, resolve as resolve7 } from "node:path";
43322
+ import { basename as basename7, resolve as resolve7 } from "node:path";
43132
43323
  import { fetch as fetch4 } from "undici";
43133
43324
 
43134
43325
  // src/storage/runtime-installation-store.ts
@@ -43770,7 +43961,7 @@ async function claimPairing(options, defaultWorkspace, localAgents, installableA
43770
43961
  installableAgents,
43771
43962
  machineName: hostname3(),
43772
43963
  pairingCode: options.code,
43773
- workspaceName: basename6(defaultWorkspace) || "Local workspace"
43964
+ workspaceName: basename7(defaultWorkspace) || "Local workspace"
43774
43965
  }),
43775
43966
  dispatcher: environmentProxyDispatcher,
43776
43967
  headers: { "content-type": "application/json" },