@moxt-ai/mobius 0.0.31 → 0.0.33

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 (47) hide show
  1. package/dist/acp/activity.d.ts +1 -1
  2. package/dist/acp/activity.d.ts.map +1 -1
  3. package/dist/acp/activity.js +8 -6
  4. package/dist/acp/activity.js.map +1 -1
  5. package/dist/acp/session-manager.d.ts +2 -0
  6. package/dist/acp/session-manager.d.ts.map +1 -1
  7. package/dist/acp/session-manager.js +23 -10
  8. package/dist/acp/session-manager.js.map +1 -1
  9. package/dist/agent-catalog/agent-discovery.d.ts.map +1 -1
  10. package/dist/agent-catalog/agent-discovery.js +4 -0
  11. package/dist/agent-catalog/agent-discovery.js.map +1 -1
  12. package/dist/agent-catalog/local-agent.d.ts.map +1 -1
  13. package/dist/agent-catalog/local-agent.js +1 -0
  14. package/dist/agent-catalog/local-agent.js.map +1 -1
  15. package/dist/agent-installation/agent-installation-manager.d.ts.map +1 -1
  16. package/dist/agent-installation/agent-installation-manager.js +3 -0
  17. package/dist/agent-installation/agent-installation-manager.js.map +1 -1
  18. package/dist/authorization/local-raster.d.ts +1 -0
  19. package/dist/authorization/local-raster.d.ts.map +1 -1
  20. package/dist/authorization/local-raster.js +17 -0
  21. package/dist/authorization/local-raster.js.map +1 -1
  22. package/dist/bots/bot-execution-context.js +1 -1
  23. package/dist/bots/bot-execution-context.js.map +1 -1
  24. package/dist/cli.js +132 -329
  25. package/dist/cli.js.map +4 -4
  26. package/dist/config.d.ts.map +1 -1
  27. package/dist/config.js +3 -10
  28. package/dist/config.js.map +1 -1
  29. package/dist/index.js +133 -339
  30. package/dist/index.js.map +4 -4
  31. package/dist/native-sessions/service.d.ts.map +1 -1
  32. package/dist/native-sessions/service.js +1 -30
  33. package/dist/native-sessions/service.js.map +1 -1
  34. package/dist/relay-connection/session-event-outbox.d.ts +0 -2
  35. package/dist/relay-connection/session-event-outbox.d.ts.map +1 -1
  36. package/dist/relay-connection/session-event-outbox.js +6 -12
  37. package/dist/relay-connection/session-event-outbox.js.map +1 -1
  38. package/dist/run-daemon.d.ts.map +1 -1
  39. package/dist/run-daemon.js +47 -5
  40. package/dist/run-daemon.js.map +1 -1
  41. package/dist/runtime.js +131 -328
  42. package/dist/runtime.js.map +4 -4
  43. package/package.json +1 -1
  44. package/dist/native-sessions/codex-history.d.ts +0 -11
  45. package/dist/native-sessions/codex-history.d.ts.map +0 -1
  46. package/dist/native-sessions/codex-history.js +0 -233
  47. package/dist/native-sessions/codex-history.js.map +0 -1
package/dist/cli.js CHANGED
@@ -11,7 +11,7 @@ import { mkdir as mkdir5 } from "node:fs/promises";
11
11
  // package.json
12
12
  var package_default = {
13
13
  name: "@moxt-ai/mobius",
14
- version: "0.0.31",
14
+ version: "0.0.33",
15
15
  description: "Mobius CLI for pairing and running local AI agent services.",
16
16
  type: "module",
17
17
  bin: {
@@ -600,6 +600,7 @@ var InstallableAgentDefinition = class {
600
600
  };
601
601
  var MissingAgentDefinition = class extends InstallableAgentDefinition {
602
602
  status = "agent_not_installed";
603
+ // biome-ignore lint/complexity/noUselessConstructor: Exposes the protected base constructor publicly.
603
604
  constructor(id, label) {
604
605
  super(id, label);
605
606
  }
@@ -694,6 +695,7 @@ var MissingAdapter = class extends UnavailableInstalledAgent {
694
695
  code = "adapter_not_found";
695
696
  message = "ACP adapter not found";
696
697
  status = "missing_adapter";
698
+ // biome-ignore lint/complexity/noUselessConstructor: Exposes the protected base constructor publicly.
697
699
  constructor(specification, agent) {
698
700
  super(specification, agent);
699
701
  }
@@ -702,6 +704,7 @@ var MissingAgent = class extends UnavailableAgent {
702
704
  code = "agent_not_found";
703
705
  message = "Agent executable not found";
704
706
  status = "missing_agent";
707
+ // biome-ignore lint/complexity/noUselessConstructor: Exposes the protected base constructor publicly.
705
708
  constructor(specification) {
706
709
  super(specification);
707
710
  }
@@ -730,6 +733,7 @@ var IncompatibleAdapter = class extends UnavailableInstalledAgent {
730
733
  code = "acp_incompatible";
731
734
  message = "ACP adapter is incompatible";
732
735
  status = "incompatible_adapter";
736
+ // biome-ignore lint/complexity/noUselessConstructor: Exposes the protected base constructor publicly.
733
737
  constructor(specification, agent) {
734
738
  super(specification, agent);
735
739
  }
@@ -738,6 +742,7 @@ var AuthenticationRequiredAgent = class extends UnavailableInstalledAgent {
738
742
  code = "authentication_required";
739
743
  message = "Agent authentication is required";
740
744
  status = "authentication_required";
745
+ // biome-ignore lint/complexity/noUselessConstructor: Exposes the protected base constructor publicly.
741
746
  constructor(specification, agent) {
742
747
  super(specification, agent);
743
748
  }
@@ -23367,6 +23372,7 @@ var decodeNativeSessionTurnForkCommand = (encoded) => decode4(nativeSessionTurnF
23367
23372
  var SESSION_EVENT_KIND = "session.event";
23368
23373
  var SESSION_EVENT_ACK_KIND = "session.event.ack";
23369
23374
  var SESSION_EVENT_COMMITTED_KIND = "session.event.committed";
23375
+ var SESSION_EVENT_DEFERRED_KIND = "session.event.deferred";
23370
23376
  var SESSION_EVENT_REJECTED_KIND = "session.event.rejected";
23371
23377
  var SessionEventRejectionCode = {
23372
23378
  SessionDeleted: "session_deleted",
@@ -23413,6 +23419,12 @@ var eventAcknowledgementSchema = external_exports.strictObject({
23413
23419
  sequence: external_exports.string().min(1).max(40).regex(DECIMAL_SEQUENCE_PATTERN),
23414
23420
  sessionId: external_exports.string().min(1).max(128).regex(IDENTIFIER_PATTERN4)
23415
23421
  }).readonly();
23422
+ var eventDeferredSchema = external_exports.strictObject({
23423
+ eventId: external_exports.string().min(1).max(128).regex(IDENTIFIER_PATTERN4),
23424
+ kind: external_exports.literal(SESSION_EVENT_DEFERRED_KIND),
23425
+ retryAfterMilliseconds: external_exports.number().int().min(100).max(6e4),
23426
+ sessionId: external_exports.string().min(1).max(128).regex(IDENTIFIER_PATTERN4)
23427
+ }).readonly();
23416
23428
  var eventRejectionSchema = external_exports.strictObject({
23417
23429
  code: external_exports.enum(SessionEventRejectionCode),
23418
23430
  eventId: external_exports.string().min(1).max(128).regex(IDENTIFIER_PATTERN4),
@@ -23446,6 +23458,7 @@ var encode4 = (message, schema) => {
23446
23458
  var decodeSessionEventEnvelope = (encoded) => decode5(encoded, eventEnvelopeSchema);
23447
23459
  var encodeSessionEventEnvelope = (message) => encode4(message, eventEnvelopeSchema);
23448
23460
  var decodeSessionEventAcknowledgement = (encoded) => decode5(encoded, eventAcknowledgementSchema);
23461
+ var decodeSessionEventDeferred = (encoded) => decode5(encoded, eventDeferredSchema);
23449
23462
  var decodeSessionEventRejection = (encoded) => decode5(encoded, eventRejectionSchema);
23450
23463
 
23451
23464
  // src/pairing/pair-local-machine.ts
@@ -24614,6 +24627,23 @@ function sniffRasterMime(bytes) {
24614
24627
  }
24615
24628
  return null;
24616
24629
  }
24630
+ function readInlineRaster(data, name = "Image") {
24631
+ if (data.length === 0 || data.length > Math.ceil(MAX_LOCAL_RASTER_BYTES / 3) * 4 || data.length % 4 !== 0) {
24632
+ return null;
24633
+ }
24634
+ if (!/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(data)) {
24635
+ return null;
24636
+ }
24637
+ const bytes = new Uint8Array(Buffer.from(data, "base64"));
24638
+ if (bytes.byteLength < 1 || bytes.byteLength > MAX_LOCAL_RASTER_BYTES) {
24639
+ return null;
24640
+ }
24641
+ const mimeType = sniffRasterMime(bytes);
24642
+ if (mimeType === null) {
24643
+ return null;
24644
+ }
24645
+ return new LocalRasterImage(basename3(name) || "Image", mimeType, bytes);
24646
+ }
24617
24647
  function isInsideRoot(root, target) {
24618
24648
  const relation = relative5(root, target);
24619
24649
  return relation !== ".." && !relation.startsWith(`..${sep4}`) && !isAbsolute9(relation);
@@ -24978,7 +25008,7 @@ function normalizeContentBlock(content) {
24978
25008
  mimeType: content.mimeType
24979
25009
  };
24980
25010
  }
24981
- function normalizeToolContent(content) {
25011
+ async function normalizeToolContent(content, prepareContent) {
24982
25012
  const normalized = [];
24983
25013
  for (const item of content) {
24984
25014
  if (item.type === "diff") {
@@ -24997,7 +25027,7 @@ function normalizeToolContent(content) {
24997
25027
  });
24998
25028
  continue;
24999
25029
  }
25000
- normalized.push(normalizeContentBlock(item.content));
25030
+ normalized.push(await prepareContent(normalizeContentBlock(item.content)));
25001
25031
  }
25002
25032
  return normalized;
25003
25033
  }
@@ -25071,10 +25101,12 @@ var AcpActivityTracker = class {
25071
25101
  #activities = /* @__PURE__ */ new Map();
25072
25102
  #identities = /* @__PURE__ */ new Map();
25073
25103
  #onActivity;
25104
+ #prepareContent;
25074
25105
  #activeNarrativeKey = "";
25075
25106
  #nextSequence = 0;
25076
- constructor(onActivity) {
25107
+ constructor(onActivity, prepareContent = (content) => Promise.resolve(content)) {
25077
25108
  this.#onActivity = onActivity;
25109
+ this.#prepareContent = prepareContent;
25078
25110
  }
25079
25111
  recordNarrative = async (activityType, messageId, text) => {
25080
25112
  const key = `${activityType}:${messageId}`;
@@ -25162,7 +25194,7 @@ var AcpActivityTracker = class {
25162
25194
  const output2 = update.rawOutput === void 0 ? readContentOutput(update.content) : formatUnknown(update.rawOutput);
25163
25195
  const detailInput = update.rawInput === void 0 ? "" : formatUnknownDetail(update.rawInput);
25164
25196
  const detailOutput = update.rawOutput === void 0 ? readContentOutputDetail(update.content) : formatUnknownDetail(update.rawOutput);
25165
- const detailContent = normalizeToolContent(update.content ?? []);
25197
+ const detailContent = await normalizeToolContent(update.content ?? [], this.#prepareContent);
25166
25198
  await this.#record(
25167
25199
  key,
25168
25200
  new AcpActivity(
@@ -25188,10 +25220,10 @@ var AcpActivityTracker = class {
25188
25220
  const identity2 = this.#identity(key);
25189
25221
  const previousDetail = recordedDetail(previous);
25190
25222
  const output2 = update.rawOutput !== void 0 ? formatUnknown(update.rawOutput) : update.content !== void 0 && update.content !== null ? readContentOutput(update.content) : previous?.output ?? "";
25191
- const content = update.content === void 0 || update.content === null ? previous?.content ?? [] : normalizeToolContent(update.content);
25223
+ const content = update.content === void 0 || update.content === null ? previous?.content ?? [] : await normalizeToolContent(update.content, this.#prepareContent);
25192
25224
  const detailInput = update.rawInput === void 0 ? previousDetail?.input ?? previous?.input ?? "" : formatUnknownDetail(update.rawInput);
25193
25225
  const detailOutput = update.rawOutput !== void 0 ? formatUnknownDetail(update.rawOutput) : update.content !== void 0 && update.content !== null ? readContentOutputDetail(update.content) : previousDetail?.output ?? previous?.output ?? "";
25194
- const detailContent = update.content === void 0 || update.content === null ? previousDetail?.content ?? previous?.content ?? [] : normalizeToolContent(update.content);
25226
+ const detailContent = update.content === void 0 || update.content === null ? previousDetail?.content ?? previous?.content ?? [] : content;
25195
25227
  await this.#record(
25196
25228
  key,
25197
25229
  new AcpActivity(
@@ -26357,10 +26389,10 @@ var RunningAcpTurn = class extends AcpTurnState {
26357
26389
  running = true;
26358
26390
  activities;
26359
26391
  onText;
26360
- constructor(commandId, onActivity, onText) {
26392
+ constructor(commandId, onActivity, onText, prepareContent) {
26361
26393
  super();
26362
26394
  this.commandId = commandId;
26363
- this.activities = new AcpActivityTracker(onActivity);
26395
+ this.activities = new AcpActivityTracker(onActivity, prepareContent);
26364
26396
  this.onText = onText;
26365
26397
  }
26366
26398
  };
@@ -26644,18 +26676,27 @@ var AcpProcessSession = class _AcpProcessSession {
26644
26676
  await this.#turn.onText(leftover, messageId);
26645
26677
  }
26646
26678
  };
26647
- emitAgentContent = async (content, messageId) => {
26679
+ prepareAgentContent = async (content) => {
26680
+ if (content.type === "image" && content.data.length > 0) {
26681
+ const raster = readInlineRaster(content.data, content.name);
26682
+ if (raster !== null) {
26683
+ return await this.importRaster(raster, AbortSignal.timeout(2e4));
26684
+ }
26685
+ }
26648
26686
  if (content.type === "image" && content.data.length === 0 && content.uri.length > 0) {
26649
26687
  const signal = AbortSignal.timeout(2e4);
26650
26688
  const raster = await readAuthorizedRaster(content.uri, this.imageRoots(), signal);
26651
26689
  if (raster !== null) {
26652
- await this.emitRaster(raster, messageId, signal);
26653
- return;
26690
+ return await this.importRaster(raster, signal);
26654
26691
  }
26655
26692
  }
26693
+ return content;
26694
+ };
26695
+ emitAgentContent = async (content, messageId) => {
26696
+ const prepared = await this.prepareAgentContent(content);
26656
26697
  await this.#getObserver().onContent({
26657
26698
  commandId: this.#turn.commandId,
26658
- content,
26699
+ content: prepared,
26659
26700
  contentId: `content-${crypto.randomUUID()}`,
26660
26701
  kind: AGENT_CONTENT_KIND,
26661
26702
  messageId,
@@ -26663,21 +26704,25 @@ var AcpProcessSession = class _AcpProcessSession {
26663
26704
  });
26664
26705
  };
26665
26706
  emitRaster = async (raster, messageId, signal) => {
26666
- const artifactId = await this.#getObserver().importLocalImage(this.#mobiusSessionId, raster, signal);
26707
+ const content = await this.importRaster(raster, signal);
26667
26708
  await this.#getObserver().onContent({
26668
26709
  commandId: this.#turn.commandId,
26669
- content: imageDisplayContent(
26670
- raster.mimeType,
26671
- raster.name,
26672
- artifactId.length > 0 ? "" : raster.base64(),
26673
- artifactId
26674
- ),
26710
+ content,
26675
26711
  contentId: `content-${crypto.randomUUID()}`,
26676
26712
  kind: AGENT_CONTENT_KIND,
26677
26713
  messageId,
26678
26714
  sessionId: this.#mobiusSessionId
26679
26715
  });
26680
26716
  };
26717
+ importRaster = async (raster, signal) => {
26718
+ const artifactId = await this.#getObserver().importLocalImage(this.#mobiusSessionId, raster, signal);
26719
+ return imageDisplayContent(
26720
+ raster.mimeType,
26721
+ raster.name,
26722
+ artifactId.length > 0 ? "" : raster.base64(),
26723
+ artifactId
26724
+ );
26725
+ };
26681
26726
  async #initializeAgent(signal) {
26682
26727
  const initialized = await this.race(
26683
26728
  this.#connection.agent.request(
@@ -27045,7 +27090,12 @@ var AcpProcessSession = class _AcpProcessSession {
27045
27090
  )
27046
27091
  );
27047
27092
  this.#prompted = true;
27048
- const running = new RunningAcpTurn(options.commandId, options.onActivity, options.onText);
27093
+ const running = new RunningAcpTurn(
27094
+ options.commandId,
27095
+ options.onActivity,
27096
+ options.onText,
27097
+ this.prepareAgentContent
27098
+ );
27049
27099
  this.#turn = running;
27050
27100
  try {
27051
27101
  const response = await this.race(
@@ -28297,6 +28347,7 @@ var AgentInstallation = class {
28297
28347
  };
28298
28348
  var RequestedInstallation = class extends AgentInstallation {
28299
28349
  status = "requested";
28350
+ // biome-ignore lint/complexity/noUselessConstructor: Exposes the protected base constructor publicly.
28300
28351
  constructor(requestId, agentId) {
28301
28352
  super(requestId, agentId);
28302
28353
  }
@@ -28312,6 +28363,7 @@ var RunningInstallation = class extends AgentInstallation {
28312
28363
  var SucceededInstallation = class extends AgentInstallation {
28313
28364
  authenticationMayBeRequired = true;
28314
28365
  status = "succeeded";
28366
+ // biome-ignore lint/complexity/noUselessConstructor: Exposes the protected base constructor publicly.
28315
28367
  constructor(requestId, agentId) {
28316
28368
  super(requestId, agentId);
28317
28369
  }
@@ -28328,6 +28380,7 @@ var FailedInstallation = class extends AgentInstallation {
28328
28380
  };
28329
28381
  var CancelledInstallation = class extends AgentInstallation {
28330
28382
  status = "cancelled";
28383
+ // biome-ignore lint/complexity/noUselessConstructor: Exposes the protected base constructor publicly.
28331
28384
  constructor(requestId, agentId) {
28332
28385
  super(requestId, agentId);
28333
28386
  }
@@ -29236,7 +29289,7 @@ var BotExecutionContextRegistry = class {
29236
29289
  activate = (command) => {
29237
29290
  let handle = this.#handlesBySession.get(command.sessionId);
29238
29291
  if (handle === void 0) {
29239
- handle = `ctx_${randomBytes(32).toString("base64url")}`;
29292
+ handle = `ctx_${Buffer.from(randomBytes(32)).toString("base64url")}`;
29240
29293
  this.#handlesBySession.set(command.sessionId, handle);
29241
29294
  }
29242
29295
  if (this.#activeByHandle.has(handle)) {
@@ -29518,255 +29571,6 @@ var BotOutboundIpcServer = class {
29518
29571
  // src/native-sessions/service.ts
29519
29572
  import { randomUUID as randomUUID4 } from "node:crypto";
29520
29573
  import { basename as basename4 } from "node:path";
29521
-
29522
- // src/native-sessions/codex-history.ts
29523
- import { spawn as spawn4 } from "node:child_process";
29524
- var responseSchema = external_exports.union([
29525
- external_exports.object({
29526
- id: external_exports.number(),
29527
- error: external_exports.object({ code: external_exports.number(), message: external_exports.string() })
29528
- }),
29529
- external_exports.object({ id: external_exports.number(), result: external_exports.unknown() }),
29530
- external_exports.object({ method: external_exports.string() })
29531
- ]);
29532
- var threadSchema = external_exports.object({
29533
- thread: external_exports.object({
29534
- id: nativeSessionIdSchema,
29535
- cwd: external_exports.string().min(1).max(2048).refine((path2) => !path2.includes("\0"))
29536
- })
29537
- });
29538
- var turnsSchema = external_exports.object({
29539
- data: external_exports.array(external_exports.object({ items: external_exports.array(external_exports.unknown()).max(1e5) })).max(SESSION_HISTORY_PREVIEW_MESSAGE_LIMIT),
29540
- nextCursor: external_exports.string().nullish()
29541
- });
29542
- var itemTypeSchema = external_exports.object({ type: external_exports.string().min(1).max(80) });
29543
- var userMessageSchema = external_exports.object({
29544
- content: external_exports.array(external_exports.unknown()).max(1e4)
29545
- });
29546
- var textSchema = external_exports.object({ text: external_exports.string() });
29547
- var imageSchema = external_exports.object({ url: external_exports.string() });
29548
- var agentMessageSchema = textSchema.extend({ phase: external_exports.string().nullish() });
29549
- function decodeHistory(thread, value) {
29550
- const page = turnsSchema.parse(value);
29551
- const messages = [];
29552
- let characters = 0;
29553
- let truncated = page.nextCursor != null;
29554
- for (const turn of page.data.toReversed()) {
29555
- for (const item of turn.items) {
29556
- const { type } = itemTypeSchema.parse(item);
29557
- let message;
29558
- if (type === "userMessage") {
29559
- const { content } = userMessageSchema.parse(item);
29560
- const text2 = content.map((block) => {
29561
- const { type: type2 } = itemTypeSchema.parse(block);
29562
- if (type2 === "text") {
29563
- return textSchema.parse(block).text;
29564
- }
29565
- if (type2 === "image") {
29566
- return `[@image](${imageSchema.parse(block).url})`;
29567
- }
29568
- return "[Attachment]";
29569
- }).join("");
29570
- message = {
29571
- role: "user",
29572
- text: text2
29573
- };
29574
- } else if (type === "agentMessage") {
29575
- const agent = agentMessageSchema.parse(item);
29576
- if (agent.phase === "commentary") {
29577
- continue;
29578
- }
29579
- message = { role: "assistant", text: agent.text };
29580
- } else {
29581
- continue;
29582
- }
29583
- const text = message.text.slice(-SESSION_HISTORY_CHARACTER_LIMIT);
29584
- if (text.length === 0 && (message.images?.length ?? 0) === 0) {
29585
- continue;
29586
- }
29587
- truncated ||= text.length < message.text.length;
29588
- messages.push({ ...message, text });
29589
- characters += text.length;
29590
- while (messages.length > SESSION_HISTORY_PREVIEW_MESSAGE_LIMIT || characters > SESSION_HISTORY_CHARACTER_LIMIT) {
29591
- const removed = messages.shift();
29592
- if (removed !== void 0) {
29593
- characters -= removed.text.length;
29594
- }
29595
- truncated = true;
29596
- }
29597
- }
29598
- }
29599
- return {
29600
- nativeSessionId: thread.id,
29601
- cwd: thread.cwd,
29602
- history: {
29603
- status: "available",
29604
- messages,
29605
- truncated,
29606
- coveredCommandIds: [],
29607
- coveredMessageIds: []
29608
- }
29609
- };
29610
- }
29611
- async function readCodexHistory(agent, cwd, nativeSessionId, signal) {
29612
- signal.throwIfAborted();
29613
- nativeSessionIdSchema.parse(nativeSessionId);
29614
- if (agent.id !== "codex" || !await revalidateExecutable(agent.agentIdentity)) {
29615
- throw new AcpExecutionError(
29616
- "The local Codex executable changed. Restart Mobius to discover it again.",
29617
- {},
29618
- "agent_executable_changed"
29619
- );
29620
- }
29621
- signal.throwIfAborted();
29622
- const child = spawn4(agent.agentIdentity.realPath, ["app-server"], {
29623
- cwd,
29624
- env: { ...process.env, ...agent.environment },
29625
- detached: process.platform !== "win32",
29626
- shell: false,
29627
- stdio: ["pipe", "pipe", "ignore"]
29628
- });
29629
- const response = Promise.withResolvers();
29630
- let state = { kind: "initializing", requestId: 1 };
29631
- let pending = "";
29632
- let receivedBytes = 0;
29633
- const fail = (cause) => response.reject(
29634
- cause instanceof AcpExecutionError ? cause : new AcpExecutionError(
29635
- "Saved Codex history could not be read.",
29636
- { cause },
29637
- "native_history_unavailable"
29638
- )
29639
- );
29640
- const send2 = (message) => {
29641
- child.stdin.write(`${JSON.stringify(message)}
29642
- `);
29643
- };
29644
- const onData = (chunk) => {
29645
- try {
29646
- receivedBytes += Buffer.byteLength(chunk);
29647
- if (receivedBytes > 32 * 1024 * 1024) {
29648
- throw new AcpExecutionError(
29649
- "This saved conversation is too large to preview.",
29650
- {},
29651
- "native_history_too_large"
29652
- );
29653
- }
29654
- pending += chunk;
29655
- let newline = pending.indexOf("\n");
29656
- while (newline >= 0) {
29657
- const line = pending.slice(0, newline);
29658
- pending = pending.slice(newline + 1);
29659
- newline = pending.indexOf("\n");
29660
- if (line.trim().length === 0) {
29661
- continue;
29662
- }
29663
- const value = JSON.parse(line);
29664
- const message = responseSchema.parse(value);
29665
- if (!("id" in message)) {
29666
- continue;
29667
- }
29668
- if (message.id !== state.requestId) {
29669
- throw new AcpExecutionError(
29670
- "Codex returned an invalid history response.",
29671
- {},
29672
- "invalid_native_session_response"
29673
- );
29674
- }
29675
- if ("error" in message) {
29676
- fail(
29677
- new AcpExecutionError(
29678
- "Saved Codex history could not be read.",
29679
- { cause: message.error },
29680
- "native_history_unavailable"
29681
- )
29682
- );
29683
- return;
29684
- }
29685
- switch (state.kind) {
29686
- case "initializing":
29687
- state = { kind: "metadata", requestId: 2 };
29688
- send2({ method: "initialized", params: {} });
29689
- send2({
29690
- id: state.requestId,
29691
- method: "thread/read",
29692
- params: { threadId: nativeSessionId, includeTurns: false }
29693
- });
29694
- break;
29695
- case "metadata": {
29696
- const { thread } = threadSchema.parse(message.result);
29697
- state = { kind: "turns", requestId: 3, thread };
29698
- send2({
29699
- id: state.requestId,
29700
- method: "thread/turns/list",
29701
- params: {
29702
- threadId: nativeSessionId,
29703
- limit: SESSION_HISTORY_PREVIEW_MESSAGE_LIMIT,
29704
- sortDirection: "desc",
29705
- itemsView: "summary"
29706
- }
29707
- });
29708
- break;
29709
- }
29710
- case "turns":
29711
- response.resolve(decodeHistory(state.thread, message.result));
29712
- return;
29713
- default: {
29714
- const unhandled = state;
29715
- throw new Error(`Unknown history read state: ${String(unhandled)}`);
29716
- }
29717
- }
29718
- }
29719
- } catch (cause) {
29720
- fail(cause);
29721
- }
29722
- };
29723
- const abort = () => response.reject(signal.reason);
29724
- const onExit = () => fail(
29725
- new AcpExecutionError(
29726
- "Codex stopped before its saved history was available.",
29727
- {},
29728
- "native_history_unavailable"
29729
- )
29730
- );
29731
- const timeout = setTimeout(
29732
- () => fail(new AcpExecutionError("Reading saved Codex history timed out.", {}, "native_history_timeout")),
29733
- 15e3
29734
- );
29735
- child.stdout.setEncoding("utf8");
29736
- child.stdout.on("data", onData);
29737
- child.stdin.on("error", fail);
29738
- child.on("error", fail);
29739
- child.on("exit", onExit);
29740
- signal.addEventListener("abort", abort, { once: true });
29741
- try {
29742
- if (signal.aborted) {
29743
- abort();
29744
- } else {
29745
- send2({
29746
- id: 1,
29747
- method: "initialize",
29748
- params: { clientInfo: { name: "mobius_history", version: "1.0.0" } }
29749
- });
29750
- }
29751
- const snapshot = await response.promise;
29752
- return {
29753
- ...snapshot,
29754
- history: await embedLocalHistoryImages(snapshot.history, [cwd, snapshot.cwd], signal)
29755
- };
29756
- } finally {
29757
- clearTimeout(timeout);
29758
- signal.removeEventListener("abort", abort);
29759
- child.stdout.removeListener("data", onData);
29760
- if (child.pid !== void 0) {
29761
- await stopProcessTree(child);
29762
- }
29763
- child.stdin.removeListener("error", fail);
29764
- child.removeListener("error", fail);
29765
- child.removeListener("exit", onExit);
29766
- }
29767
- }
29768
-
29769
- // src/native-sessions/service.ts
29770
29574
  var NativeSessionService = class {
29771
29575
  #entries = /* @__PURE__ */ new Map();
29772
29576
  #cursors = /* @__PURE__ */ new Map();
@@ -29929,7 +29733,7 @@ var NativeSessionService = class {
29929
29733
  "native_session_unsupported"
29930
29734
  );
29931
29735
  }
29932
- const opening = this.#sessions.openNativeSession(
29736
+ const opened = await this.#sessions.openNativeSession(
29933
29737
  {
29934
29738
  ...options,
29935
29739
  cwd: target.cwd,
@@ -29938,35 +29742,6 @@ var NativeSessionService = class {
29938
29742
  },
29939
29743
  { kind: command.action, nativeSessionId: target.info.sessionId }
29940
29744
  );
29941
- const opened = await opening.catch(async (cause) => {
29942
- signal.throwIfAborted();
29943
- if (command.action !== "import" || options.agent.id !== "codex" || !(cause instanceof AcpExecutionError) || cause.code !== "acp_execution_failed") {
29944
- throw cause;
29945
- }
29946
- const snapshot = await readCodexHistory(options.agent, target.cwd, target.info.sessionId, signal);
29947
- const resolved = await this.#directories.identify(command.bindingId, snapshot.cwd, signal);
29948
- if (snapshot.nativeSessionId !== target.info.sessionId || resolved.path !== target.cwd) {
29949
- throw new AcpExecutionError(
29950
- "Codex returned history for a different session or workspace.",
29951
- { cause },
29952
- "invalid_native_session_response"
29953
- );
29954
- }
29955
- signal.throwIfAborted();
29956
- this.record(command, "native_session_previewed");
29957
- return { kind: "preview", history: snapshot.history };
29958
- });
29959
- if ("kind" in opened) {
29960
- return {
29961
- ...envelope2,
29962
- action: "preview",
29963
- entryId: command.entryId,
29964
- reason: "continuation_unavailable",
29965
- targetSessionId: command.targetSessionId,
29966
- title: target.info.title ?? "Untitled session",
29967
- history: opened.history
29968
- };
29969
- }
29970
29745
  signal.throwIfAborted();
29971
29746
  const ready = {
29972
29747
  additionalDirectories: target.additionalEntries,
@@ -30702,11 +30477,9 @@ import { dirname as dirname8 } from "node:path";
30702
30477
  import { DatabaseSync as DatabaseSync4 } from "node:sqlite";
30703
30478
  var DEFAULT_OUTBOX_LIMITS = {
30704
30479
  criticalEventBytes: 136 * 1024 * 1024,
30705
- criticalEventCount: 10128,
30706
30480
  runtimeDeliveryBytes: 64 * 1024 * 1024,
30707
30481
  runtimeDeliveryCount: 64,
30708
- standardEventBytes: 128 * 1024 * 1024,
30709
- standardEventCount: 1e4
30482
+ standardEventBytes: 128 * 1024 * 1024
30710
30483
  };
30711
30484
  var SessionEventOutboxCapacityError = class extends Error {
30712
30485
  code = "session_event_outbox_full";
@@ -30989,21 +30762,9 @@ var SessionEventOutbox = class {
30989
30762
  this.#database.close();
30990
30763
  };
30991
30764
  enqueue = (sessionId, payload, attemptId = null) => {
30992
- return this.#enqueueBounded(
30993
- sessionId,
30994
- payload,
30995
- attemptId ?? "",
30996
- this.#limits.standardEventCount,
30997
- this.#limits.standardEventBytes
30998
- );
30765
+ return this.#enqueueBounded(sessionId, payload, attemptId ?? "", this.#limits.standardEventBytes);
30999
30766
  };
31000
- enqueueCritical = (sessionId, payload, attemptId = "") => this.#enqueueBounded(
31001
- sessionId,
31002
- payload,
31003
- attemptId,
31004
- this.#limits.criticalEventCount,
31005
- this.#limits.criticalEventBytes
31006
- );
30767
+ enqueueCritical = (sessionId, payload, attemptId = "") => this.#enqueueBounded(sessionId, payload, attemptId, this.#limits.criticalEventBytes);
31007
30768
  claimRuntimeDelivery = (delivery) => {
31008
30769
  const payloadBytes = new TextEncoder().encode(delivery.payload).byteLength;
31009
30770
  this.#database.exec("BEGIN IMMEDIATE");
@@ -31110,7 +30871,7 @@ var SessionEventOutbox = class {
31110
30871
  true
31111
30872
  )
31112
30873
  );
31113
- #enqueueBounded = (sessionId, payload, attemptId, maximumEventCount, maximumEventBytes) => {
30874
+ #enqueueBounded = (sessionId, payload, attemptId, maximumEventBytes) => {
31114
30875
  const sourceKey = attemptId.length === 0 ? `runtime:${sessionId}` : `attempt:${sessionId}:${attemptId}`;
31115
30876
  this.#database.exec("BEGIN IMMEDIATE");
31116
30877
  try {
@@ -31137,11 +30898,11 @@ var SessionEventOutbox = class {
31137
30898
  const encoded = encodeSessionEventEnvelope(envelope2);
31138
30899
  const byteLength = new TextEncoder().encode(encoded).byteLength;
31139
30900
  const state = this.#database.prepare(
31140
- `SELECT event_count, total_bytes
30901
+ `SELECT total_bytes
31141
30902
  FROM relay_session_event_outbox_state
31142
30903
  WHERE singleton = 1`
31143
30904
  ).get();
31144
- if (rowNumber(state, "event_count") + 1 > maximumEventCount || rowNumber(state, "total_bytes") + byteLength > maximumEventBytes) {
30905
+ if (rowNumber(state, "total_bytes") + byteLength > maximumEventBytes) {
31145
30906
  throw new SessionEventOutboxCapacityError();
31146
30907
  }
31147
30908
  this.#database.prepare(
@@ -31275,16 +31036,14 @@ var SessionEventOutbox = class {
31275
31036
  function validateLimits(limits) {
31276
31037
  const values = [
31277
31038
  limits.criticalEventBytes,
31278
- limits.criticalEventCount,
31279
31039
  limits.runtimeDeliveryBytes,
31280
31040
  limits.runtimeDeliveryCount,
31281
- limits.standardEventBytes,
31282
- limits.standardEventCount
31041
+ limits.standardEventBytes
31283
31042
  ];
31284
31043
  if (values.some((value) => !Number.isSafeInteger(value) || value < 1)) {
31285
31044
  throw new Error("Session event outbox limits must be positive integers");
31286
31045
  }
31287
- if (limits.criticalEventBytes < limits.standardEventBytes || limits.criticalEventCount < limits.standardEventCount) {
31046
+ if (limits.criticalEventBytes < limits.standardEventBytes) {
31288
31047
  throw new Error("Critical Session event capacity must include the standard capacity");
31289
31048
  }
31290
31049
  }
@@ -31634,10 +31393,13 @@ function sessionEventSourceKey(envelope2) {
31634
31393
  var DaemonSessionEventPublisher = class {
31635
31394
  #outbox;
31636
31395
  #inFlightEvents = /* @__PURE__ */ new Map();
31396
+ #pausedSources = /* @__PURE__ */ new Map();
31397
+ #timer;
31637
31398
  #inFlightBytes = 0;
31638
31399
  #connection = new DisconnectedDaemonSessionEventState();
31639
- constructor(outbox) {
31400
+ constructor(outbox, timer) {
31640
31401
  this.#outbox = outbox;
31402
+ this.#timer = timer;
31641
31403
  }
31642
31404
  connect = (socket) => {
31643
31405
  this.#connection = new ConnectedDaemonSessionEventState(socket);
@@ -31680,6 +31442,30 @@ var DaemonSessionEventPublisher = class {
31680
31442
  this.#publishNextBatch();
31681
31443
  return true;
31682
31444
  };
31445
+ defer = (deferred) => {
31446
+ const inFlight = this.#inFlightEvents.get(deferred.eventId);
31447
+ if (inFlight === void 0) {
31448
+ return;
31449
+ }
31450
+ this.#clearInFlightSource(inFlight.sourceKey);
31451
+ if (!this.#pausedSources.has(inFlight.sourceKey)) {
31452
+ this.#pausedSources.set(
31453
+ inFlight.sourceKey,
31454
+ this.#timer.schedule(() => {
31455
+ this.#pausedSources.delete(inFlight.sourceKey);
31456
+ this.#publishNextBatch();
31457
+ }, deferred.retryAfterMilliseconds)
31458
+ );
31459
+ }
31460
+ this.#publishNextBatch();
31461
+ };
31462
+ close = () => {
31463
+ for (const task of this.#pausedSources.values()) {
31464
+ task.cancel();
31465
+ }
31466
+ this.#pausedSources.clear();
31467
+ this.#clearInFlight();
31468
+ };
31683
31469
  #publishNextBatch = () => {
31684
31470
  while (this.#inFlightEvents.size < SESSION_EVENT_REPLAY_WINDOW) {
31685
31471
  const sourceCounts = /* @__PURE__ */ new Map();
@@ -31690,7 +31476,7 @@ var DaemonSessionEventPublisher = class {
31690
31476
  const batch = this.#outbox.pendingSourceHeads(
31691
31477
  SESSION_EVENT_REPLAY_WINDOW - this.#inFlightEvents.size,
31692
31478
  [...this.#inFlightEvents.keys()],
31693
- saturatedSources
31479
+ [...this.#pausedSources.keys(), ...saturatedSources]
31694
31480
  );
31695
31481
  let sent = 0;
31696
31482
  for (const encoded of batch) {
@@ -31730,6 +31516,15 @@ var DaemonSessionEventPublisher = class {
31730
31516
  this.#inFlightEvents.clear();
31731
31517
  this.#inFlightBytes = 0;
31732
31518
  };
31519
+ #clearInFlightSource = (sourceKey) => {
31520
+ for (const [eventId, inFlight] of this.#inFlightEvents) {
31521
+ if (inFlight.sourceKey !== sourceKey) {
31522
+ continue;
31523
+ }
31524
+ this.#inFlightEvents.delete(eventId);
31525
+ this.#inFlightBytes -= inFlight.byteLength;
31526
+ }
31527
+ };
31733
31528
  };
31734
31529
  var CoalescingDaemonActivityPublisher = class {
31735
31530
  #pending = /* @__PURE__ */ new Map();
@@ -32664,6 +32459,10 @@ async function runRelayConnection(config2, directories, audit, sessions, install
32664
32459
  publisher.acknowledge(decodeSessionEventAcknowledgement(encoded));
32665
32460
  return;
32666
32461
  }
32462
+ if (kind === SESSION_EVENT_DEFERRED_KIND) {
32463
+ publisher.defer(decodeSessionEventDeferred(encoded));
32464
+ return;
32465
+ }
32667
32466
  if (kind === SESSION_EVENT_REJECTED_KIND) {
32668
32467
  const rejection = decodeSessionEventRejection(encoded);
32669
32468
  if (publisher.quarantine(rejection)) {
@@ -33157,7 +32956,7 @@ async function runDaemon(config2, audit, signal, timer = systemDaemonTimer) {
33157
32956
  });
33158
32957
  const sessionStore = new SqliteAcpSessionStore(config2.auditDatabasePath);
33159
32958
  const outbox = new SessionEventOutbox(config2.auditDatabasePath);
33160
- const publisher = new DaemonSessionEventPublisher(outbox);
32959
+ const publisher = new DaemonSessionEventPublisher(outbox, timer);
33161
32960
  const grants = new LocalBotGrantStore(config2.auditDatabasePath);
33162
32961
  const contexts = new BotExecutionContextRegistry();
33163
32962
  const applicator = new EmbeddedBotContextApplicator();
@@ -33259,7 +33058,11 @@ async function runDaemon(config2, audit, signal, timer = systemDaemonTimer) {
33259
33058
  try {
33260
33059
  grants.close();
33261
33060
  } finally {
33262
- outbox.close();
33061
+ try {
33062
+ publisher.close();
33063
+ } finally {
33064
+ outbox.close();
33065
+ }
33263
33066
  }
33264
33067
  }
33265
33068
  }