@moxt-ai/mobius 0.0.26 → 0.0.28

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 (52) hide show
  1. package/dist/acp/activity.d.ts +1 -0
  2. package/dist/acp/activity.d.ts.map +1 -1
  3. package/dist/acp/activity.js +14 -1
  4. package/dist/acp/activity.js.map +1 -1
  5. package/dist/acp/session-history.d.ts.map +1 -1
  6. package/dist/acp/session-history.js +10 -16
  7. package/dist/acp/session-history.js.map +1 -1
  8. package/dist/acp/session-manager.d.ts +7 -0
  9. package/dist/acp/session-manager.d.ts.map +1 -1
  10. package/dist/acp/session-manager.js +65 -11
  11. package/dist/acp/session-manager.js.map +1 -1
  12. package/dist/agent-catalog/publish-agent-catalog.js +3 -3
  13. package/dist/agent-catalog/publish-agent-catalog.js.map +1 -1
  14. package/dist/artifacts/runtime-artifact-uploader.d.ts +12 -0
  15. package/dist/artifacts/runtime-artifact-uploader.d.ts.map +1 -0
  16. package/dist/artifacts/runtime-artifact-uploader.js +157 -0
  17. package/dist/artifacts/runtime-artifact-uploader.js.map +1 -0
  18. package/dist/authorization/local-raster.d.ts +10 -0
  19. package/dist/authorization/local-raster.d.ts.map +1 -0
  20. package/dist/authorization/local-raster.js +134 -0
  21. package/dist/authorization/local-raster.js.map +1 -0
  22. package/dist/cli.js +1644 -235
  23. package/dist/cli.js.map +4 -4
  24. package/dist/index.js +1652 -251
  25. package/dist/index.js.map +4 -4
  26. package/dist/native-sessions/codex-history.d.ts.map +1 -1
  27. package/dist/native-sessions/codex-history.js +11 -11
  28. package/dist/native-sessions/codex-history.js.map +1 -1
  29. package/dist/native-sessions/history-images.d.ts +3 -0
  30. package/dist/native-sessions/history-images.d.ts.map +1 -0
  31. package/dist/native-sessions/history-images.js +74 -0
  32. package/dist/native-sessions/history-images.js.map +1 -0
  33. package/dist/prompt-artifact-resolver.d.ts.map +1 -1
  34. package/dist/prompt-artifact-resolver.js +7 -4
  35. package/dist/prompt-artifact-resolver.js.map +1 -1
  36. package/dist/relay-connection/connect.d.ts.map +1 -1
  37. package/dist/relay-connection/connect.js +3 -6
  38. package/dist/relay-connection/connect.js.map +1 -1
  39. package/dist/relay-connection/runtime-authentication.d.ts +3 -0
  40. package/dist/relay-connection/runtime-authentication.d.ts.map +1 -0
  41. package/dist/relay-connection/runtime-authentication.js +14 -0
  42. package/dist/relay-connection/runtime-authentication.js.map +1 -0
  43. package/dist/relay-connection/session-event-outbox.d.ts +32 -2
  44. package/dist/relay-connection/session-event-outbox.d.ts.map +1 -1
  45. package/dist/relay-connection/session-event-outbox.js +362 -11
  46. package/dist/relay-connection/session-event-outbox.js.map +1 -1
  47. package/dist/run-daemon.d.ts.map +1 -1
  48. package/dist/run-daemon.js +297 -24
  49. package/dist/run-daemon.js.map +1 -1
  50. package/dist/runtime.js +1654 -253
  51. package/dist/runtime.js.map +4 -4
  52. package/package.json +2 -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.26",
14
+ version: "0.0.28",
15
15
  description: "Mobius CLI for pairing and running local AI agent services.",
16
16
  type: "module",
17
17
  bin: {
@@ -55,6 +55,7 @@ var package_default = {
55
55
  },
56
56
  devDependencies: {
57
57
  "@moxt-ai/mobius-protocol": "workspace:*",
58
+ "@moxt-ai/mobius-sdk": "workspace:*",
58
59
  "@types/node": "^24.13.3",
59
60
  esbuild: "0.28.2"
60
61
  },
@@ -18841,8 +18842,8 @@ function rewriteKeyNames(ctx) {
18841
18842
  bySchema.set(entry.schema, entry);
18842
18843
  }
18843
18844
  const rewrites = /* @__PURE__ */ new Map();
18844
- for (const record2 of pendingRecords.get(ctx) ?? []) {
18845
- const seen = ctx.seen.get(record2);
18845
+ for (const record3 of pendingRecords.get(ctx) ?? []) {
18846
+ const seen = ctx.seen.get(record3);
18846
18847
  const names = (seen?.def ?? seen?.schema)?.propertyNames;
18847
18848
  if (!names || names === true || rewrites.has(names))
18848
18849
  continue;
@@ -21799,6 +21800,7 @@ var elicitationFieldSchema = external_exports.strictObject({
21799
21800
  type: external_exports.enum(["boolean", "integer", "multiselect", "number", "select", "string"])
21800
21801
  }).readonly();
21801
21802
  var displayContentSchema = external_exports.strictObject({
21803
+ artifactId: external_exports.string().max(128).default(""),
21802
21804
  data: external_exports.string().max(4e6),
21803
21805
  mimeType: external_exports.string().max(255),
21804
21806
  name: external_exports.string().max(500),
@@ -21811,6 +21813,7 @@ var displayContentSchema = external_exports.strictObject({
21811
21813
  uri: external_exports.string().max(4096)
21812
21814
  }).readonly();
21813
21815
  var recordedDisplayContentSchema = external_exports.strictObject({
21816
+ artifactId: external_exports.string().max(128).default(""),
21814
21817
  data: external_exports.string().max(4e6),
21815
21818
  mimeType: external_exports.string().max(255),
21816
21819
  name: external_exports.string().max(500),
@@ -22094,6 +22097,9 @@ var SESSION_CANCEL_KIND = "session.cancel";
22094
22097
  var RUNTIME_LIVENESS_READY_KIND = "runtime.liveness.ready";
22095
22098
  var RUNTIME_HEARTBEAT_KIND = "runtime.heartbeat";
22096
22099
  var RUNTIME_HEARTBEAT_ACK_KIND = "runtime.heartbeat.ack";
22100
+ var RUNTIME_DELIVERY_KIND = "runtime.delivery";
22101
+ var RUNTIME_DELIVERY_RECEIVED_KIND = "runtime.delivery.received";
22102
+ var RUNTIME_DELIVERY_COMMITTED_KIND = "runtime.delivery.committed";
22097
22103
  var SESSION_STARTED_KIND = "session.started";
22098
22104
  var AGENT_MESSAGE_DELTA_KIND = "agent.message.delta";
22099
22105
  var AGENT_ACTIVITY_KIND = "agent.activity";
@@ -22116,6 +22122,7 @@ var DIRECTORY_IDENTIFIER_PATTERN2 = /^[a-zA-Z0-9][a-zA-Z0-9_-]{0,2047}$/;
22116
22122
  var MAX_PROMPT_LENGTH = 1e4;
22117
22123
  var MAX_PROMPT_ATTACHMENT_LENGTH = 6e6;
22118
22124
  var MAX_EVENT_TEXT_LENGTH = 1e5;
22125
+ var MAX_RUNTIME_DELIVERY_PAYLOAD_LENGTH = 8 * 1024 * 1024;
22119
22126
  var ACTIVITY_TYPES = /* @__PURE__ */ new Set(["plan", "progress", "reasoning", "tool"]);
22120
22127
  var ACTIVITY_STATUSES = /* @__PURE__ */ new Set(["pending", "running", "completed", "failed"]);
22121
22128
  var TOOL_KINDS = /* @__PURE__ */ new Set([
@@ -22394,6 +22401,37 @@ function decodeRuntimeHeartbeatAckEvent(encoded) {
22394
22401
  kind: RUNTIME_HEARTBEAT_ACK_KIND
22395
22402
  };
22396
22403
  }
22404
+ function decodeRuntimeDelivery(encoded) {
22405
+ const value = parseJson2(encoded);
22406
+ assertExactKeys(value, ["deliveryId", "kind", "payload", "sessionId"]);
22407
+ assertKind(value, RUNTIME_DELIVERY_KIND);
22408
+ return {
22409
+ deliveryId: readIdentifier(value, "deliveryId"),
22410
+ kind: RUNTIME_DELIVERY_KIND,
22411
+ payload: readString(value, "payload", MAX_RUNTIME_DELIVERY_PAYLOAD_LENGTH),
22412
+ sessionId: readIdentifier(value, "sessionId")
22413
+ };
22414
+ }
22415
+ function decodeRuntimeDeliveryReceived(encoded) {
22416
+ const value = parseJson2(encoded);
22417
+ assertExactKeys(value, ["deliveryId", "kind", "sessionId"]);
22418
+ assertKind(value, RUNTIME_DELIVERY_RECEIVED_KIND);
22419
+ return {
22420
+ deliveryId: readIdentifier(value, "deliveryId"),
22421
+ kind: RUNTIME_DELIVERY_RECEIVED_KIND,
22422
+ sessionId: readIdentifier(value, "sessionId")
22423
+ };
22424
+ }
22425
+ function decodeRuntimeDeliveryCommitted(encoded) {
22426
+ const value = parseJson2(encoded);
22427
+ assertExactKeys(value, ["deliveryId", "kind", "sessionId"]);
22428
+ assertKind(value, RUNTIME_DELIVERY_COMMITTED_KIND);
22429
+ return {
22430
+ deliveryId: readIdentifier(value, "deliveryId"),
22431
+ kind: RUNTIME_DELIVERY_COMMITTED_KIND,
22432
+ sessionId: readIdentifier(value, "sessionId")
22433
+ };
22434
+ }
22397
22435
  function decodeSessionStartedEvent(encoded) {
22398
22436
  const value = parseJson2(encoded);
22399
22437
  assertExactKeys(value, ["commandId", "kind", "attemptId", "sessionId"]);
@@ -22481,6 +22519,9 @@ function decodeSessionFailedEvent(encoded) {
22481
22519
  function encodeRuntimeHeartbeatEvent(message) {
22482
22520
  return JSON.stringify(decodeRuntimeHeartbeatEvent(JSON.stringify(message)));
22483
22521
  }
22522
+ function encodeRuntimeDeliveryReceived(message) {
22523
+ return JSON.stringify(decodeRuntimeDeliveryReceived(JSON.stringify(message)));
22524
+ }
22484
22525
  function encodeSessionStartedEvent(message) {
22485
22526
  return JSON.stringify(decodeSessionStartedEvent(JSON.stringify(message)));
22486
22527
  }
@@ -23179,7 +23220,8 @@ var SESSION_EVENT_COMMITTED_KIND = "session.event.committed";
23179
23220
  var SESSION_EVENT_REJECTED_KIND = "session.event.rejected";
23180
23221
  var SessionEventRejectionCode = {
23181
23222
  SessionDeleted: "session_deleted",
23182
- SessionNotFound: "session_not_found"
23223
+ SessionNotFound: "session_not_found",
23224
+ SessionRejected: "session_rejected"
23183
23225
  };
23184
23226
  var IDENTIFIER_PATTERN4 = /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/;
23185
23227
  var CURSOR_PATTERN = /^[A-Za-z0-9_-]{1,512}$/;
@@ -23437,12 +23479,12 @@ function decodePairingResponse(value, credentialField, expectedKeys) {
23437
23479
  throw new PairingClientError("invalid_relay_response", "The relay returned an invalid pairing response");
23438
23480
  }
23439
23481
  const channelId = value["channelId"];
23440
- const runtimeCredential = value[credentialField];
23482
+ const runtimeCredential2 = value[credentialField];
23441
23483
  const runtimeId = value["runtimeId"];
23442
- if (typeof channelId !== "string" || !IDENTIFIER_PATTERN5.test(channelId) || typeof runtimeCredential !== "string" || !TOKEN_PATTERN2.test(runtimeCredential) || typeof runtimeId !== "string" || !IDENTIFIER_PATTERN5.test(runtimeId)) {
23484
+ if (typeof channelId !== "string" || !IDENTIFIER_PATTERN5.test(channelId) || typeof runtimeCredential2 !== "string" || !TOKEN_PATTERN2.test(runtimeCredential2) || typeof runtimeId !== "string" || !IDENTIFIER_PATTERN5.test(runtimeId)) {
23443
23485
  throw new PairingClientError("invalid_relay_response", "The relay returned an invalid pairing response");
23444
23486
  }
23445
- return { channelId, runtimeCredential, runtimeId };
23487
+ return { channelId, runtimeCredential: runtimeCredential2, runtimeId };
23446
23488
  }
23447
23489
  async function claimPairing(options, defaultWorkspace, localAgents, installableAgents, signal) {
23448
23490
  const agents = localAgents.map((agent) => ({
@@ -23477,7 +23519,7 @@ async function claimPairing(options, defaultWorkspace, localAgents, installableA
23477
23519
  }
23478
23520
  return options.pairingId.length > 0 ? decodePairingResponse(value, "runtimeCredential", REDEEM_RESPONSE_KEYS) : decodePairingResponse(value, "daemonToken", CLAIM_RESPONSE_KEYS);
23479
23521
  }
23480
- async function persistConnection(channelId, relayOrigin, runtimeCredential, defaultWorkspace, environment) {
23522
+ async function persistConnection(channelId, relayOrigin, runtimeCredential2, defaultWorkspace, environment) {
23481
23523
  const connectionsDirectory = join14(readStateDirectory(environment), "connections");
23482
23524
  await mkdir3(connectionsDirectory, { mode: 448, recursive: true });
23483
23525
  const connectionPath = join14(connectionsDirectory, `${channelId}.json`);
@@ -23489,7 +23531,7 @@ async function persistConnection(channelId, relayOrigin, runtimeCredential, defa
23489
23531
  defaultWorkspace,
23490
23532
  channelId,
23491
23533
  relayOrigin: relayOrigin.toString(),
23492
- runtimeCredential
23534
+ runtimeCredential: runtimeCredential2
23493
23535
  },
23494
23536
  null,
23495
23537
  2
@@ -23506,16 +23548,16 @@ function decodeSavedConnection(value, expectedChannelId) {
23506
23548
  }
23507
23549
  const defaultWorkspace = value["defaultWorkspace"];
23508
23550
  const channelId = value["channelId"];
23509
- const runtimeCredential = value["runtimeCredential"] ?? value["daemonToken"];
23551
+ const runtimeCredential2 = value["runtimeCredential"] ?? value["daemonToken"];
23510
23552
  const relayOrigin = value["relayOrigin"];
23511
- if (typeof defaultWorkspace !== "string" || typeof channelId !== "string" || channelId !== expectedChannelId || !IDENTIFIER_PATTERN5.test(channelId) || typeof runtimeCredential !== "string" || !TOKEN_PATTERN2.test(runtimeCredential) || typeof relayOrigin !== "string") {
23553
+ if (typeof defaultWorkspace !== "string" || typeof channelId !== "string" || channelId !== expectedChannelId || !IDENTIFIER_PATTERN5.test(channelId) || typeof runtimeCredential2 !== "string" || !TOKEN_PATTERN2.test(runtimeCredential2) || typeof relayOrigin !== "string") {
23512
23554
  throw new PairingClientError("invalid_connection", "The saved connection is invalid");
23513
23555
  }
23514
23556
  return {
23515
23557
  defaultWorkspace,
23516
23558
  channelId,
23517
23559
  relayOrigin: parseRelayOrigin(relayOrigin),
23518
- runtimeCredential
23560
+ runtimeCredential: runtimeCredential2
23519
23561
  };
23520
23562
  }
23521
23563
  async function readSavedConnection(channelId, environment) {
@@ -23642,7 +23684,7 @@ var AuditStore = class {
23642
23684
  this.database.exec("ALTER TABLE audit_events ADD COLUMN details_json TEXT NOT NULL DEFAULT '{}'");
23643
23685
  }
23644
23686
  }
23645
- record(record2) {
23687
+ record(record3) {
23646
23688
  this.database.prepare(
23647
23689
  `
23648
23690
  INSERT INTO audit_events (
@@ -23655,10 +23697,10 @@ var AuditStore = class {
23655
23697
  `
23656
23698
  ).run(
23657
23699
  (/* @__PURE__ */ new Date()).toISOString(),
23658
- record2.event,
23659
- record2.commandId,
23660
- record2.sessionId,
23661
- JSON.stringify(record2.details ?? {})
23700
+ record3.event,
23701
+ record3.commandId,
23702
+ record3.sessionId,
23703
+ JSON.stringify(record3.details ?? {})
23662
23704
  );
23663
23705
  }
23664
23706
  close() {
@@ -23668,9 +23710,9 @@ var AuditStore = class {
23668
23710
 
23669
23711
  // src/run-daemon.ts
23670
23712
  import { randomUUID as randomUUID6 } from "node:crypto";
23671
- import { basename as basename4, join as join16 } from "node:path";
23713
+ import { basename as basename5, join as join16 } from "node:path";
23672
23714
  import { styleText } from "node:util";
23673
- import { fetch as fetch6, WebSocket as WebSocket2 } from "undici";
23715
+ import { fetch as fetch7, WebSocket as WebSocket2 } from "undici";
23674
23716
 
23675
23717
  // src/acp/session-manager.ts
23676
23718
  import { spawn as spawn3 } from "node:child_process";
@@ -23681,6 +23723,212 @@ import {
23681
23723
  RequestError as RequestError2
23682
23724
  } from "@agentclientprotocol/sdk";
23683
23725
 
23726
+ // src/authorization/local-raster.ts
23727
+ import { readFile, realpath as realpath7, stat as stat6 } from "node:fs/promises";
23728
+ import { basename as basename2, isAbsolute as isAbsolute7, normalize as normalize2, relative as relative4, sep as sep4 } from "node:path";
23729
+ import { fileURLToPath } from "node:url";
23730
+ var MAX_LOCAL_RASTER_BYTES = 3e6;
23731
+ var PNG_SIGNATURE = Uint8Array.of(137, 80, 78, 71);
23732
+ var JPEG_SIGNATURE = Uint8Array.of(255, 216, 255);
23733
+ var GIF87_SIGNATURE = new TextEncoder().encode("GIF87a");
23734
+ var GIF89_SIGNATURE = new TextEncoder().encode("GIF89a");
23735
+ var RIFF_SIGNATURE = new TextEncoder().encode("RIFF");
23736
+ var WEBP_SIGNATURE = new TextEncoder().encode("WEBP");
23737
+ var LocalRasterImage = class {
23738
+ bytes;
23739
+ mimeType;
23740
+ name;
23741
+ constructor(name, mimeType, bytes) {
23742
+ this.bytes = bytes;
23743
+ this.mimeType = mimeType;
23744
+ this.name = name;
23745
+ }
23746
+ base64 = () => Buffer.from(this.bytes).toString("base64");
23747
+ };
23748
+ function startsWith(bytes, signature, offset = 0) {
23749
+ if (bytes.byteLength < offset + signature.byteLength) {
23750
+ return false;
23751
+ }
23752
+ return signature.every((value, index) => bytes[offset + index] === value);
23753
+ }
23754
+ function sniffRasterMime(bytes) {
23755
+ if (startsWith(bytes, PNG_SIGNATURE)) {
23756
+ return "image/png";
23757
+ }
23758
+ if (startsWith(bytes, JPEG_SIGNATURE)) {
23759
+ return "image/jpeg";
23760
+ }
23761
+ if (startsWith(bytes, GIF87_SIGNATURE) || startsWith(bytes, GIF89_SIGNATURE)) {
23762
+ return "image/gif";
23763
+ }
23764
+ if (startsWith(bytes, RIFF_SIGNATURE) && startsWith(bytes, WEBP_SIGNATURE, 8)) {
23765
+ return "image/webp";
23766
+ }
23767
+ return null;
23768
+ }
23769
+ function isInsideRoot(root, target) {
23770
+ const relation = relative4(root, target);
23771
+ return relation !== ".." && !relation.startsWith(`..${sep4}`) && !isAbsolute7(relation);
23772
+ }
23773
+ async function resolveCanonicalPath(requested, signal) {
23774
+ signal.throwIfAborted();
23775
+ if (!isAbsolute7(requested) || requested.includes("\0") || normalize2(requested) !== requested) {
23776
+ return null;
23777
+ }
23778
+ try {
23779
+ const target = await realpath7(requested);
23780
+ signal.throwIfAborted();
23781
+ if (!isAbsolute7(target) || normalize2(target) !== target) {
23782
+ return null;
23783
+ }
23784
+ return target;
23785
+ } catch (cause) {
23786
+ signal.throwIfAborted();
23787
+ if (cause instanceof Error && cause.name === "AbortError") {
23788
+ throw cause;
23789
+ }
23790
+ return null;
23791
+ }
23792
+ }
23793
+ function parseLocalImageUri(uri) {
23794
+ const trimmed = uri.trim();
23795
+ if (trimmed.length === 0 || trimmed.length > 2048 || trimmed.includes("\0")) {
23796
+ return null;
23797
+ }
23798
+ if (trimmed.startsWith("data:")) {
23799
+ return null;
23800
+ }
23801
+ if (trimmed.startsWith("file:")) {
23802
+ try {
23803
+ const url2 = new URL(trimmed);
23804
+ if (url2.protocol !== "file:" || url2.host.length > 0) {
23805
+ return null;
23806
+ }
23807
+ return fileURLToPath(url2);
23808
+ } catch {
23809
+ return null;
23810
+ }
23811
+ }
23812
+ if (/^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(trimmed)) {
23813
+ return null;
23814
+ }
23815
+ return trimmed;
23816
+ }
23817
+ async function readAuthorizedRaster(uri, roots, signal) {
23818
+ signal.throwIfAborted();
23819
+ const requested = parseLocalImageUri(uri);
23820
+ if (requested === null) {
23821
+ return null;
23822
+ }
23823
+ const target = await resolveCanonicalPath(requested, signal);
23824
+ if (target === null) {
23825
+ return null;
23826
+ }
23827
+ const targetMetadata = await stat6(target);
23828
+ signal.throwIfAborted();
23829
+ if (!targetMetadata.isFile() || targetMetadata.size < 1 || targetMetadata.size > MAX_LOCAL_RASTER_BYTES) {
23830
+ return null;
23831
+ }
23832
+ const authorizedRoots = [];
23833
+ for (const root of roots) {
23834
+ const directory = await resolveCanonicalPath(root, signal);
23835
+ if (directory === null) {
23836
+ continue;
23837
+ }
23838
+ const metadata = await stat6(directory);
23839
+ signal.throwIfAborted();
23840
+ if (metadata.isDirectory()) {
23841
+ authorizedRoots.push(directory);
23842
+ }
23843
+ }
23844
+ if (!authorizedRoots.some((root) => isInsideRoot(root, target))) {
23845
+ return null;
23846
+ }
23847
+ const bytes = new Uint8Array(await readFile(target));
23848
+ signal.throwIfAborted();
23849
+ if (bytes.byteLength < 1 || bytes.byteLength > MAX_LOCAL_RASTER_BYTES) {
23850
+ return null;
23851
+ }
23852
+ const mimeType = sniffRasterMime(bytes);
23853
+ if (mimeType === null) {
23854
+ return null;
23855
+ }
23856
+ return new LocalRasterImage(basename2(target) || "Image", mimeType, bytes);
23857
+ }
23858
+
23859
+ // src/native-sessions/history-images.ts
23860
+ var IMAGE_MARKER = /\[@image\]\(([^)\r\n]*)(?:\)|$)/g;
23861
+ async function embedLocalHistoryImages(history, roots, signal) {
23862
+ if (history.status !== "available") {
23863
+ return history;
23864
+ }
23865
+ const messages = [];
23866
+ let imageCharacters = 0;
23867
+ for (const message of history.messages) {
23868
+ signal.throwIfAborted();
23869
+ const resolved = await resolveMessageImages(message, roots, imageCharacters, signal);
23870
+ imageCharacters += (resolved.images ?? []).reduce((size, image) => size + image.data.length, 0);
23871
+ messages.push(resolved);
23872
+ }
23873
+ return {
23874
+ ...history,
23875
+ messages
23876
+ };
23877
+ }
23878
+ async function resolveMessageImages(message, roots, usedCharacters, signal) {
23879
+ const images = [...message.images ?? []];
23880
+ let imageCharacters = images.reduce((size, image) => size + image.data.length, 0);
23881
+ const text = await replaceImageMarkers(message.text, async (uri) => {
23882
+ if (images.length >= 8 || usedCharacters + imageCharacters >= SESSION_HISTORY_IMAGE_CHARACTER_LIMIT) {
23883
+ return "[Image unavailable]";
23884
+ }
23885
+ const embedded = parseNativeHistoryText(`[@image](${uri})`).images[0];
23886
+ if (embedded !== void 0) {
23887
+ if (usedCharacters + imageCharacters + embedded.data.length > SESSION_HISTORY_IMAGE_CHARACTER_LIMIT) {
23888
+ return "[Image unavailable]";
23889
+ }
23890
+ images.push(embedded);
23891
+ imageCharacters += embedded.data.length;
23892
+ return "";
23893
+ }
23894
+ const local = await readAuthorizedRaster(uri, roots, signal);
23895
+ if (local === null) {
23896
+ return "[Image unavailable]";
23897
+ }
23898
+ const data = local.base64();
23899
+ if (usedCharacters + imageCharacters + data.length > SESSION_HISTORY_IMAGE_CHARACTER_LIMIT) {
23900
+ return "[Image unavailable]";
23901
+ }
23902
+ images.push({
23903
+ data,
23904
+ mimeType: local.mimeType,
23905
+ name: local.name
23906
+ });
23907
+ imageCharacters += data.length;
23908
+ return "";
23909
+ });
23910
+ return {
23911
+ ...message,
23912
+ text,
23913
+ ...images.length > 0 ? { images } : {}
23914
+ };
23915
+ }
23916
+ async function replaceImageMarkers(text, replace) {
23917
+ const matches = [...text.matchAll(IMAGE_MARKER)];
23918
+ if (matches.length === 0) {
23919
+ return text;
23920
+ }
23921
+ let cursor = 0;
23922
+ let rewritten = "";
23923
+ for (const match of matches) {
23924
+ const index = match.index ?? 0;
23925
+ rewritten += text.slice(cursor, index);
23926
+ rewritten += await replace(match[1] ?? "");
23927
+ cursor = index + match[0].length;
23928
+ }
23929
+ return `${rewritten}${text.slice(cursor)}`;
23930
+ }
23931
+
23684
23932
  // src/acp/activity.ts
23685
23933
  var TRUNCATION_MARKER = "\n\u2026 output truncated by Mobius";
23686
23934
  function isRecord8(value) {
@@ -23778,6 +24026,7 @@ function readContentOutputDetail(content) {
23778
24026
  function summarizeDisplayContent(content) {
23779
24027
  return {
23780
24028
  ...content,
24029
+ artifactId: truncate(content.artifactId, 128),
23781
24030
  data: truncate(content.data, AGENT_ACTIVITY_DETAIL_LIMIT),
23782
24031
  mimeType: truncate(content.mimeType, 255),
23783
24032
  name: truncate(content.name, 500),
@@ -23790,7 +24039,7 @@ function summarizeDisplayContent(content) {
23790
24039
  };
23791
24040
  }
23792
24041
  function contentFitsRecordingEnvelope(content) {
23793
- return content.data.length <= AGENT_ACTIVITY_RECORDED_FIELD_LIMIT && content.mimeType.length <= 255 && content.name.length <= 500 && content.newText.length <= AGENT_ACTIVITY_RECORDED_FIELD_LIMIT && content.oldText.length <= AGENT_ACTIVITY_RECORDED_FIELD_LIMIT && content.path.length <= 2048 && content.terminalId.length <= 255 && content.text.length <= AGENT_ACTIVITY_RECORDED_FIELD_LIMIT && content.uri.length <= 4096;
24042
+ return content.artifactId.length <= 128 && content.data.length <= AGENT_ACTIVITY_RECORDED_FIELD_LIMIT && content.mimeType.length <= 255 && content.name.length <= 500 && content.newText.length <= AGENT_ACTIVITY_RECORDED_FIELD_LIMIT && content.oldText.length <= AGENT_ACTIVITY_RECORDED_FIELD_LIMIT && content.path.length <= 2048 && content.terminalId.length <= 255 && content.text.length <= AGENT_ACTIVITY_RECORDED_FIELD_LIMIT && content.uri.length <= 4096;
23794
24043
  }
23795
24044
  function encodedByteLength(value) {
23796
24045
  return new TextEncoder().encode(JSON.stringify(value)).byteLength;
@@ -23816,6 +24065,7 @@ function recordedDetail(activity) {
23816
24065
  }
23817
24066
  function emptyDisplayContent(type) {
23818
24067
  return {
24068
+ artifactId: "",
23819
24069
  data: "",
23820
24070
  mimeType: "",
23821
24071
  name: "",
@@ -23828,6 +24078,16 @@ function emptyDisplayContent(type) {
23828
24078
  uri: ""
23829
24079
  };
23830
24080
  }
24081
+ function imageDisplayContent(mimeType, name, data, artifactId = "", uri = "") {
24082
+ return {
24083
+ ...emptyDisplayContent("image"),
24084
+ artifactId,
24085
+ data,
24086
+ mimeType,
24087
+ name,
24088
+ uri
24089
+ };
24090
+ }
23831
24091
  function normalizeContentBlock(content) {
23832
24092
  if (content.type === "text") {
23833
24093
  return { ...emptyDisplayContent("text"), text: content.text };
@@ -24619,7 +24879,6 @@ var AcpHistoryReplay = class {
24619
24879
  #messages = [];
24620
24880
  #lastMessageId = null;
24621
24881
  #characters = 0;
24622
- #imageCharacters = 0;
24623
24882
  #truncated = false;
24624
24883
  record = (update) => {
24625
24884
  if (update.sessionUpdate !== "user_message_chunk" && update.sessionUpdate !== "agent_message_chunk") {
@@ -24630,40 +24889,30 @@ var AcpHistoryReplay = class {
24630
24889
  }
24631
24890
  const role = update.sessionUpdate === "user_message_chunk" ? "user" : "assistant";
24632
24891
  const content = update.content;
24633
- const parsed = parseNativeHistoryText(
24634
- content.type === "text" ? content.text : content.type === "image" ? `[@image](data:${content.mimeType};base64,${content.data})` : `[${content.type} attachment]`
24635
- );
24636
- const text = parsed.text;
24637
- if (text.length === 0 && parsed.images.length === 0) {
24892
+ const text = content.type === "text" ? content.text : content.type === "image" ? content.data.length > 0 ? `[@image](data:${content.mimeType};base64,${content.data})` : content.uri != null && content.uri.length > 0 ? `[@image](${content.uri})` : "[image attachment]" : `[${content.type} attachment]`;
24893
+ if (text.length === 0) {
24638
24894
  return;
24639
24895
  }
24640
24896
  const previous = this.#messages.at(-1);
24641
24897
  const id = update.messageId ?? null;
24642
24898
  const continuation = previous?.role === role && id === this.#lastMessageId;
24643
24899
  const combined = continuation ? `${previous.text}${text}` : text;
24644
- const allImages = continuation ? [...previous.images ?? [], ...parsed.images] : parsed.images;
24645
- const images = allImages.slice(0, 8);
24646
- this.#truncated ||= images.length < allImages.length;
24647
24900
  if (continuation) {
24648
24901
  this.#messages.pop();
24649
24902
  this.#characters -= previous.text.length;
24650
- this.#imageCharacters -= (previous.images ?? []).reduce((size, image) => size + image.data.length, 0);
24651
24903
  }
24652
24904
  const bounded = combined.slice(-SESSION_HISTORY_CHARACTER_LIMIT);
24653
24905
  this.#truncated ||= bounded.length < combined.length;
24654
24906
  this.#messages.push({
24655
24907
  role,
24656
- text: bounded,
24657
- ...images.length > 0 ? { images } : {}
24908
+ text: bounded
24658
24909
  });
24659
24910
  this.#characters += bounded.length;
24660
- this.#imageCharacters += images.reduce((size, image) => size + image.data.length, 0);
24661
24911
  this.#lastMessageId = id;
24662
- while (this.#messages.length > SESSION_HISTORY_PREVIEW_MESSAGE_LIMIT || this.#characters > SESSION_HISTORY_CHARACTER_LIMIT || this.#imageCharacters > SESSION_HISTORY_IMAGE_CHARACTER_LIMIT) {
24912
+ while (this.#messages.length > SESSION_HISTORY_PREVIEW_MESSAGE_LIMIT || this.#characters > SESSION_HISTORY_CHARACTER_LIMIT) {
24663
24913
  const removed = this.#messages.shift();
24664
24914
  if (removed !== void 0) {
24665
24915
  this.#characters -= removed.text.length;
24666
- this.#imageCharacters -= (removed.images ?? []).reduce((size, image) => size + image.data.length, 0);
24667
24916
  }
24668
24917
  this.#truncated = true;
24669
24918
  }
@@ -24886,6 +25135,10 @@ var MAX_PRE_SESSION_UPDATES = 100;
24886
25135
  var MAX_PRE_SESSION_UPDATE_BYTES = 1024 * 1024;
24887
25136
  var SESSION_CONTROL_COMMAND_ID = "session-control";
24888
25137
  var NullAcpSessionObserver = class {
25138
+ importLocalImage = (_sessionId, _image, signal) => {
25139
+ signal.throwIfAborted();
25140
+ return Promise.resolve("");
25141
+ };
24889
25142
  onCommands = () => Promise.resolve();
24890
25143
  onConfig = () => Promise.resolve();
24891
25144
  onContent = () => Promise.resolve();
@@ -25508,11 +25761,75 @@ var AcpProcessSession = class _AcpProcessSession {
25508
25761
  );
25509
25762
  await this.#updateTail;
25510
25763
  signal.throwIfAborted();
25511
- return history.snapshot();
25764
+ return await embedLocalHistoryImages(
25765
+ history.snapshot(),
25766
+ [this.#cwd, ...this.#additionalDirectories],
25767
+ signal
25768
+ );
25512
25769
  } finally {
25513
25770
  this.#replay = { kind: "idle" };
25514
25771
  }
25515
25772
  };
25773
+ imageRoots = () => [this.#cwd, ...this.#additionalDirectories];
25774
+ emitAgentText = async (text, messageId) => {
25775
+ const signal = AbortSignal.timeout(2e4);
25776
+ const parts = text.split(/(\[@image\]\([^)\r\n]*(?:\)|$))/);
25777
+ let leftover = "";
25778
+ for (const part of parts) {
25779
+ const marker = /^\[@image\]\(([^)\r\n]*)(?:\)|$)/.exec(part);
25780
+ if (marker === null) {
25781
+ leftover += part;
25782
+ continue;
25783
+ }
25784
+ if (leftover.length > 0) {
25785
+ await this.#turn.onText(leftover, messageId);
25786
+ leftover = "";
25787
+ }
25788
+ const raster = await readAuthorizedRaster(marker[1] ?? "", this.imageRoots(), signal);
25789
+ if (raster === null) {
25790
+ leftover += "[Image unavailable]";
25791
+ continue;
25792
+ }
25793
+ await this.emitRaster(raster, messageId, signal);
25794
+ }
25795
+ if (leftover.length > 0) {
25796
+ await this.#turn.onText(leftover, messageId);
25797
+ }
25798
+ };
25799
+ emitAgentContent = async (content, messageId) => {
25800
+ if (content.type === "image" && content.data.length === 0 && content.uri.length > 0) {
25801
+ const signal = AbortSignal.timeout(2e4);
25802
+ const raster = await readAuthorizedRaster(content.uri, this.imageRoots(), signal);
25803
+ if (raster !== null) {
25804
+ await this.emitRaster(raster, messageId, signal);
25805
+ return;
25806
+ }
25807
+ }
25808
+ await this.#getObserver().onContent({
25809
+ commandId: this.#turn.commandId,
25810
+ content,
25811
+ contentId: `content-${crypto.randomUUID()}`,
25812
+ kind: AGENT_CONTENT_KIND,
25813
+ messageId,
25814
+ sessionId: this.#mobiusSessionId
25815
+ });
25816
+ };
25817
+ emitRaster = async (raster, messageId, signal) => {
25818
+ const artifactId = await this.#getObserver().importLocalImage(this.#mobiusSessionId, raster, signal);
25819
+ await this.#getObserver().onContent({
25820
+ commandId: this.#turn.commandId,
25821
+ content: imageDisplayContent(
25822
+ raster.mimeType,
25823
+ raster.name,
25824
+ artifactId.length > 0 ? "" : raster.base64(),
25825
+ artifactId
25826
+ ),
25827
+ contentId: `content-${crypto.randomUUID()}`,
25828
+ kind: AGENT_CONTENT_KIND,
25829
+ messageId,
25830
+ sessionId: this.#mobiusSessionId
25831
+ });
25832
+ };
25516
25833
  async #initializeAgent(signal) {
25517
25834
  const initialized = await this.race(
25518
25835
  this.#connection.agent.request(
@@ -26215,18 +26532,14 @@ var AcpProcessSession = class _AcpProcessSession {
26215
26532
  );
26216
26533
  } else {
26217
26534
  await this.#turn.activities.finishNarrative();
26218
- await this.#turn.onText(update.content.text, truncate3(update.messageId ?? "", 255));
26535
+ await this.emitAgentText(update.content.text, truncate3(update.messageId ?? "", 255));
26219
26536
  }
26220
26537
  } else {
26221
26538
  await this.#turn.activities.finishNarrative();
26222
- await this.#getObserver().onContent({
26223
- commandId: this.#turn.commandId,
26224
- content: normalizeContentBlock(update.content),
26225
- contentId: `content-${crypto.randomUUID()}`,
26226
- kind: AGENT_CONTENT_KIND,
26227
- messageId: truncate3(update.messageId ?? "", 255),
26228
- sessionId: this.#mobiusSessionId
26229
- });
26539
+ await this.emitAgentContent(
26540
+ normalizeContentBlock(update.content),
26541
+ truncate3(update.messageId ?? "", 255)
26542
+ );
26230
26543
  }
26231
26544
  return;
26232
26545
  }
@@ -27048,6 +27361,23 @@ var AcpSessionManager = class {
27048
27361
 
27049
27362
  // src/agent-catalog/publish-agent-catalog.ts
27050
27363
  import { fetch as fetch3 } from "undici";
27364
+
27365
+ // src/relay-connection/runtime-authentication.ts
27366
+ function runtimeCredential(relayUrl) {
27367
+ return relayUrl.searchParams.get("token") ?? "";
27368
+ }
27369
+ function runtimeAuthorization(relayUrl) {
27370
+ const credential = runtimeCredential(relayUrl);
27371
+ return credential.length === 0 ? {} : { authorization: `Bearer ${credential}` };
27372
+ }
27373
+ function relayHttpEndpoint(relayUrl) {
27374
+ const endpoint = new URL(relayUrl);
27375
+ endpoint.protocol = endpoint.protocol === "wss:" ? "https:" : "http:";
27376
+ endpoint.search = "";
27377
+ return endpoint;
27378
+ }
27379
+
27380
+ // src/agent-catalog/publish-agent-catalog.ts
27051
27381
  var CATALOG_UPDATE_TIMEOUT_MILLISECONDS = 2e4;
27052
27382
  var AgentCatalogPublishError = class extends Error {
27053
27383
  code = "agent_catalog_update_failed";
@@ -27057,8 +27387,7 @@ var AgentCatalogPublishError = class extends Error {
27057
27387
  }
27058
27388
  };
27059
27389
  function catalogEndpoint(config2) {
27060
- const endpoint = new URL(config2.relayUrl);
27061
- endpoint.protocol = endpoint.protocol === "wss:" ? "https:" : "http:";
27390
+ const endpoint = relayHttpEndpoint(config2.relayUrl);
27062
27391
  if (endpoint.pathname.endsWith("/daemon")) {
27063
27392
  endpoint.pathname = `${endpoint.pathname.slice(0, -"/daemon".length)}/catalog`;
27064
27393
  return endpoint;
@@ -27089,7 +27418,7 @@ async function publishAgentCatalog(config2, signal) {
27089
27418
  installableAgents: catalog.installableAgents
27090
27419
  }),
27091
27420
  dispatcher: environmentProxyDispatcher,
27092
- headers: { "content-type": "application/json" },
27421
+ headers: { ...runtimeAuthorization(config2.relayUrl), "content-type": "application/json" },
27093
27422
  method: "PUT",
27094
27423
  signal: requestSignal
27095
27424
  });
@@ -27571,114 +27900,510 @@ var FixedInstallationExecutor = class {
27571
27900
  };
27572
27901
  };
27573
27902
 
27574
- // src/authorization/local-authorization-error.ts
27575
- var LocalAuthorizationError = class extends Error {
27576
- code = "local_authorization_failed";
27577
- constructor(message, options = {}) {
27903
+ // src/artifacts/runtime-artifact-uploader.ts
27904
+ import { createHash as createHash2 } from "node:crypto";
27905
+
27906
+ // ../mobius-sdk/src/errors.ts
27907
+ var MobiusError = class extends Error {
27908
+ code;
27909
+ constructor(code, message, options = {}) {
27578
27910
  super(message, options);
27579
- this.name = "LocalAuthorizationError";
27911
+ this.code = code;
27912
+ this.name = "MobiusError";
27580
27913
  }
27581
27914
  };
27582
-
27583
- // src/authorization/workspace-directory.ts
27584
- import { readdir, realpath as realpath7, stat as stat6 } from "node:fs/promises";
27585
- import { homedir as homedir2 } from "node:os";
27586
- import { basename as basename2, dirname as dirname5, isAbsolute as isAbsolute7, join as join15, normalize as normalize2, relative as relative4 } from "node:path";
27587
- var WorkspaceDirectoryListing = class {
27588
- directoryId;
27589
- directoryLabel;
27590
- entries;
27591
- parentDirectoryId;
27592
- constructor(directoryId2, directoryLabel, entries, parentDirectoryId) {
27593
- this.directoryId = directoryId2;
27594
- this.directoryLabel = directoryLabel;
27595
- this.entries = entries;
27596
- this.parentDirectoryId = parentDirectoryId;
27915
+ var MobiusProtocolError = class extends MobiusError {
27916
+ constructor(message, options = {}) {
27917
+ super("invalid_service_response", message, options);
27918
+ this.name = "MobiusProtocolError";
27597
27919
  }
27598
27920
  };
27599
- function encodePath(path2) {
27600
- const encoded = Buffer.from(path2, "utf8").toString("base64url");
27601
- if (encoded.length === 0 || encoded.length > 2e3) {
27602
- throw new LocalAuthorizationError("The local directory path is too long to select");
27921
+ var MobiusValidationError = class extends MobiusError {
27922
+ constructor(message, options = {}) {
27923
+ super("invalid_request", message, options);
27924
+ this.name = "MobiusValidationError";
27603
27925
  }
27604
- return `path-${encoded}`;
27926
+ };
27927
+
27928
+ // ../mobius-sdk/src/resources.ts
27929
+ var IDENTIFIER_PATTERN6 = /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/;
27930
+ function invalidResponse(message) {
27931
+ return new MobiusProtocolError(message);
27605
27932
  }
27606
- function decodePath(value, prefix) {
27607
- const encoded = value.slice(prefix.length);
27608
- if (encoded.length === 0 || encoded.length > 2e3 || !/^[a-zA-Z0-9_-]+$/.test(encoded)) {
27609
- throw new LocalAuthorizationError("The directory identifier is invalid");
27933
+ function isRecord11(value) {
27934
+ return typeof value === "object" && value !== null && !Array.isArray(value);
27935
+ }
27936
+ function record2(value, name) {
27937
+ if (!isRecord11(value)) {
27938
+ throw invalidResponse(`The service returned an invalid ${name}`);
27610
27939
  }
27611
- const decoded = Buffer.from(encoded, "base64url").toString("utf8");
27612
- if (Buffer.from(decoded, "utf8").toString("base64url") !== encoded || decoded.includes("\0") || normalize2(decoded) !== decoded) {
27613
- throw new LocalAuthorizationError("The directory identifier is invalid");
27940
+ return value;
27941
+ }
27942
+ function stringField(value, field, maximumLength = 85e5) {
27943
+ const candidate = value[field];
27944
+ if (typeof candidate !== "string" || candidate.length > maximumLength) {
27945
+ throw invalidResponse(`The service returned an invalid ${field}`);
27614
27946
  }
27615
- return decoded;
27947
+ return candidate;
27616
27948
  }
27617
- var WorkspaceDirectoryService = class {
27618
- #bindingId;
27619
- #defaultWorkspace;
27620
- constructor(bindingId, defaultWorkspace) {
27621
- this.#bindingId = bindingId;
27622
- this.#defaultWorkspace = defaultWorkspace;
27949
+ function identifierField(value, field) {
27950
+ const candidate = stringField(value, field, 128);
27951
+ if (!IDENTIFIER_PATTERN6.test(candidate)) {
27952
+ throw invalidResponse(`The service returned an invalid ${field}`);
27623
27953
  }
27624
- authorizeMachine = (bindingId) => {
27625
- if (bindingId !== this.#bindingId) {
27626
- throw new LocalAuthorizationError("The runtime binding is not authorized");
27627
- }
27628
- };
27629
- requestedPath = (id) => {
27630
- if (id === "default") {
27631
- return this.#defaultWorkspace;
27632
- }
27633
- if (id === "home") {
27634
- return homedir2();
27635
- }
27636
- if (id.startsWith("path-")) {
27637
- const path2 = decodePath(id, "path-");
27638
- if (isAbsolute7(path2)) {
27639
- return path2;
27640
- }
27641
- }
27642
- throw new LocalAuthorizationError("The directory identifier is invalid");
27643
- };
27644
- resolvePath = async (requested, signal) => {
27645
- signal.throwIfAborted();
27646
- if (!isAbsolute7(requested) || requested.includes("\0") || normalize2(requested) !== requested) {
27647
- throw new LocalAuthorizationError("The local directory path is invalid");
27648
- }
27649
- try {
27650
- const target = await realpath7(requested);
27651
- signal.throwIfAborted();
27652
- const metadata = await stat6(target);
27653
- signal.throwIfAborted();
27654
- if (!isAbsolute7(target) || normalize2(target) !== target || !metadata.isDirectory()) {
27655
- throw new LocalAuthorizationError("The selected location is not a directory");
27656
- }
27657
- return target;
27658
- } catch (cause) {
27659
- signal.throwIfAborted();
27660
- if (cause instanceof LocalAuthorizationError) {
27661
- throw cause;
27662
- }
27663
- throw new LocalAuthorizationError("This directory is missing or unavailable to your user account", {
27664
- cause
27665
- });
27954
+ return candidate;
27955
+ }
27956
+ function integerField(value, field) {
27957
+ const candidate = value[field];
27958
+ if (typeof candidate !== "number" || !Number.isSafeInteger(candidate) || candidate < 0) {
27959
+ throw invalidResponse(`The service returned an invalid ${field}`);
27960
+ }
27961
+ return candidate;
27962
+ }
27963
+ function validateTimestamp(value, field) {
27964
+ if (Number.isNaN(Date.parse(value))) {
27965
+ throw invalidResponse(`The service returned an invalid ${field}`);
27966
+ }
27967
+ return value;
27968
+ }
27969
+ var MobiusArtifactUploadRequest = class {
27970
+ byteLength;
27971
+ mediaType;
27972
+ name;
27973
+ sha256;
27974
+ constructor(name, mediaType, byteLength, sha256) {
27975
+ if (name.length < 1 || name.length > 500 || name.includes("\0") || mediaType.length < 1 || mediaType.length > 255 || mediaType.includes("\r") || mediaType.includes("\n") || !Number.isSafeInteger(byteLength) || byteLength < 1 || !/^[a-f0-9]{64}$/.test(sha256)) {
27976
+ throw new MobiusValidationError("The artifact upload request is invalid");
27666
27977
  }
27667
- };
27668
- label = (path2) => {
27669
- const suffix = relative4(homedir2(), path2);
27670
- return suffix === "" ? "~" : !isAbsolute7(suffix) && suffix !== ".." && !suffix.startsWith(`..${process.platform === "win32" ? "\\" : "/"}`) ? `~/${suffix.replaceAll("\\", "/")}` : path2;
27671
- };
27672
- identify = async (bindingId, requestedPath, signal) => {
27673
- this.authorizeMachine(bindingId);
27674
- const path2 = await this.resolvePath(requestedPath, signal);
27675
- return {
27676
- path: path2,
27677
- directoryId: encodePath(path2),
27678
- name: basename2(path2) || path2,
27679
- label: this.label(path2)
27680
- };
27681
- };
27978
+ this.byteLength = byteLength;
27979
+ this.mediaType = mediaType;
27980
+ this.name = name;
27981
+ this.sha256 = sha256;
27982
+ }
27983
+ };
27984
+ var MobiusArtifact = class {
27985
+ artifactId;
27986
+ byteLength;
27987
+ createdAt;
27988
+ mediaType;
27989
+ name;
27990
+ sessionId;
27991
+ sha256;
27992
+ constructor(sessionId, artifactId, name, mediaType, byteLength, sha256, createdAt) {
27993
+ this.artifactId = artifactId;
27994
+ this.byteLength = byteLength;
27995
+ this.createdAt = createdAt;
27996
+ this.mediaType = mediaType;
27997
+ this.name = name;
27998
+ this.sessionId = sessionId;
27999
+ this.sha256 = sha256;
28000
+ }
28001
+ };
28002
+ var MobiusUploadingArtifact = class extends MobiusArtifact {
28003
+ expiresAt;
28004
+ state = "uploading";
28005
+ constructor(sessionId, artifactId, name, mediaType, byteLength, sha256, createdAt, expiresAt) {
28006
+ super(sessionId, artifactId, name, mediaType, byteLength, sha256, createdAt);
28007
+ this.expiresAt = expiresAt;
28008
+ }
28009
+ };
28010
+ var MobiusArtifactUpload = class extends MobiusUploadingArtifact {
28011
+ uploadToken;
28012
+ constructor(artifact, uploadToken) {
28013
+ super(
28014
+ artifact.sessionId,
28015
+ artifact.artifactId,
28016
+ artifact.name,
28017
+ artifact.mediaType,
28018
+ artifact.byteLength,
28019
+ artifact.sha256,
28020
+ artifact.createdAt,
28021
+ artifact.expiresAt
28022
+ );
28023
+ this.uploadToken = uploadToken;
28024
+ }
28025
+ };
28026
+ var MobiusAvailableArtifact = class extends MobiusArtifact {
28027
+ availableAt;
28028
+ state = "available";
28029
+ constructor(sessionId, artifactId, name, mediaType, byteLength, sha256, createdAt, availableAt) {
28030
+ super(sessionId, artifactId, name, mediaType, byteLength, sha256, createdAt);
28031
+ this.availableAt = availableAt;
28032
+ }
28033
+ };
28034
+ var MobiusExpiredArtifact = class extends MobiusArtifact {
28035
+ expiredAt;
28036
+ state = "expired";
28037
+ constructor(sessionId, artifactId, name, mediaType, byteLength, sha256, createdAt, expiredAt) {
28038
+ super(sessionId, artifactId, name, mediaType, byteLength, sha256, createdAt);
28039
+ this.expiredAt = expiredAt;
28040
+ }
28041
+ };
28042
+ function artifactFields(value) {
28043
+ const sha256 = stringField(value, "sha256", 64);
28044
+ if (!/^[a-f0-9]{64}$/.test(sha256)) {
28045
+ throw invalidResponse("The service returned an invalid artifact digest");
28046
+ }
28047
+ return {
28048
+ artifactId: identifierField(value, "artifactId"),
28049
+ byteLength: integerField(value, "byteLength"),
28050
+ createdAt: validateTimestamp(stringField(value, "createdAt", 128), "createdAt"),
28051
+ mediaType: stringField(value, "mediaType", 255),
28052
+ name: stringField(value, "name", 500),
28053
+ sessionId: identifierField(value, "sessionId"),
28054
+ sha256
28055
+ };
28056
+ }
28057
+ function uploadingArtifact(value) {
28058
+ const fields = artifactFields(value);
28059
+ return new MobiusUploadingArtifact(
28060
+ fields.sessionId,
28061
+ fields.artifactId,
28062
+ fields.name,
28063
+ fields.mediaType,
28064
+ fields.byteLength,
28065
+ fields.sha256,
28066
+ fields.createdAt,
28067
+ validateTimestamp(stringField(value, "expiresAt", 128), "expiresAt")
28068
+ );
28069
+ }
28070
+ function decodeMobiusArtifactUpload(value) {
28071
+ const artifact = record2(value, "artifact upload authorization");
28072
+ return new MobiusArtifactUpload(uploadingArtifact(artifact), stringField(artifact, "uploadToken", 256));
28073
+ }
28074
+ function decodeMobiusArtifact(value) {
28075
+ const artifact = record2(value, "artifact");
28076
+ const state = stringField(artifact, "state", 32);
28077
+ if (state === "uploading") {
28078
+ return uploadingArtifact(artifact);
28079
+ }
28080
+ const fields = artifactFields(artifact);
28081
+ if (state === "available") {
28082
+ return new MobiusAvailableArtifact(
28083
+ fields.sessionId,
28084
+ fields.artifactId,
28085
+ fields.name,
28086
+ fields.mediaType,
28087
+ fields.byteLength,
28088
+ fields.sha256,
28089
+ fields.createdAt,
28090
+ validateTimestamp(stringField(artifact, "availableAt", 128), "availableAt")
28091
+ );
28092
+ }
28093
+ if (state === "expired") {
28094
+ return new MobiusExpiredArtifact(
28095
+ fields.sessionId,
28096
+ fields.artifactId,
28097
+ fields.name,
28098
+ fields.mediaType,
28099
+ fields.byteLength,
28100
+ fields.sha256,
28101
+ fields.createdAt,
28102
+ validateTimestamp(stringField(artifact, "expiredAt", 128), "expiredAt")
28103
+ );
28104
+ }
28105
+ throw invalidResponse("The service returned an invalid artifact state");
28106
+ }
28107
+ function decodeMobiusAvailableArtifact(value) {
28108
+ const artifact = decodeMobiusArtifact(value);
28109
+ if (!(artifact instanceof MobiusAvailableArtifact)) {
28110
+ throw invalidResponse("The service did not make the artifact available");
28111
+ }
28112
+ return artifact;
28113
+ }
28114
+ var MobiusRuntimePairingLifecycle = Object.freeze({
28115
+ Expired: "expired",
28116
+ Paired: "paired",
28117
+ Pending: "pending",
28118
+ Revoked: "revoked"
28119
+ });
28120
+
28121
+ // src/artifacts/runtime-artifact-uploader.ts
28122
+ import { fetch as fetch4 } from "undici";
28123
+ var UPLOAD_TIMEOUT_MILLISECONDS = 2e4;
28124
+ var RuntimeArtifactUploadError = class extends Error {
28125
+ code;
28126
+ constructor(code, message, options = {}) {
28127
+ super(message, options);
28128
+ this.code = code;
28129
+ this.name = "RuntimeArtifactUploadError";
28130
+ }
28131
+ };
28132
+ var UploadedRuntimeArtifact = class {
28133
+ artifactId;
28134
+ byteLength;
28135
+ mimeType;
28136
+ name;
28137
+ sha256;
28138
+ constructor(artifactId, name, mimeType, byteLength, sha256) {
28139
+ this.artifactId = artifactId;
28140
+ this.byteLength = byteLength;
28141
+ this.mimeType = mimeType;
28142
+ this.name = name;
28143
+ this.sha256 = sha256;
28144
+ }
28145
+ };
28146
+ function daemonToken(config2) {
28147
+ const token = config2.relayUrl.searchParams.get("token");
28148
+ if (token === null || token.length < 32) {
28149
+ throw new RuntimeArtifactUploadError("artifact_endpoint_invalid", "The Relay daemon token is missing");
28150
+ }
28151
+ return token;
28152
+ }
28153
+ function channelOrigin(config2) {
28154
+ const url2 = new URL(config2.relayUrl);
28155
+ url2.protocol = url2.protocol === "wss:" ? "https:" : "http:";
28156
+ let channelPath = "";
28157
+ if (url2.pathname.endsWith("/daemon")) {
28158
+ channelPath = url2.pathname.slice(0, -"/daemon".length);
28159
+ } else {
28160
+ const runtimePath = `${MOBIUS_API_PREFIX}/v1/runtimes/connect`;
28161
+ if (!url2.pathname.endsWith("/v1/runtimes/connect") && !url2.pathname.endsWith(runtimePath)) {
28162
+ throw new RuntimeArtifactUploadError("artifact_endpoint_invalid", "The Relay artifact endpoint is invalid");
28163
+ }
28164
+ channelPath = `${url2.pathname.replace(/\/v1\/runtimes\/connect$/, "")}/channels/${encodeURIComponent(config2.channelId)}`;
28165
+ }
28166
+ url2.pathname = channelPath;
28167
+ url2.search = "";
28168
+ url2.hash = "";
28169
+ return url2;
28170
+ }
28171
+ function uploadError(code, message, cause) {
28172
+ return new RuntimeArtifactUploadError(code, message, cause === void 0 ? {} : { cause });
28173
+ }
28174
+ function translateSdkError(cause) {
28175
+ if (cause instanceof MobiusValidationError) {
28176
+ throw uploadError("artifact_upload_failed", cause.message, cause);
28177
+ }
28178
+ if (cause instanceof MobiusProtocolError) {
28179
+ throw uploadError("artifact_upload_failed", "The Relay returned an invalid upload response", cause);
28180
+ }
28181
+ throw cause;
28182
+ }
28183
+ async function readJson(response) {
28184
+ try {
28185
+ return await response.json();
28186
+ } catch (cause) {
28187
+ throw uploadError("artifact_upload_failed", "The Relay returned an invalid upload response", cause);
28188
+ }
28189
+ }
28190
+ async function readAuthorization(response) {
28191
+ try {
28192
+ return decodeMobiusArtifactUpload(await readJson(response));
28193
+ } catch (cause) {
28194
+ translateSdkError(cause);
28195
+ }
28196
+ }
28197
+ function sessionArtifactUrl(origin, sessionId, resourcePath, token) {
28198
+ const url2 = new URL(`${origin.pathname}/sessions/${encodeURIComponent(sessionId)}/${resourcePath}`, origin);
28199
+ url2.searchParams.set("token", token);
28200
+ return url2;
28201
+ }
28202
+ async function postLease(url2, request, signal) {
28203
+ return await fetch4(url2, {
28204
+ dispatcher: environmentProxyDispatcher,
28205
+ headers: { "content-type": "application/json" },
28206
+ method: "POST",
28207
+ body: JSON.stringify(request),
28208
+ signal
28209
+ });
28210
+ }
28211
+ async function putContent(url2, authorization, bytes, signal) {
28212
+ return await fetch4(url2, {
28213
+ dispatcher: environmentProxyDispatcher,
28214
+ headers: {
28215
+ "content-type": authorization.mediaType,
28216
+ "x-mobius-upload-token": authorization.uploadToken
28217
+ },
28218
+ method: "PUT",
28219
+ body: bytes,
28220
+ signal
28221
+ });
28222
+ }
28223
+ async function uploadRuntimeArtifact(config2, sessionId, image, signal) {
28224
+ signal.throwIfAborted();
28225
+ let request;
28226
+ try {
28227
+ request = new MobiusArtifactUploadRequest(
28228
+ image.name,
28229
+ image.mimeType,
28230
+ image.bytes.byteLength,
28231
+ createHash2("sha256").update(image.bytes).digest("hex")
28232
+ );
28233
+ } catch (cause) {
28234
+ translateSdkError(cause);
28235
+ }
28236
+ const timeoutSignal = AbortSignal.timeout(UPLOAD_TIMEOUT_MILLISECONDS);
28237
+ const requestSignal = AbortSignal.any([signal, timeoutSignal]);
28238
+ const origin = channelOrigin(config2);
28239
+ const token = daemonToken(config2);
28240
+ let created;
28241
+ try {
28242
+ created = await postLease(
28243
+ sessionArtifactUrl(origin, sessionId, "artifacts/uploads", token),
28244
+ request,
28245
+ requestSignal
28246
+ );
28247
+ } catch (cause) {
28248
+ signal.throwIfAborted();
28249
+ throw uploadError(
28250
+ timeoutSignal.aborted ? "artifact_upload_timeout" : "artifact_upload_failed",
28251
+ timeoutSignal.aborted ? "The artifact upload authorization timed out" : "The artifact upload could not start",
28252
+ cause
28253
+ );
28254
+ }
28255
+ if (!created.ok) {
28256
+ await created.body?.cancel();
28257
+ throw uploadError("artifact_upload_rejected", "The Relay rejected the artifact upload");
28258
+ }
28259
+ const authorization = await readAuthorization(created);
28260
+ let uploaded;
28261
+ try {
28262
+ uploaded = await putContent(
28263
+ sessionArtifactUrl(
28264
+ origin,
28265
+ sessionId,
28266
+ `artifacts/${encodeURIComponent(authorization.artifactId)}/content`,
28267
+ token
28268
+ ),
28269
+ authorization,
28270
+ image.bytes,
28271
+ requestSignal
28272
+ );
28273
+ } catch (cause) {
28274
+ signal.throwIfAborted();
28275
+ throw uploadError(
28276
+ timeoutSignal.aborted ? "artifact_upload_timeout" : "artifact_upload_failed",
28277
+ timeoutSignal.aborted ? "The artifact upload timed out" : "The artifact content could not be uploaded",
28278
+ cause
28279
+ );
28280
+ }
28281
+ if (!uploaded.ok) {
28282
+ await uploaded.body?.cancel();
28283
+ throw uploadError("artifact_upload_rejected", "The Relay rejected the artifact content");
28284
+ }
28285
+ try {
28286
+ const available = decodeMobiusAvailableArtifact(await readJson(uploaded));
28287
+ return new UploadedRuntimeArtifact(
28288
+ available.artifactId,
28289
+ available.name,
28290
+ available.mediaType,
28291
+ available.byteLength,
28292
+ available.sha256
28293
+ );
28294
+ } catch (cause) {
28295
+ translateSdkError(cause);
28296
+ }
28297
+ }
28298
+
28299
+ // src/authorization/local-authorization-error.ts
28300
+ var LocalAuthorizationError = class extends Error {
28301
+ code = "local_authorization_failed";
28302
+ constructor(message, options = {}) {
28303
+ super(message, options);
28304
+ this.name = "LocalAuthorizationError";
28305
+ }
28306
+ };
28307
+
28308
+ // src/authorization/workspace-directory.ts
28309
+ import { readdir, realpath as realpath8, stat as stat7 } from "node:fs/promises";
28310
+ import { homedir as homedir2 } from "node:os";
28311
+ import { basename as basename3, dirname as dirname5, isAbsolute as isAbsolute8, join as join15, normalize as normalize3, relative as relative5 } from "node:path";
28312
+ var WorkspaceDirectoryListing = class {
28313
+ directoryId;
28314
+ directoryLabel;
28315
+ entries;
28316
+ parentDirectoryId;
28317
+ constructor(directoryId2, directoryLabel, entries, parentDirectoryId) {
28318
+ this.directoryId = directoryId2;
28319
+ this.directoryLabel = directoryLabel;
28320
+ this.entries = entries;
28321
+ this.parentDirectoryId = parentDirectoryId;
28322
+ }
28323
+ };
28324
+ function encodePath(path2) {
28325
+ const encoded = Buffer.from(path2, "utf8").toString("base64url");
28326
+ if (encoded.length === 0 || encoded.length > 2e3) {
28327
+ throw new LocalAuthorizationError("The local directory path is too long to select");
28328
+ }
28329
+ return `path-${encoded}`;
28330
+ }
28331
+ function decodePath(value, prefix) {
28332
+ const encoded = value.slice(prefix.length);
28333
+ if (encoded.length === 0 || encoded.length > 2e3 || !/^[a-zA-Z0-9_-]+$/.test(encoded)) {
28334
+ throw new LocalAuthorizationError("The directory identifier is invalid");
28335
+ }
28336
+ const decoded = Buffer.from(encoded, "base64url").toString("utf8");
28337
+ if (Buffer.from(decoded, "utf8").toString("base64url") !== encoded || decoded.includes("\0") || normalize3(decoded) !== decoded) {
28338
+ throw new LocalAuthorizationError("The directory identifier is invalid");
28339
+ }
28340
+ return decoded;
28341
+ }
28342
+ var WorkspaceDirectoryService = class {
28343
+ #bindingId;
28344
+ #defaultWorkspace;
28345
+ constructor(bindingId, defaultWorkspace) {
28346
+ this.#bindingId = bindingId;
28347
+ this.#defaultWorkspace = defaultWorkspace;
28348
+ }
28349
+ authorizeMachine = (bindingId) => {
28350
+ if (bindingId !== this.#bindingId) {
28351
+ throw new LocalAuthorizationError("The runtime binding is not authorized");
28352
+ }
28353
+ };
28354
+ requestedPath = (id) => {
28355
+ if (id === "default") {
28356
+ return this.#defaultWorkspace;
28357
+ }
28358
+ if (id === "home") {
28359
+ return homedir2();
28360
+ }
28361
+ if (id.startsWith("path-")) {
28362
+ const path2 = decodePath(id, "path-");
28363
+ if (isAbsolute8(path2)) {
28364
+ return path2;
28365
+ }
28366
+ }
28367
+ throw new LocalAuthorizationError("The directory identifier is invalid");
28368
+ };
28369
+ resolvePath = async (requested, signal) => {
28370
+ signal.throwIfAborted();
28371
+ if (!isAbsolute8(requested) || requested.includes("\0") || normalize3(requested) !== requested) {
28372
+ throw new LocalAuthorizationError("The local directory path is invalid");
28373
+ }
28374
+ try {
28375
+ const target = await realpath8(requested);
28376
+ signal.throwIfAborted();
28377
+ const metadata = await stat7(target);
28378
+ signal.throwIfAborted();
28379
+ if (!isAbsolute8(target) || normalize3(target) !== target || !metadata.isDirectory()) {
28380
+ throw new LocalAuthorizationError("The selected location is not a directory");
28381
+ }
28382
+ return target;
28383
+ } catch (cause) {
28384
+ signal.throwIfAborted();
28385
+ if (cause instanceof LocalAuthorizationError) {
28386
+ throw cause;
28387
+ }
28388
+ throw new LocalAuthorizationError("This directory is missing or unavailable to your user account", {
28389
+ cause
28390
+ });
28391
+ }
28392
+ };
28393
+ label = (path2) => {
28394
+ const suffix = relative5(homedir2(), path2);
28395
+ return suffix === "" ? "~" : !isAbsolute8(suffix) && suffix !== ".." && !suffix.startsWith(`..${process.platform === "win32" ? "\\" : "/"}`) ? `~/${suffix.replaceAll("\\", "/")}` : path2;
28396
+ };
28397
+ identify = async (bindingId, requestedPath, signal) => {
28398
+ this.authorizeMachine(bindingId);
28399
+ const path2 = await this.resolvePath(requestedPath, signal);
28400
+ return {
28401
+ path: path2,
28402
+ directoryId: encodePath(path2),
28403
+ name: basename3(path2) || path2,
28404
+ label: this.label(path2)
28405
+ };
28406
+ };
27682
28407
  resolve = async (bindingId, id, signal) => {
27683
28408
  this.authorizeMachine(bindingId);
27684
28409
  return await this.resolvePath(this.requestedPath(id), signal);
@@ -27732,8 +28457,8 @@ var WorkspaceDirectoryService = class {
27732
28457
  };
27733
28458
 
27734
28459
  // src/bots/local-bot-grant-store.ts
27735
- import { createHash as createHash2, randomUUID as randomUUID3 } from "node:crypto";
27736
- import { stat as stat7 } from "node:fs/promises";
28460
+ import { createHash as createHash3, randomUUID as randomUUID3 } from "node:crypto";
28461
+ import { stat as stat8 } from "node:fs/promises";
27737
28462
  import { DatabaseSync as DatabaseSync3 } from "node:sqlite";
27738
28463
  var LOCAL_BOT_GRANT_LIFETIME_MILLISECONDS = 90 * 24 * 60 * 60 * 1e3;
27739
28464
  var LocalBotAuthorizationError = class extends Error {
@@ -27777,7 +28502,7 @@ var LocalBotGrant = class {
27777
28502
  }
27778
28503
  };
27779
28504
  function digest(value) {
27780
- return createHash2("sha256").update(value, "utf8").digest("hex");
28505
+ return createHash3("sha256").update(value, "utf8").digest("hex");
27781
28506
  }
27782
28507
  function agentDigest(agent) {
27783
28508
  return digest(
@@ -27791,7 +28516,7 @@ function agentDigest(agent) {
27791
28516
  );
27792
28517
  }
27793
28518
  async function workspaceDigest(path2) {
27794
- const metadata = await stat7(path2);
28519
+ const metadata = await stat8(path2);
27795
28520
  if (!metadata.isDirectory()) {
27796
28521
  throw new LocalBotAuthorizationError("binding_incompatible", "The Bot workspace is not a directory");
27797
28522
  }
@@ -28208,12 +28933,12 @@ var BotExecutionContextRegistry = class {
28208
28933
  // src/bots/bot-outbound-ipc.ts
28209
28934
  import { chmod as chmod2, mkdir as mkdir4, unlink } from "node:fs/promises";
28210
28935
  import { createServer } from "node:net";
28211
- import { dirname as dirname6, isAbsolute as isAbsolute8 } from "node:path";
28212
- import { fetch as fetch4 } from "undici";
28936
+ import { dirname as dirname6, isAbsolute as isAbsolute9 } from "node:path";
28937
+ import { fetch as fetch5 } from "undici";
28213
28938
  var BOT_IPC_REQUEST_LIMIT = 32 * 1024;
28214
28939
  var BOT_IPC_TIMEOUT_MILLISECONDS2 = 2e4;
28215
28940
  var BOT_RELAY_TIMEOUT_MILLISECONDS = 2e4;
28216
- var IDENTIFIER_PATTERN6 = /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/;
28941
+ var IDENTIFIER_PATTERN7 = /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/;
28217
28942
  var WINDOWS_NAMED_PIPE_PREFIX = "\\\\.\\pipe\\";
28218
28943
  var BotOutboundIpcRequest = class {
28219
28944
  contextHandle;
@@ -28227,7 +28952,7 @@ var BotOutboundIpcRequest = class {
28227
28952
  this.text = text;
28228
28953
  }
28229
28954
  };
28230
- function isRecord11(value) {
28955
+ function isRecord12(value) {
28231
28956
  return typeof value === "object" && value !== null && !Array.isArray(value);
28232
28957
  }
28233
28958
  function decodeRequest(encoded) {
@@ -28237,7 +28962,7 @@ function decodeRequest(encoded) {
28237
28962
  } catch (cause) {
28238
28963
  throw new LocalBotAuthorizationError("invalid_request", "The local Bot request is invalid", { cause });
28239
28964
  }
28240
- if (!isRecord11(value)) {
28965
+ if (!isRecord12(value)) {
28241
28966
  throw new LocalBotAuthorizationError("invalid_request", "The local Bot request is invalid");
28242
28967
  }
28243
28968
  const keys = Object.keys(value);
@@ -28248,7 +28973,7 @@ function decodeRequest(encoded) {
28248
28973
  const idempotencyKey = value["idempotencyKey"];
28249
28974
  const target = value["target"];
28250
28975
  const text = value["text"];
28251
- if (typeof contextHandle !== "string" || !/^ctx_[a-zA-Z0-9_-]{43}$/.test(contextHandle) || typeof idempotencyKey !== "string" || !IDENTIFIER_PATTERN6.test(idempotencyKey) || typeof target !== "string" || !IDENTIFIER_PATTERN6.test(target) || typeof text !== "string" || text.trim().length === 0 || text.length > 1e4) {
28976
+ if (typeof contextHandle !== "string" || !/^ctx_[a-zA-Z0-9_-]{43}$/.test(contextHandle) || typeof idempotencyKey !== "string" || !IDENTIFIER_PATTERN7.test(idempotencyKey) || typeof target !== "string" || !IDENTIFIER_PATTERN7.test(target) || typeof text !== "string" || text.trim().length === 0 || text.length > 1e4) {
28252
28977
  throw new LocalBotAuthorizationError("invalid_request", "The local Bot request is invalid");
28253
28978
  }
28254
28979
  return new BotOutboundIpcRequest(contextHandle, idempotencyKey, target, text);
@@ -28270,7 +28995,7 @@ function relayEndpoint(relayUrl, context, target) {
28270
28995
  endpoint.pathname = `${MOBIUS_API_PREFIX}/v1/bot-executions/${execution}/delivery-targets/${encodeURIComponent(deliveryTargetId)}/messages`;
28271
28996
  return endpoint;
28272
28997
  }
28273
- function daemonToken(relayUrl) {
28998
+ function daemonToken2(relayUrl) {
28274
28999
  const token = relayUrl.searchParams.get("token") ?? "";
28275
29000
  if (!/^[a-zA-Z0-9_-]{32,256}$/.test(token)) {
28276
29001
  throw new LocalBotAuthorizationError("bot_service_unavailable", "The Runtime credential is unavailable");
@@ -28287,10 +29012,10 @@ async function decodeRelayResponse(response) {
28287
29012
  cause
28288
29013
  });
28289
29014
  }
28290
- if (response.status === 202 && isRecord11(value) && typeof value["outboundMessageId"] === "string") {
29015
+ if (response.status === 202 && isRecord12(value) && typeof value["outboundMessageId"] === "string") {
28291
29016
  return value["outboundMessageId"];
28292
29017
  }
28293
- if (isRecord11(value) && isRecord11(value["error"])) {
29018
+ if (isRecord12(value) && isRecord12(value["error"])) {
28294
29019
  const error61 = value["error"];
28295
29020
  if (typeof error61["code"] === "string" && typeof error61["message"] === "string") {
28296
29021
  throw new LocalBotAuthorizationError(error61["code"], error61["message"]);
@@ -28306,7 +29031,7 @@ var BotOutboundIpcServer = class {
28306
29031
  #usesFilesystemSocket;
28307
29032
  constructor(socketPath, relayUrl, registry2) {
28308
29033
  const usesFilesystemSocket = !socketPath.startsWith(WINDOWS_NAMED_PIPE_PREFIX);
28309
- if (usesFilesystemSocket && !isAbsolute8(socketPath)) {
29034
+ if (usesFilesystemSocket && !isAbsolute9(socketPath)) {
28310
29035
  throw new Error("The Bot IPC path must be absolute");
28311
29036
  }
28312
29037
  this.#registry = registry2;
@@ -28323,7 +29048,7 @@ var BotOutboundIpcServer = class {
28323
29048
  if (this.#usesFilesystemSocket) {
28324
29049
  await mkdir4(dirname6(this.#socketPath), { mode: 448, recursive: true });
28325
29050
  await unlink(this.#socketPath).catch((error61) => {
28326
- if (!isRecord11(error61) || error61["code"] !== "ENOENT") {
29051
+ if (!isRecord12(error61) || error61["code"] !== "ENOENT") {
28327
29052
  throw error61;
28328
29053
  }
28329
29054
  });
@@ -28358,7 +29083,7 @@ var BotOutboundIpcServer = class {
28358
29083
  }
28359
29084
  if (this.#usesFilesystemSocket) {
28360
29085
  await unlink(this.#socketPath).catch((error61) => {
28361
- if (!isRecord11(error61) || error61["code"] !== "ENOENT") {
29086
+ if (!isRecord12(error61) || error61["code"] !== "ENOENT") {
28362
29087
  throw error61;
28363
29088
  }
28364
29089
  });
@@ -28422,10 +29147,10 @@ var BotOutboundIpcServer = class {
28422
29147
  const requestSignal = AbortSignal.any([signal, timeout]);
28423
29148
  let response;
28424
29149
  try {
28425
- response = await fetch4(relayEndpoint(this.#relayUrl, context, request.target), {
29150
+ response = await fetch5(relayEndpoint(this.#relayUrl, context, request.target), {
28426
29151
  body: JSON.stringify({ idempotencyKey: request.idempotencyKey, text: request.text }),
28427
29152
  headers: {
28428
- authorization: `Bearer ${daemonToken(this.#relayUrl)}`,
29153
+ authorization: `Bearer ${daemonToken2(this.#relayUrl)}`,
28429
29154
  "content-type": "application/json",
28430
29155
  "x-mobius-bot-execution-capability": context.command.executionCapabilitySecret
28431
29156
  },
@@ -28446,7 +29171,7 @@ var BotOutboundIpcServer = class {
28446
29171
 
28447
29172
  // src/native-sessions/service.ts
28448
29173
  import { randomUUID as randomUUID4 } from "node:crypto";
28449
- import { basename as basename3 } from "node:path";
29174
+ import { basename as basename4 } from "node:path";
28450
29175
 
28451
29176
  // src/native-sessions/codex-history.ts
28452
29177
  import { spawn as spawn4 } from "node:child_process";
@@ -28479,7 +29204,6 @@ function decodeHistory(thread, value) {
28479
29204
  const page = turnsSchema.parse(value);
28480
29205
  const messages = [];
28481
29206
  let characters = 0;
28482
- let imageCharacters = 0;
28483
29207
  let truncated = page.nextCursor != null;
28484
29208
  for (const turn of page.data.toReversed()) {
28485
29209
  for (const item of turn.items) {
@@ -28487,22 +29211,19 @@ function decodeHistory(thread, value) {
28487
29211
  let message;
28488
29212
  if (type === "userMessage") {
28489
29213
  const { content } = userMessageSchema.parse(item);
28490
- const parsed = parseNativeHistoryText(
28491
- content.map((block) => {
28492
- const { type: type2 } = itemTypeSchema.parse(block);
28493
- if (type2 === "text") {
28494
- return textSchema.parse(block).text;
28495
- }
28496
- if (type2 === "image") {
28497
- return `[@image](${imageSchema.parse(block).url})`;
28498
- }
28499
- return "[Attachment]";
28500
- }).join("")
28501
- );
29214
+ const text2 = content.map((block) => {
29215
+ const { type: type2 } = itemTypeSchema.parse(block);
29216
+ if (type2 === "text") {
29217
+ return textSchema.parse(block).text;
29218
+ }
29219
+ if (type2 === "image") {
29220
+ return `[@image](${imageSchema.parse(block).url})`;
29221
+ }
29222
+ return "[Attachment]";
29223
+ }).join("");
28502
29224
  message = {
28503
29225
  role: "user",
28504
- text: parsed.text,
28505
- ...parsed.images.length > 0 ? { images: parsed.images } : {}
29226
+ text: text2
28506
29227
  };
28507
29228
  } else if (type === "agentMessage") {
28508
29229
  const agent = agentMessageSchema.parse(item);
@@ -28520,12 +29241,10 @@ function decodeHistory(thread, value) {
28520
29241
  truncated ||= text.length < message.text.length;
28521
29242
  messages.push({ ...message, text });
28522
29243
  characters += text.length;
28523
- imageCharacters += (message.images ?? []).reduce((size, image) => size + image.data.length, 0);
28524
- while (messages.length > SESSION_HISTORY_PREVIEW_MESSAGE_LIMIT || characters > SESSION_HISTORY_CHARACTER_LIMIT || imageCharacters > SESSION_HISTORY_IMAGE_CHARACTER_LIMIT) {
29244
+ while (messages.length > SESSION_HISTORY_PREVIEW_MESSAGE_LIMIT || characters > SESSION_HISTORY_CHARACTER_LIMIT) {
28525
29245
  const removed = messages.shift();
28526
29246
  if (removed !== void 0) {
28527
29247
  characters -= removed.text.length;
28528
- imageCharacters -= (removed.images ?? []).reduce((size, image) => size + image.data.length, 0);
28529
29248
  }
28530
29249
  truncated = true;
28531
29250
  }
@@ -28683,7 +29402,11 @@ async function readCodexHistory(agent, cwd, nativeSessionId, signal) {
28683
29402
  params: { clientInfo: { name: "mobius_history", version: "1.0.0" } }
28684
29403
  });
28685
29404
  }
28686
- return await response.promise;
29405
+ const snapshot = await response.promise;
29406
+ return {
29407
+ ...snapshot,
29408
+ history: await embedLocalHistoryImages(snapshot.history, [cwd, snapshot.cwd], signal)
29409
+ };
28687
29410
  } finally {
28688
29411
  clearTimeout(timeout);
28689
29412
  signal.removeEventListener("abort", abort);
@@ -28937,7 +29660,7 @@ var NativeSessionService = class {
28937
29660
  }
28938
29661
  resolvedPaths.add(path2);
28939
29662
  additionalDirectories.push(path2);
28940
- additionalEntries.push({ directoryId: directoryId2, name: basename3(path2) });
29663
+ additionalEntries.push({ directoryId: directoryId2, name: basename4(path2) });
28941
29664
  }
28942
29665
  const listing = await this.#directories.list(this.#config.bindingId, command.directoryId, signal);
28943
29666
  const opened = await this.#sessions.forkSessionAtTurn(
@@ -29076,13 +29799,13 @@ var NativeSessionService = class {
29076
29799
  };
29077
29800
 
29078
29801
  // src/prompt-artifact-resolver.ts
29079
- import { createHash as createHash3 } from "node:crypto";
29080
- import { fetch as fetch5 } from "undici";
29802
+ import { createHash as createHash4 } from "node:crypto";
29803
+ import { fetch as fetch6 } from "undici";
29081
29804
  var ARTIFACT_SCHEME = "mobius-artifact:";
29082
29805
  var ARTIFACT_DOWNLOAD_TIMEOUT_MILLISECONDS = 2e4;
29083
29806
  var MAX_AGENT_IMAGE_BASE64_LENGTH = 4e6;
29084
29807
  var MAX_AGENT_RESOURCE_BYTE_LENGTH = 1e6;
29085
- var IDENTIFIER_PATTERN7 = /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/;
29808
+ var IDENTIFIER_PATTERN8 = /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/;
29086
29809
  var PromptArtifactError = class extends Error {
29087
29810
  code;
29088
29811
  constructor(code, message, options = {}) {
@@ -29125,14 +29848,13 @@ function parseReference(resource) {
29125
29848
  const encodedByteLength2 = url2.searchParams.get("byteLength") ?? "";
29126
29849
  const sha256 = url2.searchParams.get("sha256") ?? "";
29127
29850
  const byteLength = Number(encodedByteLength2);
29128
- if (url2.protocol !== ARTIFACT_SCHEME || url2.hash.length > 0 || resource.type !== "link" || resource.text.length > 0 || !IDENTIFIER_PATTERN7.test(artifactId) || keys.length !== 2 || keys[0] !== "byteLength" || keys[1] !== "sha256" || !/^[1-9][0-9]*$/.test(encodedByteLength2) || !Number.isSafeInteger(byteLength) || !/^[a-f0-9]{64}$/.test(sha256)) {
29851
+ if (url2.protocol !== ARTIFACT_SCHEME || url2.hash.length > 0 || resource.type !== "link" || resource.text.length > 0 || !IDENTIFIER_PATTERN8.test(artifactId) || keys.length !== 2 || keys[0] !== "byteLength" || keys[1] !== "sha256" || !/^[1-9][0-9]*$/.test(encodedByteLength2) || !Number.isSafeInteger(byteLength) || !/^[a-f0-9]{64}$/.test(sha256)) {
29129
29852
  throw new PromptArtifactError("artifact_reference_invalid", "The prompt artifact reference is invalid");
29130
29853
  }
29131
29854
  return new PromptArtifactReference(artifactId, byteLength, sha256, resource);
29132
29855
  }
29133
29856
  function downloadUrl(config2, command, reference) {
29134
- const url2 = new URL(config2.relayUrl);
29135
- url2.protocol = url2.protocol === "wss:" ? "https:" : "http:";
29857
+ const url2 = relayHttpEndpoint(config2.relayUrl);
29136
29858
  let channelPath = "";
29137
29859
  if (url2.pathname.endsWith("/daemon")) {
29138
29860
  channelPath = url2.pathname.slice(0, -"/daemon".length);
@@ -29144,7 +29866,6 @@ function downloadUrl(config2, command, reference) {
29144
29866
  channelPath = `${url2.pathname.slice(0, -runtimePath.length)}/channels/${encodeURIComponent(config2.channelId)}`;
29145
29867
  }
29146
29868
  url2.pathname = `${channelPath}/sessions/${encodeURIComponent(command.sessionId)}/commands/${encodeURIComponent(command.commandId)}/artifacts/${encodeURIComponent(reference.artifactId)}/content`;
29147
- url2.searchParams.delete("liveness");
29148
29869
  return url2;
29149
29870
  }
29150
29871
  async function responseBytes(response, expectedByteLength, signal) {
@@ -29193,9 +29914,13 @@ async function download(config2, command, reference, signal) {
29193
29914
  const requestSignal = AbortSignal.any([signal, timeoutSignal]);
29194
29915
  let response;
29195
29916
  try {
29196
- response = await fetch5(downloadUrl(config2, command, reference), {
29917
+ response = await fetch6(downloadUrl(config2, command, reference), {
29197
29918
  dispatcher: environmentProxyDispatcher,
29198
- headers: { accept: reference.resource.mimeType },
29919
+ headers: {
29920
+ accept: reference.resource.mimeType,
29921
+ "accept-encoding": "identity",
29922
+ ...runtimeAuthorization(config2.relayUrl)
29923
+ },
29199
29924
  signal: requestSignal
29200
29925
  });
29201
29926
  if (!response.ok) {
@@ -29213,7 +29938,7 @@ async function download(config2, command, reference, signal) {
29213
29938
  );
29214
29939
  }
29215
29940
  const bytes = await responseBytes(response, reference.byteLength, requestSignal);
29216
- if (createHash3("sha256").update(bytes).digest("hex") !== reference.sha256) {
29941
+ if (createHash4("sha256").update(bytes).digest("hex") !== reference.sha256) {
29217
29942
  throw new PromptArtifactError(
29218
29943
  "artifact_integrity_failed",
29219
29944
  "The prompt artifact failed integrity validation"
@@ -29305,12 +30030,8 @@ function connectRelay(url2, signal) {
29305
30030
  signal.throwIfAborted();
29306
30031
  return new Promise((resolve5, reject) => {
29307
30032
  const endpoint = new URL(url2);
29308
- const headers = {};
29309
- if (endpoint.pathname.endsWith("/v1/runtimes/connect")) {
29310
- const runtimeCredential = endpoint.searchParams.get("token") ?? "";
29311
- endpoint.searchParams.delete("token");
29312
- headers["authorization"] = `Bearer ${runtimeCredential}`;
29313
- }
30033
+ const headers = runtimeAuthorization(endpoint);
30034
+ endpoint.searchParams.delete("token");
29314
30035
  const socket = new WebSocket(endpoint, {
29315
30036
  dispatcher: environmentProxyDispatcher,
29316
30037
  headers
@@ -29633,6 +30354,42 @@ var RelayConnectionLiveness = class {
29633
30354
  import { mkdirSync as mkdirSync3 } from "node:fs";
29634
30355
  import { dirname as dirname7 } from "node:path";
29635
30356
  import { DatabaseSync as DatabaseSync4 } from "node:sqlite";
30357
+ var DEFAULT_OUTBOX_LIMITS = {
30358
+ criticalEventBytes: 136 * 1024 * 1024,
30359
+ criticalEventCount: 10128,
30360
+ runtimeDeliveryBytes: 64 * 1024 * 1024,
30361
+ runtimeDeliveryCount: 64,
30362
+ standardEventBytes: 128 * 1024 * 1024,
30363
+ standardEventCount: 1e4
30364
+ };
30365
+ var SessionEventOutboxCapacityError = class extends Error {
30366
+ code = "session_event_outbox_full";
30367
+ constructor() {
30368
+ super("The durable Session event outbox is full");
30369
+ this.name = "SessionEventOutboxCapacityError";
30370
+ }
30371
+ };
30372
+ var RuntimeDeliveryInboxCapacityError = class extends Error {
30373
+ code = "runtime_delivery_inbox_full";
30374
+ constructor() {
30375
+ super("The durable Runtime delivery inbox is full");
30376
+ this.name = "RuntimeDeliveryInboxCapacityError";
30377
+ }
30378
+ };
30379
+ var StoredRuntimeDelivery = class {
30380
+ deliveryId;
30381
+ duplicate;
30382
+ payload;
30383
+ sessionId;
30384
+ state;
30385
+ constructor(deliveryId, sessionId, payload, state, duplicate) {
30386
+ this.deliveryId = deliveryId;
30387
+ this.duplicate = duplicate;
30388
+ this.payload = payload;
30389
+ this.sessionId = sessionId;
30390
+ this.state = state;
30391
+ }
30392
+ };
29636
30393
  function readPendingEnvelope(row) {
29637
30394
  if (typeof row !== "object" || row === null || Array.isArray(row)) {
29638
30395
  throw new Error("SQLite returned an invalid session event outbox row");
@@ -29643,9 +30400,26 @@ function readPendingEnvelope(row) {
29643
30400
  }
29644
30401
  return envelope2;
29645
30402
  }
30403
+ function rowNumber(row, field) {
30404
+ const value = typeof row === "object" && row !== null ? Reflect.get(row, field) : void 0;
30405
+ if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0) {
30406
+ throw new Error(`SQLite returned an invalid ${field} value`);
30407
+ }
30408
+ return value;
30409
+ }
30410
+ function rowString2(row, field) {
30411
+ const value = typeof row === "object" && row !== null ? Reflect.get(row, field) : void 0;
30412
+ if (typeof value !== "string" || value.length === 0) {
30413
+ throw new Error(`SQLite returned an invalid ${field} value`);
30414
+ }
30415
+ return value;
30416
+ }
29646
30417
  var SessionEventOutbox = class {
29647
30418
  #database;
29648
- constructor(path2) {
30419
+ #limits;
30420
+ constructor(path2, limits = DEFAULT_OUTBOX_LIMITS) {
30421
+ validateLimits(limits);
30422
+ this.#limits = limits;
29649
30423
  mkdirSync3(dirname7(path2), { recursive: true });
29650
30424
  this.#database = new DatabaseSync4(path2);
29651
30425
  this.#database.exec(`
@@ -29654,6 +30428,7 @@ var SessionEventOutbox = class {
29654
30428
  event_id TEXT NOT NULL UNIQUE,
29655
30429
  session_id TEXT NOT NULL,
29656
30430
  source_key TEXT NOT NULL,
30431
+ byte_length INTEGER NOT NULL,
29657
30432
  envelope_json TEXT NOT NULL
29658
30433
  ) STRICT;
29659
30434
  CREATE INDEX IF NOT EXISTS relay_session_event_outbox_order
@@ -29664,7 +30439,7 @@ var SessionEventOutbox = class {
29664
30439
  session_id TEXT NOT NULL,
29665
30440
  envelope_json TEXT NOT NULL,
29666
30441
  rejection_code TEXT NOT NULL CHECK (
29667
- rejection_code IN ('session_deleted', 'session_not_found')
30442
+ rejection_code IN ('session_deleted', 'session_not_found', 'session_rejected')
29668
30443
  )
29669
30444
  ) STRICT;
29670
30445
  CREATE TABLE IF NOT EXISTS relay_session_event_sources (
@@ -29680,7 +30455,53 @@ var SessionEventOutbox = class {
29680
30455
  state IN ('dispatching', 'running', 'succeeded', 'failed', 'cancelled')
29681
30456
  )
29682
30457
  ) STRICT;
30458
+ CREATE TABLE IF NOT EXISTS relay_session_event_outbox_state (
30459
+ singleton INTEGER PRIMARY KEY CHECK (singleton = 1),
30460
+ event_count INTEGER NOT NULL,
30461
+ total_bytes INTEGER NOT NULL
30462
+ ) STRICT;
30463
+ INSERT OR IGNORE INTO relay_session_event_outbox_state (
30464
+ singleton, event_count, total_bytes
30465
+ ) VALUES (1, 0, 0);
30466
+ CREATE TABLE IF NOT EXISTS relay_runtime_deliveries (
30467
+ delivery_id TEXT PRIMARY KEY,
30468
+ session_id TEXT NOT NULL,
30469
+ payload_json TEXT NOT NULL,
30470
+ payload_bytes INTEGER NOT NULL,
30471
+ state TEXT NOT NULL CHECK (
30472
+ state IN ('received', 'relay_committed', 'processed')
30473
+ ),
30474
+ received_at INTEGER NOT NULL
30475
+ ) STRICT;
29683
30476
  `);
30477
+ const deadLetterTable = this.#database.prepare(
30478
+ `SELECT sql FROM sqlite_master
30479
+ WHERE type = 'table' AND name = 'relay_session_event_dead_letters'`
30480
+ ).get();
30481
+ const deadLetterSql = typeof deadLetterTable === "object" && deadLetterTable !== null ? Reflect.get(deadLetterTable, "sql") : void 0;
30482
+ if (typeof deadLetterSql !== "string" || !deadLetterSql.includes("'session_rejected'")) {
30483
+ this.#database.exec(`
30484
+ BEGIN IMMEDIATE;
30485
+ ALTER TABLE relay_session_event_dead_letters
30486
+ RENAME TO relay_session_event_dead_letters_legacy;
30487
+ CREATE TABLE relay_session_event_dead_letters (
30488
+ ordinal INTEGER PRIMARY KEY,
30489
+ event_id TEXT NOT NULL UNIQUE,
30490
+ session_id TEXT NOT NULL,
30491
+ envelope_json TEXT NOT NULL,
30492
+ rejection_code TEXT NOT NULL CHECK (
30493
+ rejection_code IN ('session_deleted', 'session_not_found', 'session_rejected')
30494
+ )
30495
+ ) STRICT;
30496
+ INSERT INTO relay_session_event_dead_letters (
30497
+ ordinal, event_id, session_id, envelope_json, rejection_code
30498
+ )
30499
+ SELECT ordinal, event_id, session_id, envelope_json, rejection_code
30500
+ FROM relay_session_event_dead_letters_legacy;
30501
+ DROP TABLE relay_session_event_dead_letters_legacy;
30502
+ COMMIT;
30503
+ `);
30504
+ }
29684
30505
  const outboxColumns = this.#database.prepare("PRAGMA table_info(relay_session_event_outbox)").all();
29685
30506
  const hasSourceKey = outboxColumns.some(
29686
30507
  (column) => typeof column === "object" && column !== null && Reflect.get(column, "name") === "source_key"
@@ -29691,6 +30512,15 @@ var SessionEventOutbox = class {
29691
30512
  ADD COLUMN source_key TEXT NOT NULL DEFAULT '';
29692
30513
  `);
29693
30514
  }
30515
+ const hasByteLength = outboxColumns.some(
30516
+ (column) => typeof column === "object" && column !== null && Reflect.get(column, "name") === "byte_length"
30517
+ );
30518
+ if (!hasByteLength) {
30519
+ this.#database.exec(`
30520
+ ALTER TABLE relay_session_event_outbox
30521
+ ADD COLUMN byte_length INTEGER NOT NULL DEFAULT 0;
30522
+ `);
30523
+ }
29694
30524
  this.#database.exec(`
29695
30525
  UPDATE relay_session_event_outbox
29696
30526
  SET source_key = CASE json_extract(envelope_json, '$.source.kind')
@@ -29699,6 +30529,16 @@ var SessionEventOutbox = class {
29699
30529
  ELSE 'runtime:' || session_id
29700
30530
  END
29701
30531
  WHERE source_key = '';
30532
+ UPDATE relay_session_event_outbox
30533
+ SET byte_length = length(CAST(envelope_json AS BLOB))
30534
+ WHERE byte_length = 0;
30535
+ UPDATE relay_session_event_outbox_state
30536
+ SET event_count = (SELECT COUNT(*) FROM relay_session_event_outbox),
30537
+ total_bytes = (
30538
+ SELECT COALESCE(SUM(byte_length), 0)
30539
+ FROM relay_session_event_outbox
30540
+ )
30541
+ WHERE singleton = 1;
29702
30542
  CREATE INDEX IF NOT EXISTS relay_session_event_outbox_source_order
29703
30543
  ON relay_session_event_outbox(source_key, ordinal);
29704
30544
  `);
@@ -29759,13 +30599,19 @@ var SessionEventOutbox = class {
29759
30599
  const state = typeof row === "object" && row !== null ? Reflect.get(row, "state") : void 0;
29760
30600
  return state === "succeeded" || state === "failed" || state === "cancelled";
29761
30601
  };
29762
- acknowledge = (acknowledgement) => this.#database.prepare(
29763
- `DELETE FROM relay_session_event_outbox
29764
- WHERE event_id = ? AND session_id = ?`
29765
- ).run(acknowledgement.eventId, acknowledgement.sessionId).changes === 1;
30602
+ acknowledge = (acknowledgement) => this.#removeAcknowledgedEvent(acknowledgement.eventId, acknowledgement.sessionId);
29766
30603
  quarantine = (rejection) => {
29767
30604
  this.#database.exec("BEGIN IMMEDIATE");
29768
30605
  try {
30606
+ const stored = this.#database.prepare(
30607
+ `SELECT byte_length FROM relay_session_event_outbox
30608
+ WHERE event_id = ? AND session_id = ?`
30609
+ ).get(rejection.eventId, rejection.sessionId);
30610
+ if (stored === void 0) {
30611
+ this.#database.exec("COMMIT");
30612
+ return false;
30613
+ }
30614
+ const byteLength = rowNumber(stored, "byte_length");
29769
30615
  const insertion = this.#database.prepare(
29770
30616
  `INSERT INTO relay_session_event_dead_letters (
29771
30617
  ordinal, event_id, session_id, envelope_json, rejection_code
@@ -29785,6 +30631,7 @@ var SessionEventOutbox = class {
29785
30631
  if (deletion.changes !== 1) {
29786
30632
  throw new Error("The rejected session event could not be removed from the durable outbox");
29787
30633
  }
30634
+ this.#decrementEventState(byteLength);
29788
30635
  this.#database.exec("COMMIT");
29789
30636
  return true;
29790
30637
  } catch (error61) {
@@ -29796,7 +30643,129 @@ var SessionEventOutbox = class {
29796
30643
  this.#database.close();
29797
30644
  };
29798
30645
  enqueue = (sessionId, payload, attemptId = null) => {
29799
- const sourceKey = attemptId === null ? `runtime:${sessionId}` : `attempt:${sessionId}:${attemptId}`;
30646
+ return this.#enqueueBounded(
30647
+ sessionId,
30648
+ payload,
30649
+ attemptId ?? "",
30650
+ this.#limits.standardEventCount,
30651
+ this.#limits.standardEventBytes
30652
+ );
30653
+ };
30654
+ enqueueCritical = (sessionId, payload, attemptId = "") => this.#enqueueBounded(
30655
+ sessionId,
30656
+ payload,
30657
+ attemptId,
30658
+ this.#limits.criticalEventCount,
30659
+ this.#limits.criticalEventBytes
30660
+ );
30661
+ claimRuntimeDelivery = (delivery) => {
30662
+ const payloadBytes = new TextEncoder().encode(delivery.payload).byteLength;
30663
+ this.#database.exec("BEGIN IMMEDIATE");
30664
+ try {
30665
+ const existing = this.#database.prepare(
30666
+ `SELECT session_id, payload_json, state
30667
+ FROM relay_runtime_deliveries
30668
+ WHERE delivery_id = ?`
30669
+ ).get(delivery.deliveryId);
30670
+ if (existing !== void 0) {
30671
+ const sessionId = rowString2(existing, "session_id");
30672
+ const payload = rowString2(existing, "payload_json");
30673
+ const state = runtimeDeliveryState(existing);
30674
+ if (sessionId !== delivery.sessionId || payload !== delivery.payload) {
30675
+ throw new Error("The Runtime delivery identity conflicts with its durable receipt");
30676
+ }
30677
+ this.#database.exec("COMMIT");
30678
+ return new StoredRuntimeDelivery(delivery.deliveryId, sessionId, payload, state, true);
30679
+ }
30680
+ const usage = this.#database.prepare(
30681
+ `SELECT COUNT(*) AS delivery_count,
30682
+ COALESCE(SUM(payload_bytes), 0) AS delivery_bytes
30683
+ FROM relay_runtime_deliveries`
30684
+ ).get();
30685
+ if (rowNumber(usage, "delivery_count") + 1 > this.#limits.runtimeDeliveryCount || rowNumber(usage, "delivery_bytes") + payloadBytes > this.#limits.runtimeDeliveryBytes) {
30686
+ throw new RuntimeDeliveryInboxCapacityError();
30687
+ }
30688
+ this.#database.prepare(
30689
+ `INSERT INTO relay_runtime_deliveries (
30690
+ delivery_id, session_id, payload_json, payload_bytes, state, received_at
30691
+ ) VALUES (?, ?, ?, ?, 'received', ?)`
30692
+ ).run(delivery.deliveryId, delivery.sessionId, delivery.payload, payloadBytes, Date.now());
30693
+ this.#database.exec("COMMIT");
30694
+ return new StoredRuntimeDelivery(
30695
+ delivery.deliveryId,
30696
+ delivery.sessionId,
30697
+ delivery.payload,
30698
+ "received",
30699
+ false
30700
+ );
30701
+ } catch (error61) {
30702
+ this.#database.exec("ROLLBACK");
30703
+ throw error61;
30704
+ }
30705
+ };
30706
+ markRuntimeDeliveryCommitted = (deliveryId, sessionId) => {
30707
+ this.#database.exec("BEGIN IMMEDIATE");
30708
+ try {
30709
+ const row = this.#database.prepare(
30710
+ `SELECT state FROM relay_runtime_deliveries
30711
+ WHERE delivery_id = ? AND session_id = ?`
30712
+ ).get(deliveryId, sessionId);
30713
+ if (row === void 0) {
30714
+ this.#database.exec("COMMIT");
30715
+ return false;
30716
+ }
30717
+ const state = runtimeDeliveryState(row);
30718
+ if (state === "processed") {
30719
+ this.#database.prepare(`DELETE FROM relay_runtime_deliveries WHERE delivery_id = ?`).run(deliveryId);
30720
+ } else if (state === "received") {
30721
+ this.#database.prepare(`UPDATE relay_runtime_deliveries SET state = 'relay_committed' WHERE delivery_id = ?`).run(deliveryId);
30722
+ }
30723
+ this.#database.exec("COMMIT");
30724
+ return true;
30725
+ } catch (error61) {
30726
+ this.#database.exec("ROLLBACK");
30727
+ throw error61;
30728
+ }
30729
+ };
30730
+ markRuntimeDeliveryProcessed = (deliveryId, sessionId) => {
30731
+ this.#database.exec("BEGIN IMMEDIATE");
30732
+ try {
30733
+ const row = this.#database.prepare(
30734
+ `SELECT state FROM relay_runtime_deliveries
30735
+ WHERE delivery_id = ? AND session_id = ?`
30736
+ ).get(deliveryId, sessionId);
30737
+ if (row === void 0) {
30738
+ this.#database.exec("COMMIT");
30739
+ return false;
30740
+ }
30741
+ const state = runtimeDeliveryState(row);
30742
+ if (state === "relay_committed") {
30743
+ this.#database.prepare(`DELETE FROM relay_runtime_deliveries WHERE delivery_id = ?`).run(deliveryId);
30744
+ } else if (state === "received") {
30745
+ this.#database.prepare(`UPDATE relay_runtime_deliveries SET state = 'processed' WHERE delivery_id = ?`).run(deliveryId);
30746
+ }
30747
+ this.#database.exec("COMMIT");
30748
+ return true;
30749
+ } catch (error61) {
30750
+ this.#database.exec("ROLLBACK");
30751
+ throw error61;
30752
+ }
30753
+ };
30754
+ runtimeDeliveries = () => this.#database.prepare(
30755
+ `SELECT delivery_id, session_id, payload_json, state
30756
+ FROM relay_runtime_deliveries
30757
+ ORDER BY received_at, delivery_id`
30758
+ ).all().map(
30759
+ (row) => new StoredRuntimeDelivery(
30760
+ rowString2(row, "delivery_id"),
30761
+ rowString2(row, "session_id"),
30762
+ rowString2(row, "payload_json"),
30763
+ runtimeDeliveryState(row),
30764
+ true
30765
+ )
30766
+ );
30767
+ #enqueueBounded = (sessionId, payload, attemptId, maximumEventCount, maximumEventBytes) => {
30768
+ const sourceKey = attemptId.length === 0 ? `runtime:${sessionId}` : `attempt:${sessionId}:${attemptId}`;
29800
30769
  this.#database.exec("BEGIN IMMEDIATE");
29801
30770
  try {
29802
30771
  const row = this.#database.prepare(
@@ -29813,13 +30782,22 @@ var SessionEventOutbox = class {
29813
30782
  kind: SESSION_EVENT_KIND,
29814
30783
  payload,
29815
30784
  sessionId,
29816
- source: attemptId === null ? { kind: "runtime", sourceSeq: nextSourceSeq.toString() } : {
30785
+ source: attemptId.length === 0 ? { kind: "runtime", sourceSeq: nextSourceSeq.toString() } : {
29817
30786
  attemptId,
29818
30787
  kind: "attempt",
29819
30788
  sourceSeq: nextSourceSeq.toString()
29820
30789
  }
29821
30790
  };
29822
30791
  const encoded = encodeSessionEventEnvelope(envelope2);
30792
+ const byteLength = new TextEncoder().encode(encoded).byteLength;
30793
+ const state = this.#database.prepare(
30794
+ `SELECT event_count, total_bytes
30795
+ FROM relay_session_event_outbox_state
30796
+ WHERE singleton = 1`
30797
+ ).get();
30798
+ if (rowNumber(state, "event_count") + 1 > maximumEventCount || rowNumber(state, "total_bytes") + byteLength > maximumEventBytes) {
30799
+ throw new SessionEventOutboxCapacityError();
30800
+ }
29823
30801
  this.#database.prepare(
29824
30802
  `INSERT INTO relay_session_event_sources (
29825
30803
  source_key, next_source_seq
@@ -29829,9 +30807,15 @@ var SessionEventOutbox = class {
29829
30807
  ).run(sourceKey, nextSourceSeq + 1);
29830
30808
  this.#database.prepare(
29831
30809
  `INSERT INTO relay_session_event_outbox (
29832
- event_id, session_id, source_key, envelope_json
29833
- ) VALUES (?, ?, ?, ?)`
29834
- ).run(envelope2.eventId, envelope2.sessionId, sourceKey, encoded);
30810
+ event_id, session_id, source_key, byte_length, envelope_json
30811
+ ) VALUES (?, ?, ?, ?, ?)`
30812
+ ).run(envelope2.eventId, envelope2.sessionId, sourceKey, byteLength, encoded);
30813
+ this.#database.prepare(
30814
+ `UPDATE relay_session_event_outbox_state
30815
+ SET event_count = event_count + 1,
30816
+ total_bytes = total_bytes + ?
30817
+ WHERE singleton = 1`
30818
+ ).run(byteLength);
29835
30819
  this.#database.exec("COMMIT");
29836
30820
  return encoded;
29837
30821
  } catch (error61) {
@@ -29839,6 +30823,44 @@ var SessionEventOutbox = class {
29839
30823
  throw error61;
29840
30824
  }
29841
30825
  };
30826
+ #removeAcknowledgedEvent = (eventId, sessionId) => {
30827
+ this.#database.exec("BEGIN IMMEDIATE");
30828
+ try {
30829
+ const stored = this.#database.prepare(
30830
+ `SELECT byte_length FROM relay_session_event_outbox
30831
+ WHERE event_id = ? AND session_id = ?`
30832
+ ).get(eventId, sessionId);
30833
+ if (stored === void 0) {
30834
+ this.#database.exec("COMMIT");
30835
+ return false;
30836
+ }
30837
+ const byteLength = rowNumber(stored, "byte_length");
30838
+ const deletion = this.#database.prepare(
30839
+ `DELETE FROM relay_session_event_outbox
30840
+ WHERE event_id = ? AND session_id = ?`
30841
+ ).run(eventId, sessionId);
30842
+ if (deletion.changes !== 1) {
30843
+ throw new Error("The acknowledged session event could not be removed from the durable outbox");
30844
+ }
30845
+ this.#decrementEventState(byteLength);
30846
+ this.#database.exec("COMMIT");
30847
+ return true;
30848
+ } catch (error61) {
30849
+ this.#database.exec("ROLLBACK");
30850
+ throw error61;
30851
+ }
30852
+ };
30853
+ #decrementEventState = (byteLength) => {
30854
+ const result = this.#database.prepare(
30855
+ `UPDATE relay_session_event_outbox_state
30856
+ SET event_count = event_count - 1,
30857
+ total_bytes = total_bytes - ?
30858
+ WHERE singleton = 1 AND event_count > 0 AND total_bytes >= ?`
30859
+ ).run(byteLength, byteLength);
30860
+ if (result.changes !== 1) {
30861
+ throw new Error("The Session event outbox capacity state is inconsistent");
30862
+ }
30863
+ };
29842
30864
  pending = () => this.#database.prepare(
29843
30865
  `SELECT envelope_json
29844
30866
  FROM relay_session_event_outbox
@@ -29865,7 +30887,68 @@ var SessionEventOutbox = class {
29865
30887
  LIMIT ?`
29866
30888
  ).all(limit).map(readPendingEnvelope);
29867
30889
  };
30890
+ pendingSourceHeads = (limit, excludedEventIds, excludedSourceKeys) => {
30891
+ if (!Number.isSafeInteger(limit) || limit < 1) {
30892
+ throw new Error("Session event replay batch limit must be a positive integer");
30893
+ }
30894
+ const exclusions = [];
30895
+ const parameters = [];
30896
+ if (excludedEventIds.length > 0) {
30897
+ exclusions.push(`event_id NOT IN (${excludedEventIds.map(() => "?").join(", ")})`);
30898
+ parameters.push(...excludedEventIds);
30899
+ }
30900
+ if (excludedSourceKeys.length > 0) {
30901
+ exclusions.push(`source_key NOT IN (${excludedSourceKeys.map(() => "?").join(", ")})`);
30902
+ parameters.push(...excludedSourceKeys);
30903
+ }
30904
+ parameters.push(limit.toString());
30905
+ const where = exclusions.length === 0 ? "" : `WHERE ${exclusions.join(" AND ")}`;
30906
+ return this.#database.prepare(
30907
+ `WITH available_events AS (
30908
+ SELECT ordinal, source_key
30909
+ FROM relay_session_event_outbox
30910
+ ${where}
30911
+ ), ranked_events AS (
30912
+ SELECT ordinal,
30913
+ ROW_NUMBER() OVER (
30914
+ PARTITION BY source_key
30915
+ ORDER BY ordinal
30916
+ ) AS source_position
30917
+ FROM available_events
30918
+ )
30919
+ SELECT outbox.envelope_json
30920
+ FROM ranked_events AS ranked
30921
+ INNER JOIN relay_session_event_outbox AS outbox
30922
+ ON outbox.ordinal = ranked.ordinal
30923
+ WHERE ranked.source_position = 1
30924
+ ORDER BY outbox.ordinal
30925
+ LIMIT ?`
30926
+ ).all(...parameters).map(readPendingEnvelope);
30927
+ };
29868
30928
  };
30929
+ function validateLimits(limits) {
30930
+ const values = [
30931
+ limits.criticalEventBytes,
30932
+ limits.criticalEventCount,
30933
+ limits.runtimeDeliveryBytes,
30934
+ limits.runtimeDeliveryCount,
30935
+ limits.standardEventBytes,
30936
+ limits.standardEventCount
30937
+ ];
30938
+ if (values.some((value) => !Number.isSafeInteger(value) || value < 1)) {
30939
+ throw new Error("Session event outbox limits must be positive integers");
30940
+ }
30941
+ if (limits.criticalEventBytes < limits.standardEventBytes || limits.criticalEventCount < limits.standardEventCount) {
30942
+ throw new Error("Critical Session event capacity must include the standard capacity");
30943
+ }
30944
+ }
30945
+ function runtimeDeliveryState(row) {
30946
+ const state = rowString2(row, "state");
30947
+ if (state !== "received" && state !== "relay_committed" && state !== "processed") {
30948
+ throw new Error("SQLite returned an invalid Runtime delivery state");
30949
+ }
30950
+ return state;
30951
+ }
29869
30952
  function isDaemonExecutionState(value) {
29870
30953
  return value === "cancelled" || value === "dispatching" || value === "failed" || value === "running" || value === "succeeded";
29871
30954
  }
@@ -29891,10 +30974,23 @@ function botIpcSocketPath() {
29891
30974
  return join16("/tmp", `mobius-bot-${randomUUID6()}.sock`);
29892
30975
  }
29893
30976
  var DaemonAcpObserver = class {
30977
+ #config;
29894
30978
  #record;
29895
- constructor(record2) {
29896
- this.#record = record2;
30979
+ constructor(config2, record3) {
30980
+ this.#config = config2;
30981
+ this.#record = record3;
29897
30982
  }
30983
+ importLocalImage = async (sessionId, image, signal) => {
30984
+ try {
30985
+ return (await uploadRuntimeArtifact(this.#config, sessionId, image, signal)).artifactId;
30986
+ } catch (cause) {
30987
+ signal.throwIfAborted();
30988
+ if (cause instanceof Error && cause.name === "AbortError") {
30989
+ throw cause;
30990
+ }
30991
+ return "";
30992
+ }
30993
+ };
29898
30994
  onCommands = (event) => {
29899
30995
  this.#record(event.sessionId, encodeSessionCommandsUpdatedEvent(event));
29900
30996
  return Promise.resolve();
@@ -30084,8 +31180,7 @@ var ActiveTurnReconciliationError = class extends Error {
30084
31180
  }
30085
31181
  };
30086
31182
  function activeTurnReconciliationEndpoint(config2, turn) {
30087
- const endpoint = new URL(config2.relayUrl);
30088
- endpoint.protocol = endpoint.protocol === "wss:" ? "https:" : "http:";
31183
+ const endpoint = relayHttpEndpoint(config2.relayUrl);
30089
31184
  let channelPath = "";
30090
31185
  if (endpoint.pathname.endsWith("/daemon")) {
30091
31186
  channelPath = endpoint.pathname.slice(0, -"/daemon".length);
@@ -30097,7 +31192,6 @@ function activeTurnReconciliationEndpoint(config2, turn) {
30097
31192
  channelPath = `${endpoint.pathname.slice(0, -runtimePath.length)}/channels/${encodeURIComponent(config2.channelId)}`;
30098
31193
  }
30099
31194
  endpoint.pathname = `${channelPath}/sessions/${encodeURIComponent(turn.command.sessionId)}/attempts/${encodeURIComponent(turn.attemptId)}/reconciliation`;
30100
- endpoint.searchParams.delete("liveness");
30101
31195
  return endpoint;
30102
31196
  }
30103
31197
  async function reconcileActiveTurn(config2, turn, signal) {
@@ -30106,10 +31200,10 @@ async function reconcileActiveTurn(config2, turn, signal) {
30106
31200
  const requestSignal = AbortSignal.any([signal, timeoutSignal]);
30107
31201
  let response;
30108
31202
  try {
30109
- response = await fetch6(activeTurnReconciliationEndpoint(config2, turn), {
31203
+ response = await fetch7(activeTurnReconciliationEndpoint(config2, turn), {
30110
31204
  body: JSON.stringify({ outcome: { kind: "running" } }),
30111
31205
  dispatcher: environmentProxyDispatcher,
30112
- headers: { "content-type": "application/json" },
31206
+ headers: { ...runtimeAuthorization(config2.relayUrl), "content-type": "application/json" },
30113
31207
  method: "POST",
30114
31208
  signal: requestSignal
30115
31209
  });
@@ -30177,17 +31271,31 @@ var ConnectedDaemonSessionEventState = class extends DaemonSessionEventConnectio
30177
31271
  }
30178
31272
  };
30179
31273
  };
30180
- var SESSION_EVENT_REPLAY_WINDOW = 4;
31274
+ var SESSION_EVENT_REPLAY_WINDOW = 16;
31275
+ var SESSION_EVENT_SOURCE_REPLAY_WINDOW = 4;
31276
+ var SESSION_EVENT_REPLAY_BYTE_LIMIT = 32 * 1024 * 1024;
31277
+ var InFlightSessionEvent = class {
31278
+ byteLength;
31279
+ sourceKey;
31280
+ constructor(sourceKey, byteLength) {
31281
+ this.byteLength = byteLength;
31282
+ this.sourceKey = sourceKey;
31283
+ }
31284
+ };
31285
+ function sessionEventSourceKey(envelope2) {
31286
+ return envelope2.source.kind === "attempt" ? `attempt:${envelope2.sessionId}:${envelope2.source.attemptId}` : `runtime:${envelope2.sessionId}`;
31287
+ }
30181
31288
  var DaemonSessionEventPublisher = class {
30182
31289
  #outbox;
30183
- #inFlightEventIds = /* @__PURE__ */ new Set();
31290
+ #inFlightEvents = /* @__PURE__ */ new Map();
31291
+ #inFlightBytes = 0;
30184
31292
  #connection = new DisconnectedDaemonSessionEventState();
30185
31293
  constructor(outbox) {
30186
31294
  this.#outbox = outbox;
30187
31295
  }
30188
31296
  connect = (socket) => {
30189
31297
  this.#connection = new ConnectedDaemonSessionEventState(socket);
30190
- this.#inFlightEventIds.clear();
31298
+ this.#clearInFlight();
30191
31299
  this.#publishNextBatch();
30192
31300
  };
30193
31301
  disconnect = (socket) => {
@@ -30195,10 +31303,15 @@ var DaemonSessionEventPublisher = class {
30195
31303
  return;
30196
31304
  }
30197
31305
  this.#connection = this.#connection.disconnect(socket);
30198
- this.#inFlightEventIds.clear();
31306
+ this.#clearInFlight();
30199
31307
  };
30200
31308
  recordAttempt = (sessionId, payload, attemptId) => {
30201
- this.#outbox.enqueue(sessionId, payload, attemptId);
31309
+ const kind = decodeMessageKind(payload);
31310
+ if (kind === SESSION_COMPLETED_KIND || kind === SESSION_FAILED_KIND) {
31311
+ this.#outbox.enqueueCritical(sessionId, payload, attemptId);
31312
+ } else {
31313
+ this.#outbox.enqueue(sessionId, payload, attemptId);
31314
+ }
30202
31315
  this.#publishNextBatch();
30203
31316
  };
30204
31317
  recordRuntime = (sessionId, payload) => {
@@ -30209,7 +31322,7 @@ var DaemonSessionEventPublisher = class {
30209
31322
  if (!this.#outbox.acknowledge(acknowledgement)) {
30210
31323
  return;
30211
31324
  }
30212
- this.#inFlightEventIds.delete(acknowledgement.eventId);
31325
+ this.#removeInFlight(acknowledgement.eventId);
30213
31326
  this.#publishNextBatch();
30214
31327
  };
30215
31328
  quarantine = (rejection) => {
@@ -30217,24 +31330,60 @@ var DaemonSessionEventPublisher = class {
30217
31330
  if (!quarantined) {
30218
31331
  return false;
30219
31332
  }
30220
- this.#inFlightEventIds.delete(rejection.eventId);
31333
+ this.#removeInFlight(rejection.eventId);
30221
31334
  this.#publishNextBatch();
30222
31335
  return true;
30223
31336
  };
30224
31337
  #publishNextBatch = () => {
30225
- if (this.#inFlightEventIds.size > 0) {
30226
- return;
30227
- }
30228
- const batch = this.#outbox.pendingBatch(SESSION_EVENT_REPLAY_WINDOW);
30229
- for (const encoded of batch) {
30230
- const envelope2 = decodeSessionEventEnvelope(encoded);
30231
- if (!this.#connection.send(encoded)) {
30232
- this.#inFlightEventIds.clear();
31338
+ while (this.#inFlightEvents.size < SESSION_EVENT_REPLAY_WINDOW) {
31339
+ const sourceCounts = /* @__PURE__ */ new Map();
31340
+ for (const inFlight of this.#inFlightEvents.values()) {
31341
+ sourceCounts.set(inFlight.sourceKey, (sourceCounts.get(inFlight.sourceKey) ?? 0) + 1);
31342
+ }
31343
+ const saturatedSources = [...sourceCounts.entries()].filter(([, count]) => count >= SESSION_EVENT_SOURCE_REPLAY_WINDOW).map(([sourceKey]) => sourceKey);
31344
+ const batch = this.#outbox.pendingSourceHeads(
31345
+ SESSION_EVENT_REPLAY_WINDOW - this.#inFlightEvents.size,
31346
+ [...this.#inFlightEvents.keys()],
31347
+ saturatedSources
31348
+ );
31349
+ let sent = 0;
31350
+ for (const encoded of batch) {
31351
+ const envelope2 = decodeSessionEventEnvelope(encoded);
31352
+ const sourceKey = sessionEventSourceKey(envelope2);
31353
+ const sourceCount = sourceCounts.get(sourceKey) ?? 0;
31354
+ if (sourceCount >= SESSION_EVENT_SOURCE_REPLAY_WINDOW) {
31355
+ continue;
31356
+ }
31357
+ const byteLength = new TextEncoder().encode(encoded).byteLength;
31358
+ if (this.#inFlightBytes + byteLength > SESSION_EVENT_REPLAY_BYTE_LIMIT) {
31359
+ continue;
31360
+ }
31361
+ if (!this.#connection.send(encoded)) {
31362
+ this.#clearInFlight();
31363
+ return;
31364
+ }
31365
+ this.#inFlightEvents.set(envelope2.eventId, new InFlightSessionEvent(sourceKey, byteLength));
31366
+ this.#inFlightBytes += byteLength;
31367
+ sourceCounts.set(sourceKey, sourceCount + 1);
31368
+ sent += 1;
31369
+ }
31370
+ if (sent === 0) {
30233
31371
  return;
30234
31372
  }
30235
- this.#inFlightEventIds.add(envelope2.eventId);
30236
31373
  }
30237
31374
  };
31375
+ #removeInFlight = (eventId) => {
31376
+ const inFlight = this.#inFlightEvents.get(eventId);
31377
+ if (inFlight === void 0) {
31378
+ return;
31379
+ }
31380
+ this.#inFlightEvents.delete(eventId);
31381
+ this.#inFlightBytes -= inFlight.byteLength;
31382
+ };
31383
+ #clearInFlight = () => {
31384
+ this.#inFlightEvents.clear();
31385
+ this.#inFlightBytes = 0;
31386
+ };
30238
31387
  };
30239
31388
  var CoalescingDaemonActivityPublisher = class {
30240
31389
  #pending = /* @__PURE__ */ new Map();
@@ -30367,7 +31516,7 @@ async function resolveSessionDirectories(directories, bindingId, directoryId2, a
30367
31516
  additionalDirectories.push(directory);
30368
31517
  additionalDirectoryEntries.push({
30369
31518
  directoryId: additionalDirectoryId,
30370
- name: basename4(directory)
31519
+ name: basename5(directory)
30371
31520
  });
30372
31521
  }
30373
31522
  return new ResolvedSessionDirectories(cwd, additionalDirectories, additionalDirectoryEntries);
@@ -30486,6 +31635,9 @@ async function executeSessionConfigure(publisher, socket, command, config2, dire
30486
31635
  })
30487
31636
  );
30488
31637
  } catch (error61) {
31638
+ if (signal.aborted) {
31639
+ signal.throwIfAborted();
31640
+ }
30489
31641
  reportOperationFailure(socket, command.requestId, command.sessionId, error61);
30490
31642
  }
30491
31643
  }
@@ -30825,6 +31977,7 @@ async function publishAgentCatalogUntilAvailable(config2, diagnostics, signal, t
30825
31977
  }
30826
31978
  async function runRelayConnection(config2, directories, audit, sessions, installations, installationObserver, nativeSessions, outbox, publisher, grants, contexts, applicator, ipc, activeTurns, activeAttemptIds, connectionEpoch, diagnostics, onConnected, signal, timer) {
30827
31979
  const relayUrl = new URL(config2.relayUrl);
31980
+ relayUrl.searchParams.set("deliveryReceipts", "1");
30828
31981
  relayUrl.searchParams.set("liveness", "1");
30829
31982
  const socket = await connectRelay(relayUrl, signal);
30830
31983
  const reconnectingTurns = [...activeTurns.values()];
@@ -30873,6 +32026,239 @@ async function runRelayConnection(config2, directories, audit, sessions, install
30873
32026
  closeRelaySocket(socket, code, reason);
30874
32027
  rejectConnection(failure);
30875
32028
  };
32029
+ const processingDeliveryIds = /* @__PURE__ */ new Set();
32030
+ const processDeliveredPrompt = async (delivery, command, trackActiveAttempt, execute) => {
32031
+ if (command.sessionId !== delivery.sessionId) {
32032
+ throw new Error("Runtime delivery Session identity does not match its payload");
32033
+ }
32034
+ const active = activeTurns.get(command.commandId);
32035
+ if (active !== void 0) {
32036
+ await active.completion;
32037
+ return;
32038
+ }
32039
+ const receipt = outbox.claimExecution(command.commandId, command.sessionId, delivery.payload);
32040
+ if (receipt.kind === "duplicate") {
32041
+ if (receipt.state === "running") {
32042
+ reportFailure(
32043
+ publisher,
32044
+ command,
32045
+ "agent_execution_interrupted",
32046
+ "The local Agent execution was interrupted before it completed",
32047
+ receipt.attemptId
32048
+ );
32049
+ outbox.transitionExecution(command.commandId, "failed");
32050
+ return;
32051
+ }
32052
+ if (receipt.state !== "dispatching") {
32053
+ return;
32054
+ }
32055
+ }
32056
+ const turn = new ActiveDaemonTurn(command, receipt.attemptId);
32057
+ activeTurns.set(command.commandId, turn);
32058
+ if (trackActiveAttempt) {
32059
+ activeAttemptIds.set(command.sessionId, receipt.attemptId);
32060
+ }
32061
+ try {
32062
+ await execute(receipt.attemptId, turn.signal);
32063
+ } finally {
32064
+ activeTurns.delete(command.commandId);
32065
+ if (activeAttemptIds.get(command.sessionId) === receipt.attemptId) {
32066
+ activeAttemptIds.delete(command.sessionId);
32067
+ }
32068
+ turn.finish();
32069
+ }
32070
+ };
32071
+ const processDeliveredPayload = async (delivery) => {
32072
+ const kind = decodeMessageKind(delivery.payload);
32073
+ if (kind === SESSION_CANCEL_KIND) {
32074
+ const cancellation = decodeSessionCancelCommand(delivery.payload);
32075
+ if (cancellation.sessionId !== delivery.sessionId) {
32076
+ throw new Error("Runtime delivery Session identity does not match its payload");
32077
+ }
32078
+ const turn = activeTurns.get(cancellation.commandId);
32079
+ if (turn === void 0 || !turn.matches(cancellation) || !turn.requestCancellation()) {
32080
+ return;
32081
+ }
32082
+ audit.record({
32083
+ commandId: cancellation.commandId,
32084
+ event: "session_cancellation_requested",
32085
+ sessionId: cancellation.sessionId
32086
+ });
32087
+ await sessions.cancelPrompt(cancellation.sessionId);
32088
+ return;
32089
+ }
32090
+ if (kind === SESSION_CONFIGURE_KIND) {
32091
+ const command = decodeSessionConfigureCommand(delivery.payload);
32092
+ if (command.sessionId !== delivery.sessionId) {
32093
+ throw new Error("Runtime delivery Session identity does not match its payload");
32094
+ }
32095
+ await executeSessionConfigure(
32096
+ publisher,
32097
+ socket,
32098
+ command,
32099
+ config2,
32100
+ directories,
32101
+ audit,
32102
+ sessions,
32103
+ connectionController.signal
32104
+ );
32105
+ return;
32106
+ }
32107
+ if (kind === SESSION_PERMISSION_RESPOND_KIND) {
32108
+ const command = decodeSessionPermissionRespondCommand(delivery.payload);
32109
+ if (command.sessionId !== delivery.sessionId) {
32110
+ throw new Error("Runtime delivery Session identity does not match its payload");
32111
+ }
32112
+ try {
32113
+ await sessions.respondPermission(command);
32114
+ audit.record({
32115
+ commandId: command.interactionId,
32116
+ event: "session_permission_resolved",
32117
+ sessionId: command.sessionId
32118
+ });
32119
+ } catch (error61) {
32120
+ reportOperationFailure(socket, command.interactionId, command.sessionId, error61);
32121
+ }
32122
+ return;
32123
+ }
32124
+ if (kind === SESSION_ELICITATION_RESPOND_KIND) {
32125
+ const command = decodeSessionElicitationRespondCommand(delivery.payload);
32126
+ if (command.sessionId !== delivery.sessionId) {
32127
+ throw new Error("Runtime delivery Session identity does not match its payload");
32128
+ }
32129
+ try {
32130
+ await sessions.respondElicitation(command);
32131
+ audit.record({
32132
+ commandId: command.interactionId,
32133
+ event: "session_elicitation_resolved",
32134
+ sessionId: command.sessionId
32135
+ });
32136
+ } catch (error61) {
32137
+ reportOperationFailure(socket, command.interactionId, command.sessionId, error61);
32138
+ }
32139
+ return;
32140
+ }
32141
+ if (kind === BOT_SESSION_PROMPT_KIND) {
32142
+ const command = decodeBotSessionPromptCommand(delivery.payload);
32143
+ await processDeliveredPrompt(
32144
+ delivery,
32145
+ command,
32146
+ true,
32147
+ (attemptId, executionSignal) => executeBotPrompt(
32148
+ outbox,
32149
+ publisher,
32150
+ command,
32151
+ config2,
32152
+ directories,
32153
+ audit,
32154
+ sessions,
32155
+ grants,
32156
+ contexts,
32157
+ applicator,
32158
+ ipc,
32159
+ attemptId,
32160
+ timer,
32161
+ executionSignal
32162
+ )
32163
+ );
32164
+ return;
32165
+ }
32166
+ if (kind === SESSION_PROMPT_KIND) {
32167
+ const command = decodeSessionPromptCommand(delivery.payload);
32168
+ await processDeliveredPrompt(
32169
+ delivery,
32170
+ command,
32171
+ command.disposition !== SessionPromptDisposition.Steer,
32172
+ (attemptId, executionSignal) => executePrompt(
32173
+ outbox,
32174
+ publisher,
32175
+ command,
32176
+ config2,
32177
+ directories,
32178
+ audit,
32179
+ sessions,
32180
+ attemptId,
32181
+ timer,
32182
+ executionSignal
32183
+ )
32184
+ );
32185
+ return;
32186
+ }
32187
+ throw new Error("Runtime delivery contains an unsupported protocol message");
32188
+ };
32189
+ const processRuntimeDelivery = (delivery, state) => {
32190
+ if (state === "processed" || processingDeliveryIds.has(delivery.deliveryId)) {
32191
+ return;
32192
+ }
32193
+ processingDeliveryIds.add(delivery.deliveryId);
32194
+ void processDeliveredPayload(delivery).then(() => {
32195
+ outbox.markRuntimeDeliveryProcessed(delivery.deliveryId, delivery.sessionId);
32196
+ }).catch((error61) => {
32197
+ if (connectionController.signal.aborted) {
32198
+ return;
32199
+ }
32200
+ console.error("Mobius daemon could not process a durable Runtime delivery", error61);
32201
+ failAndClose(
32202
+ new Error("Runtime delivery processing failed", { cause: error61 }),
32203
+ 4008,
32204
+ "Invalid Runtime delivery",
32205
+ "delivery"
32206
+ );
32207
+ }).finally(() => processingDeliveryIds.delete(delivery.deliveryId));
32208
+ };
32209
+ const receiveRuntimeDelivery = (delivery) => {
32210
+ const payloadKind = decodeMessageKind(delivery.payload);
32211
+ let payloadSessionId = "";
32212
+ if (payloadKind === SESSION_CANCEL_KIND) {
32213
+ payloadSessionId = decodeSessionCancelCommand(delivery.payload).sessionId;
32214
+ } else if (payloadKind === SESSION_CONFIGURE_KIND) {
32215
+ payloadSessionId = decodeSessionConfigureCommand(delivery.payload).sessionId;
32216
+ } else if (payloadKind === SESSION_PERMISSION_RESPOND_KIND) {
32217
+ payloadSessionId = decodeSessionPermissionRespondCommand(delivery.payload).sessionId;
32218
+ } else if (payloadKind === SESSION_ELICITATION_RESPOND_KIND) {
32219
+ payloadSessionId = decodeSessionElicitationRespondCommand(delivery.payload).sessionId;
32220
+ } else if (payloadKind === SESSION_PROMPT_KIND) {
32221
+ payloadSessionId = decodeSessionPromptCommand(delivery.payload).sessionId;
32222
+ } else if (payloadKind === BOT_SESSION_PROMPT_KIND) {
32223
+ payloadSessionId = decodeBotSessionPromptCommand(delivery.payload).sessionId;
32224
+ } else {
32225
+ throw new Error("Runtime delivery contains an unsupported protocol message");
32226
+ }
32227
+ if (payloadSessionId !== delivery.sessionId) {
32228
+ throw new Error("Runtime delivery Session identity does not match its payload");
32229
+ }
32230
+ const stored = outbox.claimRuntimeDelivery(delivery);
32231
+ send(
32232
+ socket,
32233
+ encodeRuntimeDeliveryReceived({
32234
+ deliveryId: delivery.deliveryId,
32235
+ kind: RUNTIME_DELIVERY_RECEIVED_KIND,
32236
+ sessionId: delivery.sessionId
32237
+ })
32238
+ );
32239
+ processRuntimeDelivery(delivery, stored.state);
32240
+ };
32241
+ const resumeRuntimeDeliveries = () => {
32242
+ for (const stored of outbox.runtimeDeliveries()) {
32243
+ const delivery = {
32244
+ deliveryId: stored.deliveryId,
32245
+ kind: RUNTIME_DELIVERY_KIND,
32246
+ payload: stored.payload,
32247
+ sessionId: stored.sessionId
32248
+ };
32249
+ if (stored.state !== "relay_committed") {
32250
+ send(
32251
+ socket,
32252
+ encodeRuntimeDeliveryReceived({
32253
+ deliveryId: stored.deliveryId,
32254
+ kind: RUNTIME_DELIVERY_RECEIVED_KIND,
32255
+ sessionId: stored.sessionId
32256
+ })
32257
+ );
32258
+ }
32259
+ processRuntimeDelivery(delivery, stored.state);
32260
+ }
32261
+ };
30876
32262
  const connectionLiveness = new RelayConnectionLiveness(timer, {
30877
32263
  send: (message) => send(socket, message),
30878
32264
  unresponsive: (heartbeatId, timeoutMilliseconds) => {
@@ -30911,6 +32297,17 @@ async function runRelayConnection(config2, directories, audit, sessions, install
30911
32297
  }
30912
32298
  try {
30913
32299
  const kind = decodeMessageKind(encoded);
32300
+ if (kind === RUNTIME_DELIVERY_COMMITTED_KIND) {
32301
+ const committed = decodeRuntimeDeliveryCommitted(encoded);
32302
+ if (!outbox.markRuntimeDeliveryCommitted(committed.deliveryId, committed.sessionId)) {
32303
+ console.warn("Mobius daemon ignored confirmation for an unknown Runtime delivery");
32304
+ }
32305
+ return;
32306
+ }
32307
+ if (kind === RUNTIME_DELIVERY_KIND) {
32308
+ receiveRuntimeDelivery(decodeRuntimeDelivery(encoded));
32309
+ return;
32310
+ }
30914
32311
  if (kind === SESSION_EVENT_ACK_KIND) {
30915
32312
  publisher.acknowledge(decodeSessionEventAcknowledgement(encoded));
30916
32313
  return;
@@ -31347,6 +32744,10 @@ async function runRelayConnection(config2, directories, audit, sessions, install
31347
32744
  });
31348
32745
  } catch (error61) {
31349
32746
  console.error("Mobius daemon rejected a message", error61);
32747
+ if (error61 instanceof RuntimeDeliveryInboxCapacityError) {
32748
+ failAndClose(error61, 4013, "Runtime delivery queue full", "delivery_backpressure");
32749
+ return;
32750
+ }
31350
32751
  failAndClose(
31351
32752
  new Error("Relay sent an invalid protocol message", { cause: error61 }),
31352
32753
  4008,
@@ -31364,6 +32765,7 @@ async function runRelayConnection(config2, directories, audit, sessions, install
31364
32765
  return;
31365
32766
  }
31366
32767
  publisher.connect(socket);
32768
+ resumeRuntimeDeliveries();
31367
32769
  },
31368
32770
  (error61) => {
31369
32771
  if (finished) {
@@ -31416,7 +32818,7 @@ async function runDaemon(config2, audit, signal, timer = systemDaemonTimer) {
31416
32818
  }
31417
32819
  publisher.recordAttempt(sessionId, payload, attemptId);
31418
32820
  };
31419
- const sessions = new AcpSessionManager(new DaemonAcpObserver(recordSessionEvent), sessionStore);
32821
+ const sessions = new AcpSessionManager(new DaemonAcpObserver(config2, recordSessionEvent), sessionStore);
31420
32822
  const directories = new WorkspaceDirectoryService(config2.bindingId, config2.defaultWorkspace);
31421
32823
  const installationObserver = new DaemonInstallationObserver();
31422
32824
  const diagnostics = new RelayConnectionDiagnostics(audit, config2.channelId, config2.relayUrl);
@@ -31583,12 +32985,14 @@ process.once("SIGTERM", () => shutdown.abort());
31583
32985
  var USAGE = `Mobius CLI
31584
32986
 
31585
32987
  Usage:
32988
+ mobius --version
31586
32989
  mobius pair --url <relay-url> --pairing <runtime-pairing-id> --code <pairing-code> [--workspace <directory>]
31587
32990
  mobius start --channel <channel-id>
31588
32991
  mobius agents [--json]
31589
32992
  mobius bot message send --target <current|alias> --text <message>
31590
32993
 
31591
32994
  Commands:
32995
+ --version Print the installed Mobius CLI version
31592
32996
  pair Pair this machine and start its local daemon
31593
32997
  start Start the local daemon for a saved channel
31594
32998
  agents Show detected, missing, and integration-ready Agents
@@ -31603,6 +33007,11 @@ async function main() {
31603
33007
  process.stdout.write(USAGE);
31604
33008
  return;
31605
33009
  }
33010
+ if (command === "--version" || command === "-v" || command === "version") {
33011
+ process.stdout.write(`${package_default.version}
33012
+ `);
33013
+ return;
33014
+ }
31606
33015
  if (command === "agents") {
31607
33016
  const arguments_ = process.argv.slice(3);
31608
33017
  if (arguments_.length > 1 || arguments_.length === 1 && arguments_[0] !== "--json") {