@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/runtime.js CHANGED
@@ -536,6 +536,7 @@ var InstallableAgentDefinition = class {
536
536
  };
537
537
  var MissingAgentDefinition = class extends InstallableAgentDefinition {
538
538
  status = "agent_not_installed";
539
+ // biome-ignore lint/complexity/noUselessConstructor: Exposes the protected base constructor publicly.
539
540
  constructor(id, label) {
540
541
  super(id, label);
541
542
  }
@@ -630,6 +631,7 @@ var MissingAdapter = class extends UnavailableInstalledAgent {
630
631
  code = "adapter_not_found";
631
632
  message = "ACP adapter not found";
632
633
  status = "missing_adapter";
634
+ // biome-ignore lint/complexity/noUselessConstructor: Exposes the protected base constructor publicly.
633
635
  constructor(specification, agent) {
634
636
  super(specification, agent);
635
637
  }
@@ -638,6 +640,7 @@ var MissingAgent = class extends UnavailableAgent {
638
640
  code = "agent_not_found";
639
641
  message = "Agent executable not found";
640
642
  status = "missing_agent";
643
+ // biome-ignore lint/complexity/noUselessConstructor: Exposes the protected base constructor publicly.
641
644
  constructor(specification) {
642
645
  super(specification);
643
646
  }
@@ -666,6 +669,7 @@ var IncompatibleAdapter = class extends UnavailableInstalledAgent {
666
669
  code = "acp_incompatible";
667
670
  message = "ACP adapter is incompatible";
668
671
  status = "incompatible_adapter";
672
+ // biome-ignore lint/complexity/noUselessConstructor: Exposes the protected base constructor publicly.
669
673
  constructor(specification, agent) {
670
674
  super(specification, agent);
671
675
  }
@@ -674,6 +678,7 @@ var AuthenticationRequiredAgent = class extends UnavailableInstalledAgent {
674
678
  code = "authentication_required";
675
679
  message = "Agent authentication is required";
676
680
  status = "authentication_required";
681
+ // biome-ignore lint/complexity/noUselessConstructor: Exposes the protected base constructor publicly.
677
682
  constructor(specification, agent) {
678
683
  super(specification, agent);
679
684
  }
@@ -23117,6 +23122,7 @@ var decodeNativeSessionTurnForkCommand = (encoded) => decode4(nativeSessionTurnF
23117
23122
  var SESSION_EVENT_KIND = "session.event";
23118
23123
  var SESSION_EVENT_ACK_KIND = "session.event.ack";
23119
23124
  var SESSION_EVENT_COMMITTED_KIND = "session.event.committed";
23125
+ var SESSION_EVENT_DEFERRED_KIND = "session.event.deferred";
23120
23126
  var SESSION_EVENT_REJECTED_KIND = "session.event.rejected";
23121
23127
  var SessionEventRejectionCode = {
23122
23128
  SessionDeleted: "session_deleted",
@@ -23163,6 +23169,12 @@ var eventAcknowledgementSchema = external_exports.strictObject({
23163
23169
  sequence: external_exports.string().min(1).max(40).regex(DECIMAL_SEQUENCE_PATTERN),
23164
23170
  sessionId: external_exports.string().min(1).max(128).regex(IDENTIFIER_PATTERN4)
23165
23171
  }).readonly();
23172
+ var eventDeferredSchema = external_exports.strictObject({
23173
+ eventId: external_exports.string().min(1).max(128).regex(IDENTIFIER_PATTERN4),
23174
+ kind: external_exports.literal(SESSION_EVENT_DEFERRED_KIND),
23175
+ retryAfterMilliseconds: external_exports.number().int().min(100).max(6e4),
23176
+ sessionId: external_exports.string().min(1).max(128).regex(IDENTIFIER_PATTERN4)
23177
+ }).readonly();
23166
23178
  var eventRejectionSchema = external_exports.strictObject({
23167
23179
  code: external_exports.enum(SessionEventRejectionCode),
23168
23180
  eventId: external_exports.string().min(1).max(128).regex(IDENTIFIER_PATTERN4),
@@ -23196,6 +23208,7 @@ var encode4 = (message, schema) => {
23196
23208
  var decodeSessionEventEnvelope = (encoded) => decode5(encoded, eventEnvelopeSchema);
23197
23209
  var encodeSessionEventEnvelope = (message) => encode4(message, eventEnvelopeSchema);
23198
23210
  var decodeSessionEventAcknowledgement = (encoded) => decode5(encoded, eventAcknowledgementSchema);
23211
+ var decodeSessionEventDeferred = (encoded) => decode5(encoded, eventDeferredSchema);
23199
23212
  var decodeSessionEventRejection = (encoded) => decode5(encoded, eventRejectionSchema);
23200
23213
 
23201
23214
  // src/config.ts
@@ -23274,6 +23287,23 @@ function sniffRasterMime(bytes) {
23274
23287
  }
23275
23288
  return null;
23276
23289
  }
23290
+ function readInlineRaster(data, name = "Image") {
23291
+ if (data.length === 0 || data.length > Math.ceil(MAX_LOCAL_RASTER_BYTES / 3) * 4 || data.length % 4 !== 0) {
23292
+ return null;
23293
+ }
23294
+ if (!/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(data)) {
23295
+ return null;
23296
+ }
23297
+ const bytes = new Uint8Array(Buffer.from(data, "base64"));
23298
+ if (bytes.byteLength < 1 || bytes.byteLength > MAX_LOCAL_RASTER_BYTES) {
23299
+ return null;
23300
+ }
23301
+ const mimeType = sniffRasterMime(bytes);
23302
+ if (mimeType === null) {
23303
+ return null;
23304
+ }
23305
+ return new LocalRasterImage(basename(name) || "Image", mimeType, bytes);
23306
+ }
23277
23307
  function isInsideRoot(root, target) {
23278
23308
  const relation = relative4(root, target);
23279
23309
  return relation !== ".." && !relation.startsWith(`..${sep4}`) && !isAbsolute8(relation);
@@ -23638,7 +23668,7 @@ function normalizeContentBlock(content) {
23638
23668
  mimeType: content.mimeType
23639
23669
  };
23640
23670
  }
23641
- function normalizeToolContent(content) {
23671
+ async function normalizeToolContent(content, prepareContent) {
23642
23672
  const normalized = [];
23643
23673
  for (const item of content) {
23644
23674
  if (item.type === "diff") {
@@ -23657,7 +23687,7 @@ function normalizeToolContent(content) {
23657
23687
  });
23658
23688
  continue;
23659
23689
  }
23660
- normalized.push(normalizeContentBlock(item.content));
23690
+ normalized.push(await prepareContent(normalizeContentBlock(item.content)));
23661
23691
  }
23662
23692
  return normalized;
23663
23693
  }
@@ -23731,10 +23761,12 @@ var AcpActivityTracker = class {
23731
23761
  #activities = /* @__PURE__ */ new Map();
23732
23762
  #identities = /* @__PURE__ */ new Map();
23733
23763
  #onActivity;
23764
+ #prepareContent;
23734
23765
  #activeNarrativeKey = "";
23735
23766
  #nextSequence = 0;
23736
- constructor(onActivity) {
23767
+ constructor(onActivity, prepareContent = (content) => Promise.resolve(content)) {
23737
23768
  this.#onActivity = onActivity;
23769
+ this.#prepareContent = prepareContent;
23738
23770
  }
23739
23771
  recordNarrative = async (activityType, messageId, text) => {
23740
23772
  const key = `${activityType}:${messageId}`;
@@ -23822,7 +23854,7 @@ var AcpActivityTracker = class {
23822
23854
  const output2 = update.rawOutput === void 0 ? readContentOutput(update.content) : formatUnknown(update.rawOutput);
23823
23855
  const detailInput = update.rawInput === void 0 ? "" : formatUnknownDetail(update.rawInput);
23824
23856
  const detailOutput = update.rawOutput === void 0 ? readContentOutputDetail(update.content) : formatUnknownDetail(update.rawOutput);
23825
- const detailContent = normalizeToolContent(update.content ?? []);
23857
+ const detailContent = await normalizeToolContent(update.content ?? [], this.#prepareContent);
23826
23858
  await this.#record(
23827
23859
  key,
23828
23860
  new AcpActivity(
@@ -23848,10 +23880,10 @@ var AcpActivityTracker = class {
23848
23880
  const identity2 = this.#identity(key);
23849
23881
  const previousDetail = recordedDetail(previous);
23850
23882
  const output2 = update.rawOutput !== void 0 ? formatUnknown(update.rawOutput) : update.content !== void 0 && update.content !== null ? readContentOutput(update.content) : previous?.output ?? "";
23851
- const content = update.content === void 0 || update.content === null ? previous?.content ?? [] : normalizeToolContent(update.content);
23883
+ const content = update.content === void 0 || update.content === null ? previous?.content ?? [] : await normalizeToolContent(update.content, this.#prepareContent);
23852
23884
  const detailInput = update.rawInput === void 0 ? previousDetail?.input ?? previous?.input ?? "" : formatUnknownDetail(update.rawInput);
23853
23885
  const detailOutput = update.rawOutput !== void 0 ? formatUnknownDetail(update.rawOutput) : update.content !== void 0 && update.content !== null ? readContentOutputDetail(update.content) : previousDetail?.output ?? previous?.output ?? "";
23854
- const detailContent = update.content === void 0 || update.content === null ? previousDetail?.content ?? previous?.content ?? [] : normalizeToolContent(update.content);
23886
+ const detailContent = update.content === void 0 || update.content === null ? previousDetail?.content ?? previous?.content ?? [] : content;
23855
23887
  await this.#record(
23856
23888
  key,
23857
23889
  new AcpActivity(
@@ -25017,10 +25049,10 @@ var RunningAcpTurn = class extends AcpTurnState {
25017
25049
  running = true;
25018
25050
  activities;
25019
25051
  onText;
25020
- constructor(commandId, onActivity, onText) {
25052
+ constructor(commandId, onActivity, onText, prepareContent) {
25021
25053
  super();
25022
25054
  this.commandId = commandId;
25023
- this.activities = new AcpActivityTracker(onActivity);
25055
+ this.activities = new AcpActivityTracker(onActivity, prepareContent);
25024
25056
  this.onText = onText;
25025
25057
  }
25026
25058
  };
@@ -25304,18 +25336,27 @@ var AcpProcessSession = class _AcpProcessSession {
25304
25336
  await this.#turn.onText(leftover, messageId);
25305
25337
  }
25306
25338
  };
25307
- emitAgentContent = async (content, messageId) => {
25339
+ prepareAgentContent = async (content) => {
25340
+ if (content.type === "image" && content.data.length > 0) {
25341
+ const raster = readInlineRaster(content.data, content.name);
25342
+ if (raster !== null) {
25343
+ return await this.importRaster(raster, AbortSignal.timeout(2e4));
25344
+ }
25345
+ }
25308
25346
  if (content.type === "image" && content.data.length === 0 && content.uri.length > 0) {
25309
25347
  const signal = AbortSignal.timeout(2e4);
25310
25348
  const raster = await readAuthorizedRaster(content.uri, this.imageRoots(), signal);
25311
25349
  if (raster !== null) {
25312
- await this.emitRaster(raster, messageId, signal);
25313
- return;
25350
+ return await this.importRaster(raster, signal);
25314
25351
  }
25315
25352
  }
25353
+ return content;
25354
+ };
25355
+ emitAgentContent = async (content, messageId) => {
25356
+ const prepared = await this.prepareAgentContent(content);
25316
25357
  await this.#getObserver().onContent({
25317
25358
  commandId: this.#turn.commandId,
25318
- content,
25359
+ content: prepared,
25319
25360
  contentId: `content-${crypto.randomUUID()}`,
25320
25361
  kind: AGENT_CONTENT_KIND,
25321
25362
  messageId,
@@ -25323,21 +25364,25 @@ var AcpProcessSession = class _AcpProcessSession {
25323
25364
  });
25324
25365
  };
25325
25366
  emitRaster = async (raster, messageId, signal) => {
25326
- const artifactId = await this.#getObserver().importLocalImage(this.#mobiusSessionId, raster, signal);
25367
+ const content = await this.importRaster(raster, signal);
25327
25368
  await this.#getObserver().onContent({
25328
25369
  commandId: this.#turn.commandId,
25329
- content: imageDisplayContent(
25330
- raster.mimeType,
25331
- raster.name,
25332
- artifactId.length > 0 ? "" : raster.base64(),
25333
- artifactId
25334
- ),
25370
+ content,
25335
25371
  contentId: `content-${crypto.randomUUID()}`,
25336
25372
  kind: AGENT_CONTENT_KIND,
25337
25373
  messageId,
25338
25374
  sessionId: this.#mobiusSessionId
25339
25375
  });
25340
25376
  };
25377
+ importRaster = async (raster, signal) => {
25378
+ const artifactId = await this.#getObserver().importLocalImage(this.#mobiusSessionId, raster, signal);
25379
+ return imageDisplayContent(
25380
+ raster.mimeType,
25381
+ raster.name,
25382
+ artifactId.length > 0 ? "" : raster.base64(),
25383
+ artifactId
25384
+ );
25385
+ };
25341
25386
  async #initializeAgent(signal) {
25342
25387
  const initialized = await this.race(
25343
25388
  this.#connection.agent.request(
@@ -25705,7 +25750,12 @@ var AcpProcessSession = class _AcpProcessSession {
25705
25750
  )
25706
25751
  );
25707
25752
  this.#prompted = true;
25708
- const running = new RunningAcpTurn(options.commandId, options.onActivity, options.onText);
25753
+ const running = new RunningAcpTurn(
25754
+ options.commandId,
25755
+ options.onActivity,
25756
+ options.onText,
25757
+ this.prepareAgentContent
25758
+ );
25709
25759
  this.#turn = running;
25710
25760
  try {
25711
25761
  const response = await this.race(
@@ -26957,6 +27007,7 @@ var AgentInstallation = class {
26957
27007
  };
26958
27008
  var RequestedInstallation = class extends AgentInstallation {
26959
27009
  status = "requested";
27010
+ // biome-ignore lint/complexity/noUselessConstructor: Exposes the protected base constructor publicly.
26960
27011
  constructor(requestId, agentId) {
26961
27012
  super(requestId, agentId);
26962
27013
  }
@@ -26972,6 +27023,7 @@ var RunningInstallation = class extends AgentInstallation {
26972
27023
  var SucceededInstallation = class extends AgentInstallation {
26973
27024
  authenticationMayBeRequired = true;
26974
27025
  status = "succeeded";
27026
+ // biome-ignore lint/complexity/noUselessConstructor: Exposes the protected base constructor publicly.
26975
27027
  constructor(requestId, agentId) {
26976
27028
  super(requestId, agentId);
26977
27029
  }
@@ -26988,6 +27040,7 @@ var FailedInstallation = class extends AgentInstallation {
26988
27040
  };
26989
27041
  var CancelledInstallation = class extends AgentInstallation {
26990
27042
  status = "cancelled";
27043
+ // biome-ignore lint/complexity/noUselessConstructor: Exposes the protected base constructor publicly.
26991
27044
  constructor(requestId, agentId) {
26992
27045
  super(requestId, agentId);
26993
27046
  }
@@ -28493,7 +28546,7 @@ var BotExecutionContextRegistry = class {
28493
28546
  activate = (command) => {
28494
28547
  let handle = this.#handlesBySession.get(command.sessionId);
28495
28548
  if (handle === void 0) {
28496
- handle = `ctx_${randomBytes(32).toString("base64url")}`;
28549
+ handle = `ctx_${Buffer.from(randomBytes(32)).toString("base64url")}`;
28497
28550
  this.#handlesBySession.set(command.sessionId, handle);
28498
28551
  }
28499
28552
  if (this.#activeByHandle.has(handle)) {
@@ -28775,255 +28828,6 @@ var BotOutboundIpcServer = class {
28775
28828
  // src/native-sessions/service.ts
28776
28829
  import { randomUUID as randomUUID2 } from "node:crypto";
28777
28830
  import { basename as basename3 } from "node:path";
28778
-
28779
- // src/native-sessions/codex-history.ts
28780
- import { spawn as spawn4 } from "node:child_process";
28781
- var responseSchema = external_exports.union([
28782
- external_exports.object({
28783
- id: external_exports.number(),
28784
- error: external_exports.object({ code: external_exports.number(), message: external_exports.string() })
28785
- }),
28786
- external_exports.object({ id: external_exports.number(), result: external_exports.unknown() }),
28787
- external_exports.object({ method: external_exports.string() })
28788
- ]);
28789
- var threadSchema = external_exports.object({
28790
- thread: external_exports.object({
28791
- id: nativeSessionIdSchema,
28792
- cwd: external_exports.string().min(1).max(2048).refine((path2) => !path2.includes("\0"))
28793
- })
28794
- });
28795
- var turnsSchema = external_exports.object({
28796
- data: external_exports.array(external_exports.object({ items: external_exports.array(external_exports.unknown()).max(1e5) })).max(SESSION_HISTORY_PREVIEW_MESSAGE_LIMIT),
28797
- nextCursor: external_exports.string().nullish()
28798
- });
28799
- var itemTypeSchema = external_exports.object({ type: external_exports.string().min(1).max(80) });
28800
- var userMessageSchema = external_exports.object({
28801
- content: external_exports.array(external_exports.unknown()).max(1e4)
28802
- });
28803
- var textSchema = external_exports.object({ text: external_exports.string() });
28804
- var imageSchema = external_exports.object({ url: external_exports.string() });
28805
- var agentMessageSchema = textSchema.extend({ phase: external_exports.string().nullish() });
28806
- function decodeHistory(thread, value) {
28807
- const page = turnsSchema.parse(value);
28808
- const messages = [];
28809
- let characters = 0;
28810
- let truncated = page.nextCursor != null;
28811
- for (const turn of page.data.toReversed()) {
28812
- for (const item of turn.items) {
28813
- const { type } = itemTypeSchema.parse(item);
28814
- let message;
28815
- if (type === "userMessage") {
28816
- const { content } = userMessageSchema.parse(item);
28817
- const text2 = content.map((block) => {
28818
- const { type: type2 } = itemTypeSchema.parse(block);
28819
- if (type2 === "text") {
28820
- return textSchema.parse(block).text;
28821
- }
28822
- if (type2 === "image") {
28823
- return `[@image](${imageSchema.parse(block).url})`;
28824
- }
28825
- return "[Attachment]";
28826
- }).join("");
28827
- message = {
28828
- role: "user",
28829
- text: text2
28830
- };
28831
- } else if (type === "agentMessage") {
28832
- const agent = agentMessageSchema.parse(item);
28833
- if (agent.phase === "commentary") {
28834
- continue;
28835
- }
28836
- message = { role: "assistant", text: agent.text };
28837
- } else {
28838
- continue;
28839
- }
28840
- const text = message.text.slice(-SESSION_HISTORY_CHARACTER_LIMIT);
28841
- if (text.length === 0 && (message.images?.length ?? 0) === 0) {
28842
- continue;
28843
- }
28844
- truncated ||= text.length < message.text.length;
28845
- messages.push({ ...message, text });
28846
- characters += text.length;
28847
- while (messages.length > SESSION_HISTORY_PREVIEW_MESSAGE_LIMIT || characters > SESSION_HISTORY_CHARACTER_LIMIT) {
28848
- const removed = messages.shift();
28849
- if (removed !== void 0) {
28850
- characters -= removed.text.length;
28851
- }
28852
- truncated = true;
28853
- }
28854
- }
28855
- }
28856
- return {
28857
- nativeSessionId: thread.id,
28858
- cwd: thread.cwd,
28859
- history: {
28860
- status: "available",
28861
- messages,
28862
- truncated,
28863
- coveredCommandIds: [],
28864
- coveredMessageIds: []
28865
- }
28866
- };
28867
- }
28868
- async function readCodexHistory(agent, cwd, nativeSessionId, signal) {
28869
- signal.throwIfAborted();
28870
- nativeSessionIdSchema.parse(nativeSessionId);
28871
- if (agent.id !== "codex" || !await revalidateExecutable(agent.agentIdentity)) {
28872
- throw new AcpExecutionError(
28873
- "The local Codex executable changed. Restart Mobius to discover it again.",
28874
- {},
28875
- "agent_executable_changed"
28876
- );
28877
- }
28878
- signal.throwIfAborted();
28879
- const child = spawn4(agent.agentIdentity.realPath, ["app-server"], {
28880
- cwd,
28881
- env: { ...process.env, ...agent.environment },
28882
- detached: process.platform !== "win32",
28883
- shell: false,
28884
- stdio: ["pipe", "pipe", "ignore"]
28885
- });
28886
- const response = Promise.withResolvers();
28887
- let state = { kind: "initializing", requestId: 1 };
28888
- let pending = "";
28889
- let receivedBytes = 0;
28890
- const fail = (cause) => response.reject(
28891
- cause instanceof AcpExecutionError ? cause : new AcpExecutionError(
28892
- "Saved Codex history could not be read.",
28893
- { cause },
28894
- "native_history_unavailable"
28895
- )
28896
- );
28897
- const send2 = (message) => {
28898
- child.stdin.write(`${JSON.stringify(message)}
28899
- `);
28900
- };
28901
- const onData = (chunk) => {
28902
- try {
28903
- receivedBytes += Buffer.byteLength(chunk);
28904
- if (receivedBytes > 32 * 1024 * 1024) {
28905
- throw new AcpExecutionError(
28906
- "This saved conversation is too large to preview.",
28907
- {},
28908
- "native_history_too_large"
28909
- );
28910
- }
28911
- pending += chunk;
28912
- let newline = pending.indexOf("\n");
28913
- while (newline >= 0) {
28914
- const line = pending.slice(0, newline);
28915
- pending = pending.slice(newline + 1);
28916
- newline = pending.indexOf("\n");
28917
- if (line.trim().length === 0) {
28918
- continue;
28919
- }
28920
- const value = JSON.parse(line);
28921
- const message = responseSchema.parse(value);
28922
- if (!("id" in message)) {
28923
- continue;
28924
- }
28925
- if (message.id !== state.requestId) {
28926
- throw new AcpExecutionError(
28927
- "Codex returned an invalid history response.",
28928
- {},
28929
- "invalid_native_session_response"
28930
- );
28931
- }
28932
- if ("error" in message) {
28933
- fail(
28934
- new AcpExecutionError(
28935
- "Saved Codex history could not be read.",
28936
- { cause: message.error },
28937
- "native_history_unavailable"
28938
- )
28939
- );
28940
- return;
28941
- }
28942
- switch (state.kind) {
28943
- case "initializing":
28944
- state = { kind: "metadata", requestId: 2 };
28945
- send2({ method: "initialized", params: {} });
28946
- send2({
28947
- id: state.requestId,
28948
- method: "thread/read",
28949
- params: { threadId: nativeSessionId, includeTurns: false }
28950
- });
28951
- break;
28952
- case "metadata": {
28953
- const { thread } = threadSchema.parse(message.result);
28954
- state = { kind: "turns", requestId: 3, thread };
28955
- send2({
28956
- id: state.requestId,
28957
- method: "thread/turns/list",
28958
- params: {
28959
- threadId: nativeSessionId,
28960
- limit: SESSION_HISTORY_PREVIEW_MESSAGE_LIMIT,
28961
- sortDirection: "desc",
28962
- itemsView: "summary"
28963
- }
28964
- });
28965
- break;
28966
- }
28967
- case "turns":
28968
- response.resolve(decodeHistory(state.thread, message.result));
28969
- return;
28970
- default: {
28971
- const unhandled = state;
28972
- throw new Error(`Unknown history read state: ${String(unhandled)}`);
28973
- }
28974
- }
28975
- }
28976
- } catch (cause) {
28977
- fail(cause);
28978
- }
28979
- };
28980
- const abort = () => response.reject(signal.reason);
28981
- const onExit = () => fail(
28982
- new AcpExecutionError(
28983
- "Codex stopped before its saved history was available.",
28984
- {},
28985
- "native_history_unavailable"
28986
- )
28987
- );
28988
- const timeout = setTimeout(
28989
- () => fail(new AcpExecutionError("Reading saved Codex history timed out.", {}, "native_history_timeout")),
28990
- 15e3
28991
- );
28992
- child.stdout.setEncoding("utf8");
28993
- child.stdout.on("data", onData);
28994
- child.stdin.on("error", fail);
28995
- child.on("error", fail);
28996
- child.on("exit", onExit);
28997
- signal.addEventListener("abort", abort, { once: true });
28998
- try {
28999
- if (signal.aborted) {
29000
- abort();
29001
- } else {
29002
- send2({
29003
- id: 1,
29004
- method: "initialize",
29005
- params: { clientInfo: { name: "mobius_history", version: "1.0.0" } }
29006
- });
29007
- }
29008
- const snapshot = await response.promise;
29009
- return {
29010
- ...snapshot,
29011
- history: await embedLocalHistoryImages(snapshot.history, [cwd, snapshot.cwd], signal)
29012
- };
29013
- } finally {
29014
- clearTimeout(timeout);
29015
- signal.removeEventListener("abort", abort);
29016
- child.stdout.removeListener("data", onData);
29017
- if (child.pid !== void 0) {
29018
- await stopProcessTree(child);
29019
- }
29020
- child.stdin.removeListener("error", fail);
29021
- child.removeListener("error", fail);
29022
- child.removeListener("exit", onExit);
29023
- }
29024
- }
29025
-
29026
- // src/native-sessions/service.ts
29027
28831
  var NativeSessionService = class {
29028
28832
  #entries = /* @__PURE__ */ new Map();
29029
28833
  #cursors = /* @__PURE__ */ new Map();
@@ -29186,7 +28990,7 @@ var NativeSessionService = class {
29186
28990
  "native_session_unsupported"
29187
28991
  );
29188
28992
  }
29189
- const opening = this.#sessions.openNativeSession(
28993
+ const opened = await this.#sessions.openNativeSession(
29190
28994
  {
29191
28995
  ...options,
29192
28996
  cwd: target.cwd,
@@ -29195,35 +28999,6 @@ var NativeSessionService = class {
29195
28999
  },
29196
29000
  { kind: command.action, nativeSessionId: target.info.sessionId }
29197
29001
  );
29198
- const opened = await opening.catch(async (cause) => {
29199
- signal.throwIfAborted();
29200
- if (command.action !== "import" || options.agent.id !== "codex" || !(cause instanceof AcpExecutionError) || cause.code !== "acp_execution_failed") {
29201
- throw cause;
29202
- }
29203
- const snapshot = await readCodexHistory(options.agent, target.cwd, target.info.sessionId, signal);
29204
- const resolved = await this.#directories.identify(command.bindingId, snapshot.cwd, signal);
29205
- if (snapshot.nativeSessionId !== target.info.sessionId || resolved.path !== target.cwd) {
29206
- throw new AcpExecutionError(
29207
- "Codex returned history for a different session or workspace.",
29208
- { cause },
29209
- "invalid_native_session_response"
29210
- );
29211
- }
29212
- signal.throwIfAborted();
29213
- this.record(command, "native_session_previewed");
29214
- return { kind: "preview", history: snapshot.history };
29215
- });
29216
- if ("kind" in opened) {
29217
- return {
29218
- ...envelope2,
29219
- action: "preview",
29220
- entryId: command.entryId,
29221
- reason: "continuation_unavailable",
29222
- targetSessionId: command.targetSessionId,
29223
- title: target.info.title ?? "Untitled session",
29224
- history: opened.history
29225
- };
29226
- }
29227
29002
  signal.throwIfAborted();
29228
29003
  const ready = {
29229
29004
  additionalDirectories: target.additionalEntries,
@@ -29959,11 +29734,9 @@ import { dirname as dirname7 } from "node:path";
29959
29734
  import { DatabaseSync as DatabaseSync4 } from "node:sqlite";
29960
29735
  var DEFAULT_OUTBOX_LIMITS = {
29961
29736
  criticalEventBytes: 136 * 1024 * 1024,
29962
- criticalEventCount: 10128,
29963
29737
  runtimeDeliveryBytes: 64 * 1024 * 1024,
29964
29738
  runtimeDeliveryCount: 64,
29965
- standardEventBytes: 128 * 1024 * 1024,
29966
- standardEventCount: 1e4
29739
+ standardEventBytes: 128 * 1024 * 1024
29967
29740
  };
29968
29741
  var SessionEventOutboxCapacityError = class extends Error {
29969
29742
  code = "session_event_outbox_full";
@@ -30246,21 +30019,9 @@ var SessionEventOutbox = class {
30246
30019
  this.#database.close();
30247
30020
  };
30248
30021
  enqueue = (sessionId, payload, attemptId = null) => {
30249
- return this.#enqueueBounded(
30250
- sessionId,
30251
- payload,
30252
- attemptId ?? "",
30253
- this.#limits.standardEventCount,
30254
- this.#limits.standardEventBytes
30255
- );
30022
+ return this.#enqueueBounded(sessionId, payload, attemptId ?? "", this.#limits.standardEventBytes);
30256
30023
  };
30257
- enqueueCritical = (sessionId, payload, attemptId = "") => this.#enqueueBounded(
30258
- sessionId,
30259
- payload,
30260
- attemptId,
30261
- this.#limits.criticalEventCount,
30262
- this.#limits.criticalEventBytes
30263
- );
30024
+ enqueueCritical = (sessionId, payload, attemptId = "") => this.#enqueueBounded(sessionId, payload, attemptId, this.#limits.criticalEventBytes);
30264
30025
  claimRuntimeDelivery = (delivery) => {
30265
30026
  const payloadBytes = new TextEncoder().encode(delivery.payload).byteLength;
30266
30027
  this.#database.exec("BEGIN IMMEDIATE");
@@ -30367,7 +30128,7 @@ var SessionEventOutbox = class {
30367
30128
  true
30368
30129
  )
30369
30130
  );
30370
- #enqueueBounded = (sessionId, payload, attemptId, maximumEventCount, maximumEventBytes) => {
30131
+ #enqueueBounded = (sessionId, payload, attemptId, maximumEventBytes) => {
30371
30132
  const sourceKey = attemptId.length === 0 ? `runtime:${sessionId}` : `attempt:${sessionId}:${attemptId}`;
30372
30133
  this.#database.exec("BEGIN IMMEDIATE");
30373
30134
  try {
@@ -30394,11 +30155,11 @@ var SessionEventOutbox = class {
30394
30155
  const encoded = encodeSessionEventEnvelope(envelope2);
30395
30156
  const byteLength = new TextEncoder().encode(encoded).byteLength;
30396
30157
  const state = this.#database.prepare(
30397
- `SELECT event_count, total_bytes
30158
+ `SELECT total_bytes
30398
30159
  FROM relay_session_event_outbox_state
30399
30160
  WHERE singleton = 1`
30400
30161
  ).get();
30401
- if (rowNumber(state, "event_count") + 1 > maximumEventCount || rowNumber(state, "total_bytes") + byteLength > maximumEventBytes) {
30162
+ if (rowNumber(state, "total_bytes") + byteLength > maximumEventBytes) {
30402
30163
  throw new SessionEventOutboxCapacityError();
30403
30164
  }
30404
30165
  this.#database.prepare(
@@ -30532,16 +30293,14 @@ var SessionEventOutbox = class {
30532
30293
  function validateLimits(limits) {
30533
30294
  const values = [
30534
30295
  limits.criticalEventBytes,
30535
- limits.criticalEventCount,
30536
30296
  limits.runtimeDeliveryBytes,
30537
30297
  limits.runtimeDeliveryCount,
30538
- limits.standardEventBytes,
30539
- limits.standardEventCount
30298
+ limits.standardEventBytes
30540
30299
  ];
30541
30300
  if (values.some((value) => !Number.isSafeInteger(value) || value < 1)) {
30542
30301
  throw new Error("Session event outbox limits must be positive integers");
30543
30302
  }
30544
- if (limits.criticalEventBytes < limits.standardEventBytes || limits.criticalEventCount < limits.standardEventCount) {
30303
+ if (limits.criticalEventBytes < limits.standardEventBytes) {
30545
30304
  throw new Error("Critical Session event capacity must include the standard capacity");
30546
30305
  }
30547
30306
  }
@@ -30891,10 +30650,13 @@ function sessionEventSourceKey(envelope2) {
30891
30650
  var DaemonSessionEventPublisher = class {
30892
30651
  #outbox;
30893
30652
  #inFlightEvents = /* @__PURE__ */ new Map();
30653
+ #pausedSources = /* @__PURE__ */ new Map();
30654
+ #timer;
30894
30655
  #inFlightBytes = 0;
30895
30656
  #connection = new DisconnectedDaemonSessionEventState();
30896
- constructor(outbox) {
30657
+ constructor(outbox, timer) {
30897
30658
  this.#outbox = outbox;
30659
+ this.#timer = timer;
30898
30660
  }
30899
30661
  connect = (socket) => {
30900
30662
  this.#connection = new ConnectedDaemonSessionEventState(socket);
@@ -30937,6 +30699,30 @@ var DaemonSessionEventPublisher = class {
30937
30699
  this.#publishNextBatch();
30938
30700
  return true;
30939
30701
  };
30702
+ defer = (deferred) => {
30703
+ const inFlight = this.#inFlightEvents.get(deferred.eventId);
30704
+ if (inFlight === void 0) {
30705
+ return;
30706
+ }
30707
+ this.#clearInFlightSource(inFlight.sourceKey);
30708
+ if (!this.#pausedSources.has(inFlight.sourceKey)) {
30709
+ this.#pausedSources.set(
30710
+ inFlight.sourceKey,
30711
+ this.#timer.schedule(() => {
30712
+ this.#pausedSources.delete(inFlight.sourceKey);
30713
+ this.#publishNextBatch();
30714
+ }, deferred.retryAfterMilliseconds)
30715
+ );
30716
+ }
30717
+ this.#publishNextBatch();
30718
+ };
30719
+ close = () => {
30720
+ for (const task of this.#pausedSources.values()) {
30721
+ task.cancel();
30722
+ }
30723
+ this.#pausedSources.clear();
30724
+ this.#clearInFlight();
30725
+ };
30940
30726
  #publishNextBatch = () => {
30941
30727
  while (this.#inFlightEvents.size < SESSION_EVENT_REPLAY_WINDOW) {
30942
30728
  const sourceCounts = /* @__PURE__ */ new Map();
@@ -30947,7 +30733,7 @@ var DaemonSessionEventPublisher = class {
30947
30733
  const batch = this.#outbox.pendingSourceHeads(
30948
30734
  SESSION_EVENT_REPLAY_WINDOW - this.#inFlightEvents.size,
30949
30735
  [...this.#inFlightEvents.keys()],
30950
- saturatedSources
30736
+ [...this.#pausedSources.keys(), ...saturatedSources]
30951
30737
  );
30952
30738
  let sent = 0;
30953
30739
  for (const encoded of batch) {
@@ -30987,6 +30773,15 @@ var DaemonSessionEventPublisher = class {
30987
30773
  this.#inFlightEvents.clear();
30988
30774
  this.#inFlightBytes = 0;
30989
30775
  };
30776
+ #clearInFlightSource = (sourceKey) => {
30777
+ for (const [eventId, inFlight] of this.#inFlightEvents) {
30778
+ if (inFlight.sourceKey !== sourceKey) {
30779
+ continue;
30780
+ }
30781
+ this.#inFlightEvents.delete(eventId);
30782
+ this.#inFlightBytes -= inFlight.byteLength;
30783
+ }
30784
+ };
30990
30785
  };
30991
30786
  var CoalescingDaemonActivityPublisher = class {
30992
30787
  #pending = /* @__PURE__ */ new Map();
@@ -31921,6 +31716,10 @@ async function runRelayConnection(config2, directories, audit, sessions, install
31921
31716
  publisher.acknowledge(decodeSessionEventAcknowledgement(encoded));
31922
31717
  return;
31923
31718
  }
31719
+ if (kind === SESSION_EVENT_DEFERRED_KIND) {
31720
+ publisher.defer(decodeSessionEventDeferred(encoded));
31721
+ return;
31722
+ }
31924
31723
  if (kind === SESSION_EVENT_REJECTED_KIND) {
31925
31724
  const rejection = decodeSessionEventRejection(encoded);
31926
31725
  if (publisher.quarantine(rejection)) {
@@ -32414,7 +32213,7 @@ async function runDaemon(config2, audit, signal, timer = systemDaemonTimer) {
32414
32213
  });
32415
32214
  const sessionStore = new SqliteAcpSessionStore(config2.auditDatabasePath);
32416
32215
  const outbox = new SessionEventOutbox(config2.auditDatabasePath);
32417
- const publisher = new DaemonSessionEventPublisher(outbox);
32216
+ const publisher = new DaemonSessionEventPublisher(outbox, timer);
32418
32217
  const grants = new LocalBotGrantStore(config2.auditDatabasePath);
32419
32218
  const contexts = new BotExecutionContextRegistry();
32420
32219
  const applicator = new EmbeddedBotContextApplicator();
@@ -32516,7 +32315,11 @@ async function runDaemon(config2, audit, signal, timer = systemDaemonTimer) {
32516
32315
  try {
32517
32316
  grants.close();
32518
32317
  } finally {
32519
- outbox.close();
32318
+ try {
32319
+ publisher.close();
32320
+ } finally {
32321
+ outbox.close();
32322
+ }
32520
32323
  }
32521
32324
  }
32522
32325
  }