@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/runtime.js CHANGED
@@ -5,7 +5,7 @@ var __export = (target, all) => {
5
5
  };
6
6
 
7
7
  // src/runtime.ts
8
- import { mkdir as mkdir5, realpath as realpath8, stat as stat8 } from "node:fs/promises";
8
+ import { mkdir as mkdir5, realpath as realpath9, stat as stat9 } from "node:fs/promises";
9
9
  import { dirname as dirname8, join as join17, resolve as resolve5 } from "node:path";
10
10
 
11
11
  // src/agent-catalog/local-agent.ts
@@ -2524,7 +2524,7 @@ var AuditStore = class {
2524
2524
  this.database.exec("ALTER TABLE audit_events ADD COLUMN details_json TEXT NOT NULL DEFAULT '{}'");
2525
2525
  }
2526
2526
  }
2527
- record(record2) {
2527
+ record(record3) {
2528
2528
  this.database.prepare(
2529
2529
  `
2530
2530
  INSERT INTO audit_events (
@@ -2537,10 +2537,10 @@ var AuditStore = class {
2537
2537
  `
2538
2538
  ).run(
2539
2539
  (/* @__PURE__ */ new Date()).toISOString(),
2540
- record2.event,
2541
- record2.commandId,
2542
- record2.sessionId,
2543
- JSON.stringify(record2.details ?? {})
2540
+ record3.event,
2541
+ record3.commandId,
2542
+ record3.sessionId,
2543
+ JSON.stringify(record3.details ?? {})
2544
2544
  );
2545
2545
  }
2546
2546
  close() {
@@ -18603,8 +18603,8 @@ function rewriteKeyNames(ctx) {
18603
18603
  bySchema.set(entry.schema, entry);
18604
18604
  }
18605
18605
  const rewrites = /* @__PURE__ */ new Map();
18606
- for (const record2 of pendingRecords.get(ctx) ?? []) {
18607
- const seen = ctx.seen.get(record2);
18606
+ for (const record3 of pendingRecords.get(ctx) ?? []) {
18607
+ const seen = ctx.seen.get(record3);
18608
18608
  const names = (seen?.def ?? seen?.schema)?.propertyNames;
18609
18609
  if (!names || names === true || rewrites.has(names))
18610
18610
  continue;
@@ -21561,6 +21561,7 @@ var elicitationFieldSchema = external_exports.strictObject({
21561
21561
  type: external_exports.enum(["boolean", "integer", "multiselect", "number", "select", "string"])
21562
21562
  }).readonly();
21563
21563
  var displayContentSchema = external_exports.strictObject({
21564
+ artifactId: external_exports.string().max(128).default(""),
21564
21565
  data: external_exports.string().max(4e6),
21565
21566
  mimeType: external_exports.string().max(255),
21566
21567
  name: external_exports.string().max(500),
@@ -21573,6 +21574,7 @@ var displayContentSchema = external_exports.strictObject({
21573
21574
  uri: external_exports.string().max(4096)
21574
21575
  }).readonly();
21575
21576
  var recordedDisplayContentSchema = external_exports.strictObject({
21577
+ artifactId: external_exports.string().max(128).default(""),
21576
21578
  data: external_exports.string().max(4e6),
21577
21579
  mimeType: external_exports.string().max(255),
21578
21580
  name: external_exports.string().max(500),
@@ -21856,6 +21858,9 @@ var SESSION_CANCEL_KIND = "session.cancel";
21856
21858
  var RUNTIME_LIVENESS_READY_KIND = "runtime.liveness.ready";
21857
21859
  var RUNTIME_HEARTBEAT_KIND = "runtime.heartbeat";
21858
21860
  var RUNTIME_HEARTBEAT_ACK_KIND = "runtime.heartbeat.ack";
21861
+ var RUNTIME_DELIVERY_KIND = "runtime.delivery";
21862
+ var RUNTIME_DELIVERY_RECEIVED_KIND = "runtime.delivery.received";
21863
+ var RUNTIME_DELIVERY_COMMITTED_KIND = "runtime.delivery.committed";
21859
21864
  var SESSION_STARTED_KIND = "session.started";
21860
21865
  var AGENT_MESSAGE_DELTA_KIND = "agent.message.delta";
21861
21866
  var AGENT_ACTIVITY_KIND = "agent.activity";
@@ -21878,6 +21883,7 @@ var DIRECTORY_IDENTIFIER_PATTERN2 = /^[a-zA-Z0-9][a-zA-Z0-9_-]{0,2047}$/;
21878
21883
  var MAX_PROMPT_LENGTH = 1e4;
21879
21884
  var MAX_PROMPT_ATTACHMENT_LENGTH = 6e6;
21880
21885
  var MAX_EVENT_TEXT_LENGTH = 1e5;
21886
+ var MAX_RUNTIME_DELIVERY_PAYLOAD_LENGTH = 8 * 1024 * 1024;
21881
21887
  var ACTIVITY_TYPES = /* @__PURE__ */ new Set(["plan", "progress", "reasoning", "tool"]);
21882
21888
  var ACTIVITY_STATUSES = /* @__PURE__ */ new Set(["pending", "running", "completed", "failed"]);
21883
21889
  var TOOL_KINDS = /* @__PURE__ */ new Set([
@@ -22156,6 +22162,37 @@ function decodeRuntimeHeartbeatAckEvent(encoded) {
22156
22162
  kind: RUNTIME_HEARTBEAT_ACK_KIND
22157
22163
  };
22158
22164
  }
22165
+ function decodeRuntimeDelivery(encoded) {
22166
+ const value = parseJson2(encoded);
22167
+ assertExactKeys(value, ["deliveryId", "kind", "payload", "sessionId"]);
22168
+ assertKind(value, RUNTIME_DELIVERY_KIND);
22169
+ return {
22170
+ deliveryId: readIdentifier(value, "deliveryId"),
22171
+ kind: RUNTIME_DELIVERY_KIND,
22172
+ payload: readString(value, "payload", MAX_RUNTIME_DELIVERY_PAYLOAD_LENGTH),
22173
+ sessionId: readIdentifier(value, "sessionId")
22174
+ };
22175
+ }
22176
+ function decodeRuntimeDeliveryReceived(encoded) {
22177
+ const value = parseJson2(encoded);
22178
+ assertExactKeys(value, ["deliveryId", "kind", "sessionId"]);
22179
+ assertKind(value, RUNTIME_DELIVERY_RECEIVED_KIND);
22180
+ return {
22181
+ deliveryId: readIdentifier(value, "deliveryId"),
22182
+ kind: RUNTIME_DELIVERY_RECEIVED_KIND,
22183
+ sessionId: readIdentifier(value, "sessionId")
22184
+ };
22185
+ }
22186
+ function decodeRuntimeDeliveryCommitted(encoded) {
22187
+ const value = parseJson2(encoded);
22188
+ assertExactKeys(value, ["deliveryId", "kind", "sessionId"]);
22189
+ assertKind(value, RUNTIME_DELIVERY_COMMITTED_KIND);
22190
+ return {
22191
+ deliveryId: readIdentifier(value, "deliveryId"),
22192
+ kind: RUNTIME_DELIVERY_COMMITTED_KIND,
22193
+ sessionId: readIdentifier(value, "sessionId")
22194
+ };
22195
+ }
22159
22196
  function decodeSessionStartedEvent(encoded) {
22160
22197
  const value = parseJson2(encoded);
22161
22198
  assertExactKeys(value, ["commandId", "kind", "attemptId", "sessionId"]);
@@ -22243,6 +22280,9 @@ function decodeSessionFailedEvent(encoded) {
22243
22280
  function encodeRuntimeHeartbeatEvent(message) {
22244
22281
  return JSON.stringify(decodeRuntimeHeartbeatEvent(JSON.stringify(message)));
22245
22282
  }
22283
+ function encodeRuntimeDeliveryReceived(message) {
22284
+ return JSON.stringify(decodeRuntimeDeliveryReceived(JSON.stringify(message)));
22285
+ }
22246
22286
  function encodeSessionStartedEvent(message) {
22247
22287
  return JSON.stringify(decodeSessionStartedEvent(JSON.stringify(message)));
22248
22288
  }
@@ -22941,7 +22981,8 @@ var SESSION_EVENT_COMMITTED_KIND = "session.event.committed";
22941
22981
  var SESSION_EVENT_REJECTED_KIND = "session.event.rejected";
22942
22982
  var SessionEventRejectionCode = {
22943
22983
  SessionDeleted: "session_deleted",
22944
- SessionNotFound: "session_not_found"
22984
+ SessionNotFound: "session_not_found",
22985
+ SessionRejected: "session_rejected"
22945
22986
  };
22946
22987
  var IDENTIFIER_PATTERN4 = /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/;
22947
22988
  var CURSOR_PATTERN = /^[A-Za-z0-9_-]{1,512}$/;
@@ -23038,9 +23079,9 @@ function createDaemonConfig(connection, agents = [], installableAgents = []) {
23038
23079
 
23039
23080
  // src/run-daemon.ts
23040
23081
  import { randomUUID as randomUUID4 } from "node:crypto";
23041
- import { basename as basename3, join as join15 } from "node:path";
23082
+ import { basename as basename4, join as join15 } from "node:path";
23042
23083
  import { styleText } from "node:util";
23043
- import { fetch as fetch5, WebSocket as WebSocket2 } from "undici";
23084
+ import { fetch as fetch6, WebSocket as WebSocket2 } from "undici";
23044
23085
 
23045
23086
  // src/acp/session-manager.ts
23046
23087
  import { spawn as spawn3 } from "node:child_process";
@@ -23051,6 +23092,212 @@ import {
23051
23092
  RequestError as RequestError2
23052
23093
  } from "@agentclientprotocol/sdk";
23053
23094
 
23095
+ // src/authorization/local-raster.ts
23096
+ import { readFile, realpath as realpath6, stat as stat5 } from "node:fs/promises";
23097
+ import { basename, isAbsolute as isAbsolute7, normalize as normalize2, relative as relative4, sep as sep4 } from "node:path";
23098
+ import { fileURLToPath } from "node:url";
23099
+ var MAX_LOCAL_RASTER_BYTES = 3e6;
23100
+ var PNG_SIGNATURE = Uint8Array.of(137, 80, 78, 71);
23101
+ var JPEG_SIGNATURE = Uint8Array.of(255, 216, 255);
23102
+ var GIF87_SIGNATURE = new TextEncoder().encode("GIF87a");
23103
+ var GIF89_SIGNATURE = new TextEncoder().encode("GIF89a");
23104
+ var RIFF_SIGNATURE = new TextEncoder().encode("RIFF");
23105
+ var WEBP_SIGNATURE = new TextEncoder().encode("WEBP");
23106
+ var LocalRasterImage = class {
23107
+ bytes;
23108
+ mimeType;
23109
+ name;
23110
+ constructor(name, mimeType, bytes) {
23111
+ this.bytes = bytes;
23112
+ this.mimeType = mimeType;
23113
+ this.name = name;
23114
+ }
23115
+ base64 = () => Buffer.from(this.bytes).toString("base64");
23116
+ };
23117
+ function startsWith(bytes, signature, offset = 0) {
23118
+ if (bytes.byteLength < offset + signature.byteLength) {
23119
+ return false;
23120
+ }
23121
+ return signature.every((value, index) => bytes[offset + index] === value);
23122
+ }
23123
+ function sniffRasterMime(bytes) {
23124
+ if (startsWith(bytes, PNG_SIGNATURE)) {
23125
+ return "image/png";
23126
+ }
23127
+ if (startsWith(bytes, JPEG_SIGNATURE)) {
23128
+ return "image/jpeg";
23129
+ }
23130
+ if (startsWith(bytes, GIF87_SIGNATURE) || startsWith(bytes, GIF89_SIGNATURE)) {
23131
+ return "image/gif";
23132
+ }
23133
+ if (startsWith(bytes, RIFF_SIGNATURE) && startsWith(bytes, WEBP_SIGNATURE, 8)) {
23134
+ return "image/webp";
23135
+ }
23136
+ return null;
23137
+ }
23138
+ function isInsideRoot(root, target) {
23139
+ const relation = relative4(root, target);
23140
+ return relation !== ".." && !relation.startsWith(`..${sep4}`) && !isAbsolute7(relation);
23141
+ }
23142
+ async function resolveCanonicalPath(requested, signal) {
23143
+ signal.throwIfAborted();
23144
+ if (!isAbsolute7(requested) || requested.includes("\0") || normalize2(requested) !== requested) {
23145
+ return null;
23146
+ }
23147
+ try {
23148
+ const target = await realpath6(requested);
23149
+ signal.throwIfAborted();
23150
+ if (!isAbsolute7(target) || normalize2(target) !== target) {
23151
+ return null;
23152
+ }
23153
+ return target;
23154
+ } catch (cause) {
23155
+ signal.throwIfAborted();
23156
+ if (cause instanceof Error && cause.name === "AbortError") {
23157
+ throw cause;
23158
+ }
23159
+ return null;
23160
+ }
23161
+ }
23162
+ function parseLocalImageUri(uri) {
23163
+ const trimmed = uri.trim();
23164
+ if (trimmed.length === 0 || trimmed.length > 2048 || trimmed.includes("\0")) {
23165
+ return null;
23166
+ }
23167
+ if (trimmed.startsWith("data:")) {
23168
+ return null;
23169
+ }
23170
+ if (trimmed.startsWith("file:")) {
23171
+ try {
23172
+ const url2 = new URL(trimmed);
23173
+ if (url2.protocol !== "file:" || url2.host.length > 0) {
23174
+ return null;
23175
+ }
23176
+ return fileURLToPath(url2);
23177
+ } catch {
23178
+ return null;
23179
+ }
23180
+ }
23181
+ if (/^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(trimmed)) {
23182
+ return null;
23183
+ }
23184
+ return trimmed;
23185
+ }
23186
+ async function readAuthorizedRaster(uri, roots, signal) {
23187
+ signal.throwIfAborted();
23188
+ const requested = parseLocalImageUri(uri);
23189
+ if (requested === null) {
23190
+ return null;
23191
+ }
23192
+ const target = await resolveCanonicalPath(requested, signal);
23193
+ if (target === null) {
23194
+ return null;
23195
+ }
23196
+ const targetMetadata = await stat5(target);
23197
+ signal.throwIfAborted();
23198
+ if (!targetMetadata.isFile() || targetMetadata.size < 1 || targetMetadata.size > MAX_LOCAL_RASTER_BYTES) {
23199
+ return null;
23200
+ }
23201
+ const authorizedRoots = [];
23202
+ for (const root of roots) {
23203
+ const directory = await resolveCanonicalPath(root, signal);
23204
+ if (directory === null) {
23205
+ continue;
23206
+ }
23207
+ const metadata = await stat5(directory);
23208
+ signal.throwIfAborted();
23209
+ if (metadata.isDirectory()) {
23210
+ authorizedRoots.push(directory);
23211
+ }
23212
+ }
23213
+ if (!authorizedRoots.some((root) => isInsideRoot(root, target))) {
23214
+ return null;
23215
+ }
23216
+ const bytes = new Uint8Array(await readFile(target));
23217
+ signal.throwIfAborted();
23218
+ if (bytes.byteLength < 1 || bytes.byteLength > MAX_LOCAL_RASTER_BYTES) {
23219
+ return null;
23220
+ }
23221
+ const mimeType = sniffRasterMime(bytes);
23222
+ if (mimeType === null) {
23223
+ return null;
23224
+ }
23225
+ return new LocalRasterImage(basename(target) || "Image", mimeType, bytes);
23226
+ }
23227
+
23228
+ // src/native-sessions/history-images.ts
23229
+ var IMAGE_MARKER = /\[@image\]\(([^)\r\n]*)(?:\)|$)/g;
23230
+ async function embedLocalHistoryImages(history, roots, signal) {
23231
+ if (history.status !== "available") {
23232
+ return history;
23233
+ }
23234
+ const messages = [];
23235
+ let imageCharacters = 0;
23236
+ for (const message of history.messages) {
23237
+ signal.throwIfAborted();
23238
+ const resolved = await resolveMessageImages(message, roots, imageCharacters, signal);
23239
+ imageCharacters += (resolved.images ?? []).reduce((size, image) => size + image.data.length, 0);
23240
+ messages.push(resolved);
23241
+ }
23242
+ return {
23243
+ ...history,
23244
+ messages
23245
+ };
23246
+ }
23247
+ async function resolveMessageImages(message, roots, usedCharacters, signal) {
23248
+ const images = [...message.images ?? []];
23249
+ let imageCharacters = images.reduce((size, image) => size + image.data.length, 0);
23250
+ const text = await replaceImageMarkers(message.text, async (uri) => {
23251
+ if (images.length >= 8 || usedCharacters + imageCharacters >= SESSION_HISTORY_IMAGE_CHARACTER_LIMIT) {
23252
+ return "[Image unavailable]";
23253
+ }
23254
+ const embedded = parseNativeHistoryText(`[@image](${uri})`).images[0];
23255
+ if (embedded !== void 0) {
23256
+ if (usedCharacters + imageCharacters + embedded.data.length > SESSION_HISTORY_IMAGE_CHARACTER_LIMIT) {
23257
+ return "[Image unavailable]";
23258
+ }
23259
+ images.push(embedded);
23260
+ imageCharacters += embedded.data.length;
23261
+ return "";
23262
+ }
23263
+ const local = await readAuthorizedRaster(uri, roots, signal);
23264
+ if (local === null) {
23265
+ return "[Image unavailable]";
23266
+ }
23267
+ const data = local.base64();
23268
+ if (usedCharacters + imageCharacters + data.length > SESSION_HISTORY_IMAGE_CHARACTER_LIMIT) {
23269
+ return "[Image unavailable]";
23270
+ }
23271
+ images.push({
23272
+ data,
23273
+ mimeType: local.mimeType,
23274
+ name: local.name
23275
+ });
23276
+ imageCharacters += data.length;
23277
+ return "";
23278
+ });
23279
+ return {
23280
+ ...message,
23281
+ text,
23282
+ ...images.length > 0 ? { images } : {}
23283
+ };
23284
+ }
23285
+ async function replaceImageMarkers(text, replace) {
23286
+ const matches = [...text.matchAll(IMAGE_MARKER)];
23287
+ if (matches.length === 0) {
23288
+ return text;
23289
+ }
23290
+ let cursor = 0;
23291
+ let rewritten = "";
23292
+ for (const match of matches) {
23293
+ const index = match.index ?? 0;
23294
+ rewritten += text.slice(cursor, index);
23295
+ rewritten += await replace(match[1] ?? "");
23296
+ cursor = index + match[0].length;
23297
+ }
23298
+ return `${rewritten}${text.slice(cursor)}`;
23299
+ }
23300
+
23054
23301
  // src/acp/activity.ts
23055
23302
  var TRUNCATION_MARKER = "\n\u2026 output truncated by Mobius";
23056
23303
  function isRecord6(value) {
@@ -23148,6 +23395,7 @@ function readContentOutputDetail(content) {
23148
23395
  function summarizeDisplayContent(content) {
23149
23396
  return {
23150
23397
  ...content,
23398
+ artifactId: truncate(content.artifactId, 128),
23151
23399
  data: truncate(content.data, AGENT_ACTIVITY_DETAIL_LIMIT),
23152
23400
  mimeType: truncate(content.mimeType, 255),
23153
23401
  name: truncate(content.name, 500),
@@ -23160,7 +23408,7 @@ function summarizeDisplayContent(content) {
23160
23408
  };
23161
23409
  }
23162
23410
  function contentFitsRecordingEnvelope(content) {
23163
- 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;
23411
+ 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;
23164
23412
  }
23165
23413
  function encodedByteLength(value) {
23166
23414
  return new TextEncoder().encode(JSON.stringify(value)).byteLength;
@@ -23186,6 +23434,7 @@ function recordedDetail(activity) {
23186
23434
  }
23187
23435
  function emptyDisplayContent(type) {
23188
23436
  return {
23437
+ artifactId: "",
23189
23438
  data: "",
23190
23439
  mimeType: "",
23191
23440
  name: "",
@@ -23198,6 +23447,16 @@ function emptyDisplayContent(type) {
23198
23447
  uri: ""
23199
23448
  };
23200
23449
  }
23450
+ function imageDisplayContent(mimeType, name, data, artifactId = "", uri = "") {
23451
+ return {
23452
+ ...emptyDisplayContent("image"),
23453
+ artifactId,
23454
+ data,
23455
+ mimeType,
23456
+ name,
23457
+ uri
23458
+ };
23459
+ }
23201
23460
  function normalizeContentBlock(content) {
23202
23461
  if (content.type === "text") {
23203
23462
  return { ...emptyDisplayContent("text"), text: content.text };
@@ -23989,7 +24248,6 @@ var AcpHistoryReplay = class {
23989
24248
  #messages = [];
23990
24249
  #lastMessageId = null;
23991
24250
  #characters = 0;
23992
- #imageCharacters = 0;
23993
24251
  #truncated = false;
23994
24252
  record = (update) => {
23995
24253
  if (update.sessionUpdate !== "user_message_chunk" && update.sessionUpdate !== "agent_message_chunk") {
@@ -24000,40 +24258,30 @@ var AcpHistoryReplay = class {
24000
24258
  }
24001
24259
  const role = update.sessionUpdate === "user_message_chunk" ? "user" : "assistant";
24002
24260
  const content = update.content;
24003
- const parsed = parseNativeHistoryText(
24004
- content.type === "text" ? content.text : content.type === "image" ? `[@image](data:${content.mimeType};base64,${content.data})` : `[${content.type} attachment]`
24005
- );
24006
- const text = parsed.text;
24007
- if (text.length === 0 && parsed.images.length === 0) {
24261
+ 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]`;
24262
+ if (text.length === 0) {
24008
24263
  return;
24009
24264
  }
24010
24265
  const previous = this.#messages.at(-1);
24011
24266
  const id = update.messageId ?? null;
24012
24267
  const continuation = previous?.role === role && id === this.#lastMessageId;
24013
24268
  const combined = continuation ? `${previous.text}${text}` : text;
24014
- const allImages = continuation ? [...previous.images ?? [], ...parsed.images] : parsed.images;
24015
- const images = allImages.slice(0, 8);
24016
- this.#truncated ||= images.length < allImages.length;
24017
24269
  if (continuation) {
24018
24270
  this.#messages.pop();
24019
24271
  this.#characters -= previous.text.length;
24020
- this.#imageCharacters -= (previous.images ?? []).reduce((size, image) => size + image.data.length, 0);
24021
24272
  }
24022
24273
  const bounded = combined.slice(-SESSION_HISTORY_CHARACTER_LIMIT);
24023
24274
  this.#truncated ||= bounded.length < combined.length;
24024
24275
  this.#messages.push({
24025
24276
  role,
24026
- text: bounded,
24027
- ...images.length > 0 ? { images } : {}
24277
+ text: bounded
24028
24278
  });
24029
24279
  this.#characters += bounded.length;
24030
- this.#imageCharacters += images.reduce((size, image) => size + image.data.length, 0);
24031
24280
  this.#lastMessageId = id;
24032
- while (this.#messages.length > SESSION_HISTORY_PREVIEW_MESSAGE_LIMIT || this.#characters > SESSION_HISTORY_CHARACTER_LIMIT || this.#imageCharacters > SESSION_HISTORY_IMAGE_CHARACTER_LIMIT) {
24281
+ while (this.#messages.length > SESSION_HISTORY_PREVIEW_MESSAGE_LIMIT || this.#characters > SESSION_HISTORY_CHARACTER_LIMIT) {
24033
24282
  const removed = this.#messages.shift();
24034
24283
  if (removed !== void 0) {
24035
24284
  this.#characters -= removed.text.length;
24036
- this.#imageCharacters -= (removed.images ?? []).reduce((size, image) => size + image.data.length, 0);
24037
24285
  }
24038
24286
  this.#truncated = true;
24039
24287
  }
@@ -24256,6 +24504,10 @@ var MAX_PRE_SESSION_UPDATES = 100;
24256
24504
  var MAX_PRE_SESSION_UPDATE_BYTES = 1024 * 1024;
24257
24505
  var SESSION_CONTROL_COMMAND_ID = "session-control";
24258
24506
  var NullAcpSessionObserver = class {
24507
+ importLocalImage = (_sessionId, _image, signal) => {
24508
+ signal.throwIfAborted();
24509
+ return Promise.resolve("");
24510
+ };
24259
24511
  onCommands = () => Promise.resolve();
24260
24512
  onConfig = () => Promise.resolve();
24261
24513
  onContent = () => Promise.resolve();
@@ -24878,11 +25130,75 @@ var AcpProcessSession = class _AcpProcessSession {
24878
25130
  );
24879
25131
  await this.#updateTail;
24880
25132
  signal.throwIfAborted();
24881
- return history.snapshot();
25133
+ return await embedLocalHistoryImages(
25134
+ history.snapshot(),
25135
+ [this.#cwd, ...this.#additionalDirectories],
25136
+ signal
25137
+ );
24882
25138
  } finally {
24883
25139
  this.#replay = { kind: "idle" };
24884
25140
  }
24885
25141
  };
25142
+ imageRoots = () => [this.#cwd, ...this.#additionalDirectories];
25143
+ emitAgentText = async (text, messageId) => {
25144
+ const signal = AbortSignal.timeout(2e4);
25145
+ const parts = text.split(/(\[@image\]\([^)\r\n]*(?:\)|$))/);
25146
+ let leftover = "";
25147
+ for (const part of parts) {
25148
+ const marker = /^\[@image\]\(([^)\r\n]*)(?:\)|$)/.exec(part);
25149
+ if (marker === null) {
25150
+ leftover += part;
25151
+ continue;
25152
+ }
25153
+ if (leftover.length > 0) {
25154
+ await this.#turn.onText(leftover, messageId);
25155
+ leftover = "";
25156
+ }
25157
+ const raster = await readAuthorizedRaster(marker[1] ?? "", this.imageRoots(), signal);
25158
+ if (raster === null) {
25159
+ leftover += "[Image unavailable]";
25160
+ continue;
25161
+ }
25162
+ await this.emitRaster(raster, messageId, signal);
25163
+ }
25164
+ if (leftover.length > 0) {
25165
+ await this.#turn.onText(leftover, messageId);
25166
+ }
25167
+ };
25168
+ emitAgentContent = async (content, messageId) => {
25169
+ if (content.type === "image" && content.data.length === 0 && content.uri.length > 0) {
25170
+ const signal = AbortSignal.timeout(2e4);
25171
+ const raster = await readAuthorizedRaster(content.uri, this.imageRoots(), signal);
25172
+ if (raster !== null) {
25173
+ await this.emitRaster(raster, messageId, signal);
25174
+ return;
25175
+ }
25176
+ }
25177
+ await this.#getObserver().onContent({
25178
+ commandId: this.#turn.commandId,
25179
+ content,
25180
+ contentId: `content-${crypto.randomUUID()}`,
25181
+ kind: AGENT_CONTENT_KIND,
25182
+ messageId,
25183
+ sessionId: this.#mobiusSessionId
25184
+ });
25185
+ };
25186
+ emitRaster = async (raster, messageId, signal) => {
25187
+ const artifactId = await this.#getObserver().importLocalImage(this.#mobiusSessionId, raster, signal);
25188
+ await this.#getObserver().onContent({
25189
+ commandId: this.#turn.commandId,
25190
+ content: imageDisplayContent(
25191
+ raster.mimeType,
25192
+ raster.name,
25193
+ artifactId.length > 0 ? "" : raster.base64(),
25194
+ artifactId
25195
+ ),
25196
+ contentId: `content-${crypto.randomUUID()}`,
25197
+ kind: AGENT_CONTENT_KIND,
25198
+ messageId,
25199
+ sessionId: this.#mobiusSessionId
25200
+ });
25201
+ };
24886
25202
  async #initializeAgent(signal) {
24887
25203
  const initialized = await this.race(
24888
25204
  this.#connection.agent.request(
@@ -25585,18 +25901,14 @@ var AcpProcessSession = class _AcpProcessSession {
25585
25901
  );
25586
25902
  } else {
25587
25903
  await this.#turn.activities.finishNarrative();
25588
- await this.#turn.onText(update.content.text, truncate3(update.messageId ?? "", 255));
25904
+ await this.emitAgentText(update.content.text, truncate3(update.messageId ?? "", 255));
25589
25905
  }
25590
25906
  } else {
25591
25907
  await this.#turn.activities.finishNarrative();
25592
- await this.#getObserver().onContent({
25593
- commandId: this.#turn.commandId,
25594
- content: normalizeContentBlock(update.content),
25595
- contentId: `content-${crypto.randomUUID()}`,
25596
- kind: AGENT_CONTENT_KIND,
25597
- messageId: truncate3(update.messageId ?? "", 255),
25598
- sessionId: this.#mobiusSessionId
25599
- });
25908
+ await this.emitAgentContent(
25909
+ normalizeContentBlock(update.content),
25910
+ truncate3(update.messageId ?? "", 255)
25911
+ );
25600
25912
  }
25601
25913
  return;
25602
25914
  }
@@ -26418,6 +26730,23 @@ var AcpSessionManager = class {
26418
26730
 
26419
26731
  // src/agent-catalog/publish-agent-catalog.ts
26420
26732
  import { fetch as fetch2 } from "undici";
26733
+
26734
+ // src/relay-connection/runtime-authentication.ts
26735
+ function runtimeCredential(relayUrl) {
26736
+ return relayUrl.searchParams.get("token") ?? "";
26737
+ }
26738
+ function runtimeAuthorization(relayUrl) {
26739
+ const credential = runtimeCredential(relayUrl);
26740
+ return credential.length === 0 ? {} : { authorization: `Bearer ${credential}` };
26741
+ }
26742
+ function relayHttpEndpoint(relayUrl) {
26743
+ const endpoint = new URL(relayUrl);
26744
+ endpoint.protocol = endpoint.protocol === "wss:" ? "https:" : "http:";
26745
+ endpoint.search = "";
26746
+ return endpoint;
26747
+ }
26748
+
26749
+ // src/agent-catalog/publish-agent-catalog.ts
26421
26750
  var CATALOG_UPDATE_TIMEOUT_MILLISECONDS = 2e4;
26422
26751
  var AgentCatalogPublishError = class extends Error {
26423
26752
  code = "agent_catalog_update_failed";
@@ -26427,8 +26756,7 @@ var AgentCatalogPublishError = class extends Error {
26427
26756
  }
26428
26757
  };
26429
26758
  function catalogEndpoint(config2) {
26430
- const endpoint = new URL(config2.relayUrl);
26431
- endpoint.protocol = endpoint.protocol === "wss:" ? "https:" : "http:";
26759
+ const endpoint = relayHttpEndpoint(config2.relayUrl);
26432
26760
  if (endpoint.pathname.endsWith("/daemon")) {
26433
26761
  endpoint.pathname = `${endpoint.pathname.slice(0, -"/daemon".length)}/catalog`;
26434
26762
  return endpoint;
@@ -26459,7 +26787,7 @@ async function publishAgentCatalog(config2, signal) {
26459
26787
  installableAgents: catalog.installableAgents
26460
26788
  }),
26461
26789
  dispatcher: environmentProxyDispatcher,
26462
- headers: { "content-type": "application/json" },
26790
+ headers: { ...runtimeAuthorization(config2.relayUrl), "content-type": "application/json" },
26463
26791
  method: "PUT",
26464
26792
  signal: requestSignal
26465
26793
  });
@@ -26941,114 +27269,510 @@ var FixedInstallationExecutor = class {
26941
27269
  };
26942
27270
  };
26943
27271
 
26944
- // src/authorization/local-authorization-error.ts
26945
- var LocalAuthorizationError = class extends Error {
26946
- code = "local_authorization_failed";
26947
- constructor(message, options = {}) {
27272
+ // src/artifacts/runtime-artifact-uploader.ts
27273
+ import { createHash as createHash2 } from "node:crypto";
27274
+
27275
+ // ../mobius-sdk/src/errors.ts
27276
+ var MobiusError = class extends Error {
27277
+ code;
27278
+ constructor(code, message, options = {}) {
26948
27279
  super(message, options);
26949
- this.name = "LocalAuthorizationError";
27280
+ this.code = code;
27281
+ this.name = "MobiusError";
26950
27282
  }
26951
27283
  };
26952
-
26953
- // src/authorization/workspace-directory.ts
26954
- import { readdir, realpath as realpath6, stat as stat5 } from "node:fs/promises";
26955
- import { homedir as homedir2 } from "node:os";
26956
- import { basename, dirname as dirname5, isAbsolute as isAbsolute7, join as join14, normalize as normalize2, relative as relative4 } from "node:path";
26957
- var WorkspaceDirectoryListing = class {
26958
- directoryId;
26959
- directoryLabel;
26960
- entries;
26961
- parentDirectoryId;
26962
- constructor(directoryId2, directoryLabel, entries, parentDirectoryId) {
26963
- this.directoryId = directoryId2;
26964
- this.directoryLabel = directoryLabel;
26965
- this.entries = entries;
26966
- this.parentDirectoryId = parentDirectoryId;
27284
+ var MobiusProtocolError = class extends MobiusError {
27285
+ constructor(message, options = {}) {
27286
+ super("invalid_service_response", message, options);
27287
+ this.name = "MobiusProtocolError";
26967
27288
  }
26968
27289
  };
26969
- function encodePath(path2) {
26970
- const encoded = Buffer.from(path2, "utf8").toString("base64url");
26971
- if (encoded.length === 0 || encoded.length > 2e3) {
26972
- throw new LocalAuthorizationError("The local directory path is too long to select");
27290
+ var MobiusValidationError = class extends MobiusError {
27291
+ constructor(message, options = {}) {
27292
+ super("invalid_request", message, options);
27293
+ this.name = "MobiusValidationError";
26973
27294
  }
26974
- return `path-${encoded}`;
27295
+ };
27296
+
27297
+ // ../mobius-sdk/src/resources.ts
27298
+ var IDENTIFIER_PATTERN5 = /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/;
27299
+ function invalidResponse(message) {
27300
+ return new MobiusProtocolError(message);
26975
27301
  }
26976
- function decodePath(value, prefix) {
26977
- const encoded = value.slice(prefix.length);
26978
- if (encoded.length === 0 || encoded.length > 2e3 || !/^[a-zA-Z0-9_-]+$/.test(encoded)) {
26979
- throw new LocalAuthorizationError("The directory identifier is invalid");
27302
+ function isRecord9(value) {
27303
+ return typeof value === "object" && value !== null && !Array.isArray(value);
27304
+ }
27305
+ function record2(value, name) {
27306
+ if (!isRecord9(value)) {
27307
+ throw invalidResponse(`The service returned an invalid ${name}`);
26980
27308
  }
26981
- const decoded = Buffer.from(encoded, "base64url").toString("utf8");
26982
- if (Buffer.from(decoded, "utf8").toString("base64url") !== encoded || decoded.includes("\0") || normalize2(decoded) !== decoded) {
26983
- throw new LocalAuthorizationError("The directory identifier is invalid");
27309
+ return value;
27310
+ }
27311
+ function stringField(value, field, maximumLength = 85e5) {
27312
+ const candidate = value[field];
27313
+ if (typeof candidate !== "string" || candidate.length > maximumLength) {
27314
+ throw invalidResponse(`The service returned an invalid ${field}`);
26984
27315
  }
26985
- return decoded;
27316
+ return candidate;
26986
27317
  }
26987
- var WorkspaceDirectoryService = class {
26988
- #bindingId;
26989
- #defaultWorkspace;
26990
- constructor(bindingId, defaultWorkspace) {
26991
- this.#bindingId = bindingId;
26992
- this.#defaultWorkspace = defaultWorkspace;
27318
+ function identifierField(value, field) {
27319
+ const candidate = stringField(value, field, 128);
27320
+ if (!IDENTIFIER_PATTERN5.test(candidate)) {
27321
+ throw invalidResponse(`The service returned an invalid ${field}`);
26993
27322
  }
26994
- authorizeMachine = (bindingId) => {
26995
- if (bindingId !== this.#bindingId) {
26996
- throw new LocalAuthorizationError("The runtime binding is not authorized");
26997
- }
26998
- };
26999
- requestedPath = (id) => {
27000
- if (id === "default") {
27001
- return this.#defaultWorkspace;
27002
- }
27003
- if (id === "home") {
27004
- return homedir2();
27005
- }
27006
- if (id.startsWith("path-")) {
27007
- const path2 = decodePath(id, "path-");
27008
- if (isAbsolute7(path2)) {
27009
- return path2;
27010
- }
27011
- }
27012
- throw new LocalAuthorizationError("The directory identifier is invalid");
27013
- };
27014
- resolvePath = async (requested, signal) => {
27015
- signal.throwIfAborted();
27016
- if (!isAbsolute7(requested) || requested.includes("\0") || normalize2(requested) !== requested) {
27017
- throw new LocalAuthorizationError("The local directory path is invalid");
27018
- }
27019
- try {
27020
- const target = await realpath6(requested);
27021
- signal.throwIfAborted();
27022
- const metadata = await stat5(target);
27023
- signal.throwIfAborted();
27024
- if (!isAbsolute7(target) || normalize2(target) !== target || !metadata.isDirectory()) {
27025
- throw new LocalAuthorizationError("The selected location is not a directory");
27026
- }
27027
- return target;
27028
- } catch (cause) {
27029
- signal.throwIfAborted();
27030
- if (cause instanceof LocalAuthorizationError) {
27031
- throw cause;
27032
- }
27033
- throw new LocalAuthorizationError("This directory is missing or unavailable to your user account", {
27034
- cause
27035
- });
27323
+ return candidate;
27324
+ }
27325
+ function integerField(value, field) {
27326
+ const candidate = value[field];
27327
+ if (typeof candidate !== "number" || !Number.isSafeInteger(candidate) || candidate < 0) {
27328
+ throw invalidResponse(`The service returned an invalid ${field}`);
27329
+ }
27330
+ return candidate;
27331
+ }
27332
+ function validateTimestamp(value, field) {
27333
+ if (Number.isNaN(Date.parse(value))) {
27334
+ throw invalidResponse(`The service returned an invalid ${field}`);
27335
+ }
27336
+ return value;
27337
+ }
27338
+ var MobiusArtifactUploadRequest = class {
27339
+ byteLength;
27340
+ mediaType;
27341
+ name;
27342
+ sha256;
27343
+ constructor(name, mediaType, byteLength, sha256) {
27344
+ 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)) {
27345
+ throw new MobiusValidationError("The artifact upload request is invalid");
27036
27346
  }
27037
- };
27038
- label = (path2) => {
27039
- const suffix = relative4(homedir2(), path2);
27040
- return suffix === "" ? "~" : !isAbsolute7(suffix) && suffix !== ".." && !suffix.startsWith(`..${process.platform === "win32" ? "\\" : "/"}`) ? `~/${suffix.replaceAll("\\", "/")}` : path2;
27041
- };
27042
- identify = async (bindingId, requestedPath, signal) => {
27043
- this.authorizeMachine(bindingId);
27044
- const path2 = await this.resolvePath(requestedPath, signal);
27045
- return {
27046
- path: path2,
27047
- directoryId: encodePath(path2),
27048
- name: basename(path2) || path2,
27049
- label: this.label(path2)
27050
- };
27051
- };
27347
+ this.byteLength = byteLength;
27348
+ this.mediaType = mediaType;
27349
+ this.name = name;
27350
+ this.sha256 = sha256;
27351
+ }
27352
+ };
27353
+ var MobiusArtifact = class {
27354
+ artifactId;
27355
+ byteLength;
27356
+ createdAt;
27357
+ mediaType;
27358
+ name;
27359
+ sessionId;
27360
+ sha256;
27361
+ constructor(sessionId, artifactId, name, mediaType, byteLength, sha256, createdAt) {
27362
+ this.artifactId = artifactId;
27363
+ this.byteLength = byteLength;
27364
+ this.createdAt = createdAt;
27365
+ this.mediaType = mediaType;
27366
+ this.name = name;
27367
+ this.sessionId = sessionId;
27368
+ this.sha256 = sha256;
27369
+ }
27370
+ };
27371
+ var MobiusUploadingArtifact = class extends MobiusArtifact {
27372
+ expiresAt;
27373
+ state = "uploading";
27374
+ constructor(sessionId, artifactId, name, mediaType, byteLength, sha256, createdAt, expiresAt) {
27375
+ super(sessionId, artifactId, name, mediaType, byteLength, sha256, createdAt);
27376
+ this.expiresAt = expiresAt;
27377
+ }
27378
+ };
27379
+ var MobiusArtifactUpload = class extends MobiusUploadingArtifact {
27380
+ uploadToken;
27381
+ constructor(artifact, uploadToken) {
27382
+ super(
27383
+ artifact.sessionId,
27384
+ artifact.artifactId,
27385
+ artifact.name,
27386
+ artifact.mediaType,
27387
+ artifact.byteLength,
27388
+ artifact.sha256,
27389
+ artifact.createdAt,
27390
+ artifact.expiresAt
27391
+ );
27392
+ this.uploadToken = uploadToken;
27393
+ }
27394
+ };
27395
+ var MobiusAvailableArtifact = class extends MobiusArtifact {
27396
+ availableAt;
27397
+ state = "available";
27398
+ constructor(sessionId, artifactId, name, mediaType, byteLength, sha256, createdAt, availableAt) {
27399
+ super(sessionId, artifactId, name, mediaType, byteLength, sha256, createdAt);
27400
+ this.availableAt = availableAt;
27401
+ }
27402
+ };
27403
+ var MobiusExpiredArtifact = class extends MobiusArtifact {
27404
+ expiredAt;
27405
+ state = "expired";
27406
+ constructor(sessionId, artifactId, name, mediaType, byteLength, sha256, createdAt, expiredAt) {
27407
+ super(sessionId, artifactId, name, mediaType, byteLength, sha256, createdAt);
27408
+ this.expiredAt = expiredAt;
27409
+ }
27410
+ };
27411
+ function artifactFields(value) {
27412
+ const sha256 = stringField(value, "sha256", 64);
27413
+ if (!/^[a-f0-9]{64}$/.test(sha256)) {
27414
+ throw invalidResponse("The service returned an invalid artifact digest");
27415
+ }
27416
+ return {
27417
+ artifactId: identifierField(value, "artifactId"),
27418
+ byteLength: integerField(value, "byteLength"),
27419
+ createdAt: validateTimestamp(stringField(value, "createdAt", 128), "createdAt"),
27420
+ mediaType: stringField(value, "mediaType", 255),
27421
+ name: stringField(value, "name", 500),
27422
+ sessionId: identifierField(value, "sessionId"),
27423
+ sha256
27424
+ };
27425
+ }
27426
+ function uploadingArtifact(value) {
27427
+ const fields = artifactFields(value);
27428
+ return new MobiusUploadingArtifact(
27429
+ fields.sessionId,
27430
+ fields.artifactId,
27431
+ fields.name,
27432
+ fields.mediaType,
27433
+ fields.byteLength,
27434
+ fields.sha256,
27435
+ fields.createdAt,
27436
+ validateTimestamp(stringField(value, "expiresAt", 128), "expiresAt")
27437
+ );
27438
+ }
27439
+ function decodeMobiusArtifactUpload(value) {
27440
+ const artifact = record2(value, "artifact upload authorization");
27441
+ return new MobiusArtifactUpload(uploadingArtifact(artifact), stringField(artifact, "uploadToken", 256));
27442
+ }
27443
+ function decodeMobiusArtifact(value) {
27444
+ const artifact = record2(value, "artifact");
27445
+ const state = stringField(artifact, "state", 32);
27446
+ if (state === "uploading") {
27447
+ return uploadingArtifact(artifact);
27448
+ }
27449
+ const fields = artifactFields(artifact);
27450
+ if (state === "available") {
27451
+ return new MobiusAvailableArtifact(
27452
+ fields.sessionId,
27453
+ fields.artifactId,
27454
+ fields.name,
27455
+ fields.mediaType,
27456
+ fields.byteLength,
27457
+ fields.sha256,
27458
+ fields.createdAt,
27459
+ validateTimestamp(stringField(artifact, "availableAt", 128), "availableAt")
27460
+ );
27461
+ }
27462
+ if (state === "expired") {
27463
+ return new MobiusExpiredArtifact(
27464
+ fields.sessionId,
27465
+ fields.artifactId,
27466
+ fields.name,
27467
+ fields.mediaType,
27468
+ fields.byteLength,
27469
+ fields.sha256,
27470
+ fields.createdAt,
27471
+ validateTimestamp(stringField(artifact, "expiredAt", 128), "expiredAt")
27472
+ );
27473
+ }
27474
+ throw invalidResponse("The service returned an invalid artifact state");
27475
+ }
27476
+ function decodeMobiusAvailableArtifact(value) {
27477
+ const artifact = decodeMobiusArtifact(value);
27478
+ if (!(artifact instanceof MobiusAvailableArtifact)) {
27479
+ throw invalidResponse("The service did not make the artifact available");
27480
+ }
27481
+ return artifact;
27482
+ }
27483
+ var MobiusRuntimePairingLifecycle = Object.freeze({
27484
+ Expired: "expired",
27485
+ Paired: "paired",
27486
+ Pending: "pending",
27487
+ Revoked: "revoked"
27488
+ });
27489
+
27490
+ // src/artifacts/runtime-artifact-uploader.ts
27491
+ import { fetch as fetch3 } from "undici";
27492
+ var UPLOAD_TIMEOUT_MILLISECONDS = 2e4;
27493
+ var RuntimeArtifactUploadError = class extends Error {
27494
+ code;
27495
+ constructor(code, message, options = {}) {
27496
+ super(message, options);
27497
+ this.code = code;
27498
+ this.name = "RuntimeArtifactUploadError";
27499
+ }
27500
+ };
27501
+ var UploadedRuntimeArtifact = class {
27502
+ artifactId;
27503
+ byteLength;
27504
+ mimeType;
27505
+ name;
27506
+ sha256;
27507
+ constructor(artifactId, name, mimeType, byteLength, sha256) {
27508
+ this.artifactId = artifactId;
27509
+ this.byteLength = byteLength;
27510
+ this.mimeType = mimeType;
27511
+ this.name = name;
27512
+ this.sha256 = sha256;
27513
+ }
27514
+ };
27515
+ function daemonToken(config2) {
27516
+ const token = config2.relayUrl.searchParams.get("token");
27517
+ if (token === null || token.length < 32) {
27518
+ throw new RuntimeArtifactUploadError("artifact_endpoint_invalid", "The Relay daemon token is missing");
27519
+ }
27520
+ return token;
27521
+ }
27522
+ function channelOrigin(config2) {
27523
+ const url2 = new URL(config2.relayUrl);
27524
+ url2.protocol = url2.protocol === "wss:" ? "https:" : "http:";
27525
+ let channelPath = "";
27526
+ if (url2.pathname.endsWith("/daemon")) {
27527
+ channelPath = url2.pathname.slice(0, -"/daemon".length);
27528
+ } else {
27529
+ const runtimePath = `${MOBIUS_API_PREFIX}/v1/runtimes/connect`;
27530
+ if (!url2.pathname.endsWith("/v1/runtimes/connect") && !url2.pathname.endsWith(runtimePath)) {
27531
+ throw new RuntimeArtifactUploadError("artifact_endpoint_invalid", "The Relay artifact endpoint is invalid");
27532
+ }
27533
+ channelPath = `${url2.pathname.replace(/\/v1\/runtimes\/connect$/, "")}/channels/${encodeURIComponent(config2.channelId)}`;
27534
+ }
27535
+ url2.pathname = channelPath;
27536
+ url2.search = "";
27537
+ url2.hash = "";
27538
+ return url2;
27539
+ }
27540
+ function uploadError(code, message, cause) {
27541
+ return new RuntimeArtifactUploadError(code, message, cause === void 0 ? {} : { cause });
27542
+ }
27543
+ function translateSdkError(cause) {
27544
+ if (cause instanceof MobiusValidationError) {
27545
+ throw uploadError("artifact_upload_failed", cause.message, cause);
27546
+ }
27547
+ if (cause instanceof MobiusProtocolError) {
27548
+ throw uploadError("artifact_upload_failed", "The Relay returned an invalid upload response", cause);
27549
+ }
27550
+ throw cause;
27551
+ }
27552
+ async function readJson(response) {
27553
+ try {
27554
+ return await response.json();
27555
+ } catch (cause) {
27556
+ throw uploadError("artifact_upload_failed", "The Relay returned an invalid upload response", cause);
27557
+ }
27558
+ }
27559
+ async function readAuthorization(response) {
27560
+ try {
27561
+ return decodeMobiusArtifactUpload(await readJson(response));
27562
+ } catch (cause) {
27563
+ translateSdkError(cause);
27564
+ }
27565
+ }
27566
+ function sessionArtifactUrl(origin, sessionId, resourcePath, token) {
27567
+ const url2 = new URL(`${origin.pathname}/sessions/${encodeURIComponent(sessionId)}/${resourcePath}`, origin);
27568
+ url2.searchParams.set("token", token);
27569
+ return url2;
27570
+ }
27571
+ async function postLease(url2, request, signal) {
27572
+ return await fetch3(url2, {
27573
+ dispatcher: environmentProxyDispatcher,
27574
+ headers: { "content-type": "application/json" },
27575
+ method: "POST",
27576
+ body: JSON.stringify(request),
27577
+ signal
27578
+ });
27579
+ }
27580
+ async function putContent(url2, authorization, bytes, signal) {
27581
+ return await fetch3(url2, {
27582
+ dispatcher: environmentProxyDispatcher,
27583
+ headers: {
27584
+ "content-type": authorization.mediaType,
27585
+ "x-mobius-upload-token": authorization.uploadToken
27586
+ },
27587
+ method: "PUT",
27588
+ body: bytes,
27589
+ signal
27590
+ });
27591
+ }
27592
+ async function uploadRuntimeArtifact(config2, sessionId, image, signal) {
27593
+ signal.throwIfAborted();
27594
+ let request;
27595
+ try {
27596
+ request = new MobiusArtifactUploadRequest(
27597
+ image.name,
27598
+ image.mimeType,
27599
+ image.bytes.byteLength,
27600
+ createHash2("sha256").update(image.bytes).digest("hex")
27601
+ );
27602
+ } catch (cause) {
27603
+ translateSdkError(cause);
27604
+ }
27605
+ const timeoutSignal = AbortSignal.timeout(UPLOAD_TIMEOUT_MILLISECONDS);
27606
+ const requestSignal = AbortSignal.any([signal, timeoutSignal]);
27607
+ const origin = channelOrigin(config2);
27608
+ const token = daemonToken(config2);
27609
+ let created;
27610
+ try {
27611
+ created = await postLease(
27612
+ sessionArtifactUrl(origin, sessionId, "artifacts/uploads", token),
27613
+ request,
27614
+ requestSignal
27615
+ );
27616
+ } catch (cause) {
27617
+ signal.throwIfAborted();
27618
+ throw uploadError(
27619
+ timeoutSignal.aborted ? "artifact_upload_timeout" : "artifact_upload_failed",
27620
+ timeoutSignal.aborted ? "The artifact upload authorization timed out" : "The artifact upload could not start",
27621
+ cause
27622
+ );
27623
+ }
27624
+ if (!created.ok) {
27625
+ await created.body?.cancel();
27626
+ throw uploadError("artifact_upload_rejected", "The Relay rejected the artifact upload");
27627
+ }
27628
+ const authorization = await readAuthorization(created);
27629
+ let uploaded;
27630
+ try {
27631
+ uploaded = await putContent(
27632
+ sessionArtifactUrl(
27633
+ origin,
27634
+ sessionId,
27635
+ `artifacts/${encodeURIComponent(authorization.artifactId)}/content`,
27636
+ token
27637
+ ),
27638
+ authorization,
27639
+ image.bytes,
27640
+ requestSignal
27641
+ );
27642
+ } catch (cause) {
27643
+ signal.throwIfAborted();
27644
+ throw uploadError(
27645
+ timeoutSignal.aborted ? "artifact_upload_timeout" : "artifact_upload_failed",
27646
+ timeoutSignal.aborted ? "The artifact upload timed out" : "The artifact content could not be uploaded",
27647
+ cause
27648
+ );
27649
+ }
27650
+ if (!uploaded.ok) {
27651
+ await uploaded.body?.cancel();
27652
+ throw uploadError("artifact_upload_rejected", "The Relay rejected the artifact content");
27653
+ }
27654
+ try {
27655
+ const available = decodeMobiusAvailableArtifact(await readJson(uploaded));
27656
+ return new UploadedRuntimeArtifact(
27657
+ available.artifactId,
27658
+ available.name,
27659
+ available.mediaType,
27660
+ available.byteLength,
27661
+ available.sha256
27662
+ );
27663
+ } catch (cause) {
27664
+ translateSdkError(cause);
27665
+ }
27666
+ }
27667
+
27668
+ // src/authorization/local-authorization-error.ts
27669
+ var LocalAuthorizationError = class extends Error {
27670
+ code = "local_authorization_failed";
27671
+ constructor(message, options = {}) {
27672
+ super(message, options);
27673
+ this.name = "LocalAuthorizationError";
27674
+ }
27675
+ };
27676
+
27677
+ // src/authorization/workspace-directory.ts
27678
+ import { readdir, realpath as realpath7, stat as stat6 } from "node:fs/promises";
27679
+ import { homedir as homedir2 } from "node:os";
27680
+ import { basename as basename2, dirname as dirname5, isAbsolute as isAbsolute8, join as join14, normalize as normalize3, relative as relative5 } from "node:path";
27681
+ var WorkspaceDirectoryListing = class {
27682
+ directoryId;
27683
+ directoryLabel;
27684
+ entries;
27685
+ parentDirectoryId;
27686
+ constructor(directoryId2, directoryLabel, entries, parentDirectoryId) {
27687
+ this.directoryId = directoryId2;
27688
+ this.directoryLabel = directoryLabel;
27689
+ this.entries = entries;
27690
+ this.parentDirectoryId = parentDirectoryId;
27691
+ }
27692
+ };
27693
+ function encodePath(path2) {
27694
+ const encoded = Buffer.from(path2, "utf8").toString("base64url");
27695
+ if (encoded.length === 0 || encoded.length > 2e3) {
27696
+ throw new LocalAuthorizationError("The local directory path is too long to select");
27697
+ }
27698
+ return `path-${encoded}`;
27699
+ }
27700
+ function decodePath(value, prefix) {
27701
+ const encoded = value.slice(prefix.length);
27702
+ if (encoded.length === 0 || encoded.length > 2e3 || !/^[a-zA-Z0-9_-]+$/.test(encoded)) {
27703
+ throw new LocalAuthorizationError("The directory identifier is invalid");
27704
+ }
27705
+ const decoded = Buffer.from(encoded, "base64url").toString("utf8");
27706
+ if (Buffer.from(decoded, "utf8").toString("base64url") !== encoded || decoded.includes("\0") || normalize3(decoded) !== decoded) {
27707
+ throw new LocalAuthorizationError("The directory identifier is invalid");
27708
+ }
27709
+ return decoded;
27710
+ }
27711
+ var WorkspaceDirectoryService = class {
27712
+ #bindingId;
27713
+ #defaultWorkspace;
27714
+ constructor(bindingId, defaultWorkspace) {
27715
+ this.#bindingId = bindingId;
27716
+ this.#defaultWorkspace = defaultWorkspace;
27717
+ }
27718
+ authorizeMachine = (bindingId) => {
27719
+ if (bindingId !== this.#bindingId) {
27720
+ throw new LocalAuthorizationError("The runtime binding is not authorized");
27721
+ }
27722
+ };
27723
+ requestedPath = (id) => {
27724
+ if (id === "default") {
27725
+ return this.#defaultWorkspace;
27726
+ }
27727
+ if (id === "home") {
27728
+ return homedir2();
27729
+ }
27730
+ if (id.startsWith("path-")) {
27731
+ const path2 = decodePath(id, "path-");
27732
+ if (isAbsolute8(path2)) {
27733
+ return path2;
27734
+ }
27735
+ }
27736
+ throw new LocalAuthorizationError("The directory identifier is invalid");
27737
+ };
27738
+ resolvePath = async (requested, signal) => {
27739
+ signal.throwIfAborted();
27740
+ if (!isAbsolute8(requested) || requested.includes("\0") || normalize3(requested) !== requested) {
27741
+ throw new LocalAuthorizationError("The local directory path is invalid");
27742
+ }
27743
+ try {
27744
+ const target = await realpath7(requested);
27745
+ signal.throwIfAborted();
27746
+ const metadata = await stat6(target);
27747
+ signal.throwIfAborted();
27748
+ if (!isAbsolute8(target) || normalize3(target) !== target || !metadata.isDirectory()) {
27749
+ throw new LocalAuthorizationError("The selected location is not a directory");
27750
+ }
27751
+ return target;
27752
+ } catch (cause) {
27753
+ signal.throwIfAborted();
27754
+ if (cause instanceof LocalAuthorizationError) {
27755
+ throw cause;
27756
+ }
27757
+ throw new LocalAuthorizationError("This directory is missing or unavailable to your user account", {
27758
+ cause
27759
+ });
27760
+ }
27761
+ };
27762
+ label = (path2) => {
27763
+ const suffix = relative5(homedir2(), path2);
27764
+ return suffix === "" ? "~" : !isAbsolute8(suffix) && suffix !== ".." && !suffix.startsWith(`..${process.platform === "win32" ? "\\" : "/"}`) ? `~/${suffix.replaceAll("\\", "/")}` : path2;
27765
+ };
27766
+ identify = async (bindingId, requestedPath, signal) => {
27767
+ this.authorizeMachine(bindingId);
27768
+ const path2 = await this.resolvePath(requestedPath, signal);
27769
+ return {
27770
+ path: path2,
27771
+ directoryId: encodePath(path2),
27772
+ name: basename2(path2) || path2,
27773
+ label: this.label(path2)
27774
+ };
27775
+ };
27052
27776
  resolve = async (bindingId, id, signal) => {
27053
27777
  this.authorizeMachine(bindingId);
27054
27778
  return await this.resolvePath(this.requestedPath(id), signal);
@@ -27102,8 +27826,8 @@ var WorkspaceDirectoryService = class {
27102
27826
  };
27103
27827
 
27104
27828
  // src/bots/local-bot-grant-store.ts
27105
- import { createHash as createHash2, randomUUID } from "node:crypto";
27106
- import { stat as stat6 } from "node:fs/promises";
27829
+ import { createHash as createHash3, randomUUID } from "node:crypto";
27830
+ import { stat as stat7 } from "node:fs/promises";
27107
27831
  import { DatabaseSync as DatabaseSync3 } from "node:sqlite";
27108
27832
  var LOCAL_BOT_GRANT_LIFETIME_MILLISECONDS = 90 * 24 * 60 * 60 * 1e3;
27109
27833
  var LocalBotAuthorizationError = class extends Error {
@@ -27147,7 +27871,7 @@ var LocalBotGrant = class {
27147
27871
  }
27148
27872
  };
27149
27873
  function digest(value) {
27150
- return createHash2("sha256").update(value, "utf8").digest("hex");
27874
+ return createHash3("sha256").update(value, "utf8").digest("hex");
27151
27875
  }
27152
27876
  function agentDigest(agent) {
27153
27877
  return digest(
@@ -27161,7 +27885,7 @@ function agentDigest(agent) {
27161
27885
  );
27162
27886
  }
27163
27887
  async function workspaceDigest(path2) {
27164
- const metadata = await stat6(path2);
27888
+ const metadata = await stat7(path2);
27165
27889
  if (!metadata.isDirectory()) {
27166
27890
  throw new LocalBotAuthorizationError("binding_incompatible", "The Bot workspace is not a directory");
27167
27891
  }
@@ -27578,12 +28302,12 @@ var BotExecutionContextRegistry = class {
27578
28302
  // src/bots/bot-outbound-ipc.ts
27579
28303
  import { chmod as chmod2, mkdir as mkdir3, unlink } from "node:fs/promises";
27580
28304
  import { createServer } from "node:net";
27581
- import { dirname as dirname6, isAbsolute as isAbsolute8 } from "node:path";
27582
- import { fetch as fetch3 } from "undici";
28305
+ import { dirname as dirname6, isAbsolute as isAbsolute9 } from "node:path";
28306
+ import { fetch as fetch4 } from "undici";
27583
28307
  var BOT_IPC_REQUEST_LIMIT = 32 * 1024;
27584
28308
  var BOT_IPC_TIMEOUT_MILLISECONDS = 2e4;
27585
28309
  var BOT_RELAY_TIMEOUT_MILLISECONDS = 2e4;
27586
- var IDENTIFIER_PATTERN5 = /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/;
28310
+ var IDENTIFIER_PATTERN6 = /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/;
27587
28311
  var WINDOWS_NAMED_PIPE_PREFIX = "\\\\.\\pipe\\";
27588
28312
  var BotOutboundIpcRequest = class {
27589
28313
  contextHandle;
@@ -27597,7 +28321,7 @@ var BotOutboundIpcRequest = class {
27597
28321
  this.text = text;
27598
28322
  }
27599
28323
  };
27600
- function isRecord9(value) {
28324
+ function isRecord10(value) {
27601
28325
  return typeof value === "object" && value !== null && !Array.isArray(value);
27602
28326
  }
27603
28327
  function decodeRequest(encoded) {
@@ -27607,7 +28331,7 @@ function decodeRequest(encoded) {
27607
28331
  } catch (cause) {
27608
28332
  throw new LocalBotAuthorizationError("invalid_request", "The local Bot request is invalid", { cause });
27609
28333
  }
27610
- if (!isRecord9(value)) {
28334
+ if (!isRecord10(value)) {
27611
28335
  throw new LocalBotAuthorizationError("invalid_request", "The local Bot request is invalid");
27612
28336
  }
27613
28337
  const keys = Object.keys(value);
@@ -27618,7 +28342,7 @@ function decodeRequest(encoded) {
27618
28342
  const idempotencyKey = value["idempotencyKey"];
27619
28343
  const target = value["target"];
27620
28344
  const text = value["text"];
27621
- if (typeof contextHandle !== "string" || !/^ctx_[a-zA-Z0-9_-]{43}$/.test(contextHandle) || typeof idempotencyKey !== "string" || !IDENTIFIER_PATTERN5.test(idempotencyKey) || typeof target !== "string" || !IDENTIFIER_PATTERN5.test(target) || typeof text !== "string" || text.trim().length === 0 || text.length > 1e4) {
28345
+ 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) {
27622
28346
  throw new LocalBotAuthorizationError("invalid_request", "The local Bot request is invalid");
27623
28347
  }
27624
28348
  return new BotOutboundIpcRequest(contextHandle, idempotencyKey, target, text);
@@ -27640,7 +28364,7 @@ function relayEndpoint(relayUrl, context, target) {
27640
28364
  endpoint.pathname = `${MOBIUS_API_PREFIX}/v1/bot-executions/${execution}/delivery-targets/${encodeURIComponent(deliveryTargetId)}/messages`;
27641
28365
  return endpoint;
27642
28366
  }
27643
- function daemonToken(relayUrl) {
28367
+ function daemonToken2(relayUrl) {
27644
28368
  const token = relayUrl.searchParams.get("token") ?? "";
27645
28369
  if (!/^[a-zA-Z0-9_-]{32,256}$/.test(token)) {
27646
28370
  throw new LocalBotAuthorizationError("bot_service_unavailable", "The Runtime credential is unavailable");
@@ -27657,10 +28381,10 @@ async function decodeRelayResponse(response) {
27657
28381
  cause
27658
28382
  });
27659
28383
  }
27660
- if (response.status === 202 && isRecord9(value) && typeof value["outboundMessageId"] === "string") {
28384
+ if (response.status === 202 && isRecord10(value) && typeof value["outboundMessageId"] === "string") {
27661
28385
  return value["outboundMessageId"];
27662
28386
  }
27663
- if (isRecord9(value) && isRecord9(value["error"])) {
28387
+ if (isRecord10(value) && isRecord10(value["error"])) {
27664
28388
  const error61 = value["error"];
27665
28389
  if (typeof error61["code"] === "string" && typeof error61["message"] === "string") {
27666
28390
  throw new LocalBotAuthorizationError(error61["code"], error61["message"]);
@@ -27676,7 +28400,7 @@ var BotOutboundIpcServer = class {
27676
28400
  #usesFilesystemSocket;
27677
28401
  constructor(socketPath, relayUrl, registry2) {
27678
28402
  const usesFilesystemSocket = !socketPath.startsWith(WINDOWS_NAMED_PIPE_PREFIX);
27679
- if (usesFilesystemSocket && !isAbsolute8(socketPath)) {
28403
+ if (usesFilesystemSocket && !isAbsolute9(socketPath)) {
27680
28404
  throw new Error("The Bot IPC path must be absolute");
27681
28405
  }
27682
28406
  this.#registry = registry2;
@@ -27693,7 +28417,7 @@ var BotOutboundIpcServer = class {
27693
28417
  if (this.#usesFilesystemSocket) {
27694
28418
  await mkdir3(dirname6(this.#socketPath), { mode: 448, recursive: true });
27695
28419
  await unlink(this.#socketPath).catch((error61) => {
27696
- if (!isRecord9(error61) || error61["code"] !== "ENOENT") {
28420
+ if (!isRecord10(error61) || error61["code"] !== "ENOENT") {
27697
28421
  throw error61;
27698
28422
  }
27699
28423
  });
@@ -27728,7 +28452,7 @@ var BotOutboundIpcServer = class {
27728
28452
  }
27729
28453
  if (this.#usesFilesystemSocket) {
27730
28454
  await unlink(this.#socketPath).catch((error61) => {
27731
- if (!isRecord9(error61) || error61["code"] !== "ENOENT") {
28455
+ if (!isRecord10(error61) || error61["code"] !== "ENOENT") {
27732
28456
  throw error61;
27733
28457
  }
27734
28458
  });
@@ -27792,10 +28516,10 @@ var BotOutboundIpcServer = class {
27792
28516
  const requestSignal = AbortSignal.any([signal, timeout]);
27793
28517
  let response;
27794
28518
  try {
27795
- response = await fetch3(relayEndpoint(this.#relayUrl, context, request.target), {
28519
+ response = await fetch4(relayEndpoint(this.#relayUrl, context, request.target), {
27796
28520
  body: JSON.stringify({ idempotencyKey: request.idempotencyKey, text: request.text }),
27797
28521
  headers: {
27798
- authorization: `Bearer ${daemonToken(this.#relayUrl)}`,
28522
+ authorization: `Bearer ${daemonToken2(this.#relayUrl)}`,
27799
28523
  "content-type": "application/json",
27800
28524
  "x-mobius-bot-execution-capability": context.command.executionCapabilitySecret
27801
28525
  },
@@ -27816,7 +28540,7 @@ var BotOutboundIpcServer = class {
27816
28540
 
27817
28541
  // src/native-sessions/service.ts
27818
28542
  import { randomUUID as randomUUID2 } from "node:crypto";
27819
- import { basename as basename2 } from "node:path";
28543
+ import { basename as basename3 } from "node:path";
27820
28544
 
27821
28545
  // src/native-sessions/codex-history.ts
27822
28546
  import { spawn as spawn4 } from "node:child_process";
@@ -27849,7 +28573,6 @@ function decodeHistory(thread, value) {
27849
28573
  const page = turnsSchema.parse(value);
27850
28574
  const messages = [];
27851
28575
  let characters = 0;
27852
- let imageCharacters = 0;
27853
28576
  let truncated = page.nextCursor != null;
27854
28577
  for (const turn of page.data.toReversed()) {
27855
28578
  for (const item of turn.items) {
@@ -27857,22 +28580,19 @@ function decodeHistory(thread, value) {
27857
28580
  let message;
27858
28581
  if (type === "userMessage") {
27859
28582
  const { content } = userMessageSchema.parse(item);
27860
- const parsed = parseNativeHistoryText(
27861
- content.map((block) => {
27862
- const { type: type2 } = itemTypeSchema.parse(block);
27863
- if (type2 === "text") {
27864
- return textSchema.parse(block).text;
27865
- }
27866
- if (type2 === "image") {
27867
- return `[@image](${imageSchema.parse(block).url})`;
27868
- }
27869
- return "[Attachment]";
27870
- }).join("")
27871
- );
28583
+ const text2 = content.map((block) => {
28584
+ const { type: type2 } = itemTypeSchema.parse(block);
28585
+ if (type2 === "text") {
28586
+ return textSchema.parse(block).text;
28587
+ }
28588
+ if (type2 === "image") {
28589
+ return `[@image](${imageSchema.parse(block).url})`;
28590
+ }
28591
+ return "[Attachment]";
28592
+ }).join("");
27872
28593
  message = {
27873
28594
  role: "user",
27874
- text: parsed.text,
27875
- ...parsed.images.length > 0 ? { images: parsed.images } : {}
28595
+ text: text2
27876
28596
  };
27877
28597
  } else if (type === "agentMessage") {
27878
28598
  const agent = agentMessageSchema.parse(item);
@@ -27890,12 +28610,10 @@ function decodeHistory(thread, value) {
27890
28610
  truncated ||= text.length < message.text.length;
27891
28611
  messages.push({ ...message, text });
27892
28612
  characters += text.length;
27893
- imageCharacters += (message.images ?? []).reduce((size, image) => size + image.data.length, 0);
27894
- while (messages.length > SESSION_HISTORY_PREVIEW_MESSAGE_LIMIT || characters > SESSION_HISTORY_CHARACTER_LIMIT || imageCharacters > SESSION_HISTORY_IMAGE_CHARACTER_LIMIT) {
28613
+ while (messages.length > SESSION_HISTORY_PREVIEW_MESSAGE_LIMIT || characters > SESSION_HISTORY_CHARACTER_LIMIT) {
27895
28614
  const removed = messages.shift();
27896
28615
  if (removed !== void 0) {
27897
28616
  characters -= removed.text.length;
27898
- imageCharacters -= (removed.images ?? []).reduce((size, image) => size + image.data.length, 0);
27899
28617
  }
27900
28618
  truncated = true;
27901
28619
  }
@@ -28053,7 +28771,11 @@ async function readCodexHistory(agent, cwd, nativeSessionId, signal) {
28053
28771
  params: { clientInfo: { name: "mobius_history", version: "1.0.0" } }
28054
28772
  });
28055
28773
  }
28056
- return await response.promise;
28774
+ const snapshot = await response.promise;
28775
+ return {
28776
+ ...snapshot,
28777
+ history: await embedLocalHistoryImages(snapshot.history, [cwd, snapshot.cwd], signal)
28778
+ };
28057
28779
  } finally {
28058
28780
  clearTimeout(timeout);
28059
28781
  signal.removeEventListener("abort", abort);
@@ -28307,7 +29029,7 @@ var NativeSessionService = class {
28307
29029
  }
28308
29030
  resolvedPaths.add(path2);
28309
29031
  additionalDirectories.push(path2);
28310
- additionalEntries.push({ directoryId: directoryId2, name: basename2(path2) });
29032
+ additionalEntries.push({ directoryId: directoryId2, name: basename3(path2) });
28311
29033
  }
28312
29034
  const listing = await this.#directories.list(this.#config.bindingId, command.directoryId, signal);
28313
29035
  const opened = await this.#sessions.forkSessionAtTurn(
@@ -28446,13 +29168,13 @@ var NativeSessionService = class {
28446
29168
  };
28447
29169
 
28448
29170
  // src/prompt-artifact-resolver.ts
28449
- import { createHash as createHash3 } from "node:crypto";
28450
- import { fetch as fetch4 } from "undici";
29171
+ import { createHash as createHash4 } from "node:crypto";
29172
+ import { fetch as fetch5 } from "undici";
28451
29173
  var ARTIFACT_SCHEME = "mobius-artifact:";
28452
29174
  var ARTIFACT_DOWNLOAD_TIMEOUT_MILLISECONDS = 2e4;
28453
29175
  var MAX_AGENT_IMAGE_BASE64_LENGTH = 4e6;
28454
29176
  var MAX_AGENT_RESOURCE_BYTE_LENGTH = 1e6;
28455
- var IDENTIFIER_PATTERN6 = /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/;
29177
+ var IDENTIFIER_PATTERN7 = /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/;
28456
29178
  var PromptArtifactError = class extends Error {
28457
29179
  code;
28458
29180
  constructor(code, message, options = {}) {
@@ -28495,14 +29217,13 @@ function parseReference(resource) {
28495
29217
  const encodedByteLength2 = url2.searchParams.get("byteLength") ?? "";
28496
29218
  const sha256 = url2.searchParams.get("sha256") ?? "";
28497
29219
  const byteLength = Number(encodedByteLength2);
28498
- if (url2.protocol !== ARTIFACT_SCHEME || url2.hash.length > 0 || resource.type !== "link" || resource.text.length > 0 || !IDENTIFIER_PATTERN6.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)) {
29220
+ 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)) {
28499
29221
  throw new PromptArtifactError("artifact_reference_invalid", "The prompt artifact reference is invalid");
28500
29222
  }
28501
29223
  return new PromptArtifactReference(artifactId, byteLength, sha256, resource);
28502
29224
  }
28503
29225
  function downloadUrl(config2, command, reference) {
28504
- const url2 = new URL(config2.relayUrl);
28505
- url2.protocol = url2.protocol === "wss:" ? "https:" : "http:";
29226
+ const url2 = relayHttpEndpoint(config2.relayUrl);
28506
29227
  let channelPath = "";
28507
29228
  if (url2.pathname.endsWith("/daemon")) {
28508
29229
  channelPath = url2.pathname.slice(0, -"/daemon".length);
@@ -28514,7 +29235,6 @@ function downloadUrl(config2, command, reference) {
28514
29235
  channelPath = `${url2.pathname.slice(0, -runtimePath.length)}/channels/${encodeURIComponent(config2.channelId)}`;
28515
29236
  }
28516
29237
  url2.pathname = `${channelPath}/sessions/${encodeURIComponent(command.sessionId)}/commands/${encodeURIComponent(command.commandId)}/artifacts/${encodeURIComponent(reference.artifactId)}/content`;
28517
- url2.searchParams.delete("liveness");
28518
29238
  return url2;
28519
29239
  }
28520
29240
  async function responseBytes(response, expectedByteLength, signal) {
@@ -28563,9 +29283,13 @@ async function download(config2, command, reference, signal) {
28563
29283
  const requestSignal = AbortSignal.any([signal, timeoutSignal]);
28564
29284
  let response;
28565
29285
  try {
28566
- response = await fetch4(downloadUrl(config2, command, reference), {
29286
+ response = await fetch5(downloadUrl(config2, command, reference), {
28567
29287
  dispatcher: environmentProxyDispatcher,
28568
- headers: { accept: reference.resource.mimeType },
29288
+ headers: {
29289
+ accept: reference.resource.mimeType,
29290
+ "accept-encoding": "identity",
29291
+ ...runtimeAuthorization(config2.relayUrl)
29292
+ },
28569
29293
  signal: requestSignal
28570
29294
  });
28571
29295
  if (!response.ok) {
@@ -28583,7 +29307,7 @@ async function download(config2, command, reference, signal) {
28583
29307
  );
28584
29308
  }
28585
29309
  const bytes = await responseBytes(response, reference.byteLength, requestSignal);
28586
- if (createHash3("sha256").update(bytes).digest("hex") !== reference.sha256) {
29310
+ if (createHash4("sha256").update(bytes).digest("hex") !== reference.sha256) {
28587
29311
  throw new PromptArtifactError(
28588
29312
  "artifact_integrity_failed",
28589
29313
  "The prompt artifact failed integrity validation"
@@ -28675,12 +29399,8 @@ function connectRelay(url2, signal) {
28675
29399
  signal.throwIfAborted();
28676
29400
  return new Promise((resolve6, reject) => {
28677
29401
  const endpoint = new URL(url2);
28678
- const headers = {};
28679
- if (endpoint.pathname.endsWith("/v1/runtimes/connect")) {
28680
- const runtimeCredential = endpoint.searchParams.get("token") ?? "";
28681
- endpoint.searchParams.delete("token");
28682
- headers["authorization"] = `Bearer ${runtimeCredential}`;
28683
- }
29402
+ const headers = runtimeAuthorization(endpoint);
29403
+ endpoint.searchParams.delete("token");
28684
29404
  const socket = new WebSocket(endpoint, {
28685
29405
  dispatcher: environmentProxyDispatcher,
28686
29406
  headers
@@ -29003,6 +29723,42 @@ var RelayConnectionLiveness = class {
29003
29723
  import { mkdirSync as mkdirSync3 } from "node:fs";
29004
29724
  import { dirname as dirname7 } from "node:path";
29005
29725
  import { DatabaseSync as DatabaseSync4 } from "node:sqlite";
29726
+ var DEFAULT_OUTBOX_LIMITS = {
29727
+ criticalEventBytes: 136 * 1024 * 1024,
29728
+ criticalEventCount: 10128,
29729
+ runtimeDeliveryBytes: 64 * 1024 * 1024,
29730
+ runtimeDeliveryCount: 64,
29731
+ standardEventBytes: 128 * 1024 * 1024,
29732
+ standardEventCount: 1e4
29733
+ };
29734
+ var SessionEventOutboxCapacityError = class extends Error {
29735
+ code = "session_event_outbox_full";
29736
+ constructor() {
29737
+ super("The durable Session event outbox is full");
29738
+ this.name = "SessionEventOutboxCapacityError";
29739
+ }
29740
+ };
29741
+ var RuntimeDeliveryInboxCapacityError = class extends Error {
29742
+ code = "runtime_delivery_inbox_full";
29743
+ constructor() {
29744
+ super("The durable Runtime delivery inbox is full");
29745
+ this.name = "RuntimeDeliveryInboxCapacityError";
29746
+ }
29747
+ };
29748
+ var StoredRuntimeDelivery = class {
29749
+ deliveryId;
29750
+ duplicate;
29751
+ payload;
29752
+ sessionId;
29753
+ state;
29754
+ constructor(deliveryId, sessionId, payload, state, duplicate) {
29755
+ this.deliveryId = deliveryId;
29756
+ this.duplicate = duplicate;
29757
+ this.payload = payload;
29758
+ this.sessionId = sessionId;
29759
+ this.state = state;
29760
+ }
29761
+ };
29006
29762
  function readPendingEnvelope(row) {
29007
29763
  if (typeof row !== "object" || row === null || Array.isArray(row)) {
29008
29764
  throw new Error("SQLite returned an invalid session event outbox row");
@@ -29013,9 +29769,26 @@ function readPendingEnvelope(row) {
29013
29769
  }
29014
29770
  return envelope2;
29015
29771
  }
29772
+ function rowNumber(row, field) {
29773
+ const value = typeof row === "object" && row !== null ? Reflect.get(row, field) : void 0;
29774
+ if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0) {
29775
+ throw new Error(`SQLite returned an invalid ${field} value`);
29776
+ }
29777
+ return value;
29778
+ }
29779
+ function rowString2(row, field) {
29780
+ const value = typeof row === "object" && row !== null ? Reflect.get(row, field) : void 0;
29781
+ if (typeof value !== "string" || value.length === 0) {
29782
+ throw new Error(`SQLite returned an invalid ${field} value`);
29783
+ }
29784
+ return value;
29785
+ }
29016
29786
  var SessionEventOutbox = class {
29017
29787
  #database;
29018
- constructor(path2) {
29788
+ #limits;
29789
+ constructor(path2, limits = DEFAULT_OUTBOX_LIMITS) {
29790
+ validateLimits(limits);
29791
+ this.#limits = limits;
29019
29792
  mkdirSync3(dirname7(path2), { recursive: true });
29020
29793
  this.#database = new DatabaseSync4(path2);
29021
29794
  this.#database.exec(`
@@ -29024,6 +29797,7 @@ var SessionEventOutbox = class {
29024
29797
  event_id TEXT NOT NULL UNIQUE,
29025
29798
  session_id TEXT NOT NULL,
29026
29799
  source_key TEXT NOT NULL,
29800
+ byte_length INTEGER NOT NULL,
29027
29801
  envelope_json TEXT NOT NULL
29028
29802
  ) STRICT;
29029
29803
  CREATE INDEX IF NOT EXISTS relay_session_event_outbox_order
@@ -29034,7 +29808,7 @@ var SessionEventOutbox = class {
29034
29808
  session_id TEXT NOT NULL,
29035
29809
  envelope_json TEXT NOT NULL,
29036
29810
  rejection_code TEXT NOT NULL CHECK (
29037
- rejection_code IN ('session_deleted', 'session_not_found')
29811
+ rejection_code IN ('session_deleted', 'session_not_found', 'session_rejected')
29038
29812
  )
29039
29813
  ) STRICT;
29040
29814
  CREATE TABLE IF NOT EXISTS relay_session_event_sources (
@@ -29050,7 +29824,53 @@ var SessionEventOutbox = class {
29050
29824
  state IN ('dispatching', 'running', 'succeeded', 'failed', 'cancelled')
29051
29825
  )
29052
29826
  ) STRICT;
29827
+ CREATE TABLE IF NOT EXISTS relay_session_event_outbox_state (
29828
+ singleton INTEGER PRIMARY KEY CHECK (singleton = 1),
29829
+ event_count INTEGER NOT NULL,
29830
+ total_bytes INTEGER NOT NULL
29831
+ ) STRICT;
29832
+ INSERT OR IGNORE INTO relay_session_event_outbox_state (
29833
+ singleton, event_count, total_bytes
29834
+ ) VALUES (1, 0, 0);
29835
+ CREATE TABLE IF NOT EXISTS relay_runtime_deliveries (
29836
+ delivery_id TEXT PRIMARY KEY,
29837
+ session_id TEXT NOT NULL,
29838
+ payload_json TEXT NOT NULL,
29839
+ payload_bytes INTEGER NOT NULL,
29840
+ state TEXT NOT NULL CHECK (
29841
+ state IN ('received', 'relay_committed', 'processed')
29842
+ ),
29843
+ received_at INTEGER NOT NULL
29844
+ ) STRICT;
29053
29845
  `);
29846
+ const deadLetterTable = this.#database.prepare(
29847
+ `SELECT sql FROM sqlite_master
29848
+ WHERE type = 'table' AND name = 'relay_session_event_dead_letters'`
29849
+ ).get();
29850
+ const deadLetterSql = typeof deadLetterTable === "object" && deadLetterTable !== null ? Reflect.get(deadLetterTable, "sql") : void 0;
29851
+ if (typeof deadLetterSql !== "string" || !deadLetterSql.includes("'session_rejected'")) {
29852
+ this.#database.exec(`
29853
+ BEGIN IMMEDIATE;
29854
+ ALTER TABLE relay_session_event_dead_letters
29855
+ RENAME TO relay_session_event_dead_letters_legacy;
29856
+ CREATE TABLE relay_session_event_dead_letters (
29857
+ ordinal INTEGER PRIMARY KEY,
29858
+ event_id TEXT NOT NULL UNIQUE,
29859
+ session_id TEXT NOT NULL,
29860
+ envelope_json TEXT NOT NULL,
29861
+ rejection_code TEXT NOT NULL CHECK (
29862
+ rejection_code IN ('session_deleted', 'session_not_found', 'session_rejected')
29863
+ )
29864
+ ) STRICT;
29865
+ INSERT INTO relay_session_event_dead_letters (
29866
+ ordinal, event_id, session_id, envelope_json, rejection_code
29867
+ )
29868
+ SELECT ordinal, event_id, session_id, envelope_json, rejection_code
29869
+ FROM relay_session_event_dead_letters_legacy;
29870
+ DROP TABLE relay_session_event_dead_letters_legacy;
29871
+ COMMIT;
29872
+ `);
29873
+ }
29054
29874
  const outboxColumns = this.#database.prepare("PRAGMA table_info(relay_session_event_outbox)").all();
29055
29875
  const hasSourceKey = outboxColumns.some(
29056
29876
  (column) => typeof column === "object" && column !== null && Reflect.get(column, "name") === "source_key"
@@ -29061,6 +29881,15 @@ var SessionEventOutbox = class {
29061
29881
  ADD COLUMN source_key TEXT NOT NULL DEFAULT '';
29062
29882
  `);
29063
29883
  }
29884
+ const hasByteLength = outboxColumns.some(
29885
+ (column) => typeof column === "object" && column !== null && Reflect.get(column, "name") === "byte_length"
29886
+ );
29887
+ if (!hasByteLength) {
29888
+ this.#database.exec(`
29889
+ ALTER TABLE relay_session_event_outbox
29890
+ ADD COLUMN byte_length INTEGER NOT NULL DEFAULT 0;
29891
+ `);
29892
+ }
29064
29893
  this.#database.exec(`
29065
29894
  UPDATE relay_session_event_outbox
29066
29895
  SET source_key = CASE json_extract(envelope_json, '$.source.kind')
@@ -29069,6 +29898,16 @@ var SessionEventOutbox = class {
29069
29898
  ELSE 'runtime:' || session_id
29070
29899
  END
29071
29900
  WHERE source_key = '';
29901
+ UPDATE relay_session_event_outbox
29902
+ SET byte_length = length(CAST(envelope_json AS BLOB))
29903
+ WHERE byte_length = 0;
29904
+ UPDATE relay_session_event_outbox_state
29905
+ SET event_count = (SELECT COUNT(*) FROM relay_session_event_outbox),
29906
+ total_bytes = (
29907
+ SELECT COALESCE(SUM(byte_length), 0)
29908
+ FROM relay_session_event_outbox
29909
+ )
29910
+ WHERE singleton = 1;
29072
29911
  CREATE INDEX IF NOT EXISTS relay_session_event_outbox_source_order
29073
29912
  ON relay_session_event_outbox(source_key, ordinal);
29074
29913
  `);
@@ -29129,13 +29968,19 @@ var SessionEventOutbox = class {
29129
29968
  const state = typeof row === "object" && row !== null ? Reflect.get(row, "state") : void 0;
29130
29969
  return state === "succeeded" || state === "failed" || state === "cancelled";
29131
29970
  };
29132
- acknowledge = (acknowledgement) => this.#database.prepare(
29133
- `DELETE FROM relay_session_event_outbox
29134
- WHERE event_id = ? AND session_id = ?`
29135
- ).run(acknowledgement.eventId, acknowledgement.sessionId).changes === 1;
29971
+ acknowledge = (acknowledgement) => this.#removeAcknowledgedEvent(acknowledgement.eventId, acknowledgement.sessionId);
29136
29972
  quarantine = (rejection) => {
29137
29973
  this.#database.exec("BEGIN IMMEDIATE");
29138
29974
  try {
29975
+ const stored = this.#database.prepare(
29976
+ `SELECT byte_length FROM relay_session_event_outbox
29977
+ WHERE event_id = ? AND session_id = ?`
29978
+ ).get(rejection.eventId, rejection.sessionId);
29979
+ if (stored === void 0) {
29980
+ this.#database.exec("COMMIT");
29981
+ return false;
29982
+ }
29983
+ const byteLength = rowNumber(stored, "byte_length");
29139
29984
  const insertion = this.#database.prepare(
29140
29985
  `INSERT INTO relay_session_event_dead_letters (
29141
29986
  ordinal, event_id, session_id, envelope_json, rejection_code
@@ -29155,6 +30000,7 @@ var SessionEventOutbox = class {
29155
30000
  if (deletion.changes !== 1) {
29156
30001
  throw new Error("The rejected session event could not be removed from the durable outbox");
29157
30002
  }
30003
+ this.#decrementEventState(byteLength);
29158
30004
  this.#database.exec("COMMIT");
29159
30005
  return true;
29160
30006
  } catch (error61) {
@@ -29166,7 +30012,129 @@ var SessionEventOutbox = class {
29166
30012
  this.#database.close();
29167
30013
  };
29168
30014
  enqueue = (sessionId, payload, attemptId = null) => {
29169
- const sourceKey = attemptId === null ? `runtime:${sessionId}` : `attempt:${sessionId}:${attemptId}`;
30015
+ return this.#enqueueBounded(
30016
+ sessionId,
30017
+ payload,
30018
+ attemptId ?? "",
30019
+ this.#limits.standardEventCount,
30020
+ this.#limits.standardEventBytes
30021
+ );
30022
+ };
30023
+ enqueueCritical = (sessionId, payload, attemptId = "") => this.#enqueueBounded(
30024
+ sessionId,
30025
+ payload,
30026
+ attemptId,
30027
+ this.#limits.criticalEventCount,
30028
+ this.#limits.criticalEventBytes
30029
+ );
30030
+ claimRuntimeDelivery = (delivery) => {
30031
+ const payloadBytes = new TextEncoder().encode(delivery.payload).byteLength;
30032
+ this.#database.exec("BEGIN IMMEDIATE");
30033
+ try {
30034
+ const existing = this.#database.prepare(
30035
+ `SELECT session_id, payload_json, state
30036
+ FROM relay_runtime_deliveries
30037
+ WHERE delivery_id = ?`
30038
+ ).get(delivery.deliveryId);
30039
+ if (existing !== void 0) {
30040
+ const sessionId = rowString2(existing, "session_id");
30041
+ const payload = rowString2(existing, "payload_json");
30042
+ const state = runtimeDeliveryState(existing);
30043
+ if (sessionId !== delivery.sessionId || payload !== delivery.payload) {
30044
+ throw new Error("The Runtime delivery identity conflicts with its durable receipt");
30045
+ }
30046
+ this.#database.exec("COMMIT");
30047
+ return new StoredRuntimeDelivery(delivery.deliveryId, sessionId, payload, state, true);
30048
+ }
30049
+ const usage = this.#database.prepare(
30050
+ `SELECT COUNT(*) AS delivery_count,
30051
+ COALESCE(SUM(payload_bytes), 0) AS delivery_bytes
30052
+ FROM relay_runtime_deliveries`
30053
+ ).get();
30054
+ if (rowNumber(usage, "delivery_count") + 1 > this.#limits.runtimeDeliveryCount || rowNumber(usage, "delivery_bytes") + payloadBytes > this.#limits.runtimeDeliveryBytes) {
30055
+ throw new RuntimeDeliveryInboxCapacityError();
30056
+ }
30057
+ this.#database.prepare(
30058
+ `INSERT INTO relay_runtime_deliveries (
30059
+ delivery_id, session_id, payload_json, payload_bytes, state, received_at
30060
+ ) VALUES (?, ?, ?, ?, 'received', ?)`
30061
+ ).run(delivery.deliveryId, delivery.sessionId, delivery.payload, payloadBytes, Date.now());
30062
+ this.#database.exec("COMMIT");
30063
+ return new StoredRuntimeDelivery(
30064
+ delivery.deliveryId,
30065
+ delivery.sessionId,
30066
+ delivery.payload,
30067
+ "received",
30068
+ false
30069
+ );
30070
+ } catch (error61) {
30071
+ this.#database.exec("ROLLBACK");
30072
+ throw error61;
30073
+ }
30074
+ };
30075
+ markRuntimeDeliveryCommitted = (deliveryId, sessionId) => {
30076
+ this.#database.exec("BEGIN IMMEDIATE");
30077
+ try {
30078
+ const row = this.#database.prepare(
30079
+ `SELECT state FROM relay_runtime_deliveries
30080
+ WHERE delivery_id = ? AND session_id = ?`
30081
+ ).get(deliveryId, sessionId);
30082
+ if (row === void 0) {
30083
+ this.#database.exec("COMMIT");
30084
+ return false;
30085
+ }
30086
+ const state = runtimeDeliveryState(row);
30087
+ if (state === "processed") {
30088
+ this.#database.prepare(`DELETE FROM relay_runtime_deliveries WHERE delivery_id = ?`).run(deliveryId);
30089
+ } else if (state === "received") {
30090
+ this.#database.prepare(`UPDATE relay_runtime_deliveries SET state = 'relay_committed' WHERE delivery_id = ?`).run(deliveryId);
30091
+ }
30092
+ this.#database.exec("COMMIT");
30093
+ return true;
30094
+ } catch (error61) {
30095
+ this.#database.exec("ROLLBACK");
30096
+ throw error61;
30097
+ }
30098
+ };
30099
+ markRuntimeDeliveryProcessed = (deliveryId, sessionId) => {
30100
+ this.#database.exec("BEGIN IMMEDIATE");
30101
+ try {
30102
+ const row = this.#database.prepare(
30103
+ `SELECT state FROM relay_runtime_deliveries
30104
+ WHERE delivery_id = ? AND session_id = ?`
30105
+ ).get(deliveryId, sessionId);
30106
+ if (row === void 0) {
30107
+ this.#database.exec("COMMIT");
30108
+ return false;
30109
+ }
30110
+ const state = runtimeDeliveryState(row);
30111
+ if (state === "relay_committed") {
30112
+ this.#database.prepare(`DELETE FROM relay_runtime_deliveries WHERE delivery_id = ?`).run(deliveryId);
30113
+ } else if (state === "received") {
30114
+ this.#database.prepare(`UPDATE relay_runtime_deliveries SET state = 'processed' WHERE delivery_id = ?`).run(deliveryId);
30115
+ }
30116
+ this.#database.exec("COMMIT");
30117
+ return true;
30118
+ } catch (error61) {
30119
+ this.#database.exec("ROLLBACK");
30120
+ throw error61;
30121
+ }
30122
+ };
30123
+ runtimeDeliveries = () => this.#database.prepare(
30124
+ `SELECT delivery_id, session_id, payload_json, state
30125
+ FROM relay_runtime_deliveries
30126
+ ORDER BY received_at, delivery_id`
30127
+ ).all().map(
30128
+ (row) => new StoredRuntimeDelivery(
30129
+ rowString2(row, "delivery_id"),
30130
+ rowString2(row, "session_id"),
30131
+ rowString2(row, "payload_json"),
30132
+ runtimeDeliveryState(row),
30133
+ true
30134
+ )
30135
+ );
30136
+ #enqueueBounded = (sessionId, payload, attemptId, maximumEventCount, maximumEventBytes) => {
30137
+ const sourceKey = attemptId.length === 0 ? `runtime:${sessionId}` : `attempt:${sessionId}:${attemptId}`;
29170
30138
  this.#database.exec("BEGIN IMMEDIATE");
29171
30139
  try {
29172
30140
  const row = this.#database.prepare(
@@ -29183,13 +30151,22 @@ var SessionEventOutbox = class {
29183
30151
  kind: SESSION_EVENT_KIND,
29184
30152
  payload,
29185
30153
  sessionId,
29186
- source: attemptId === null ? { kind: "runtime", sourceSeq: nextSourceSeq.toString() } : {
30154
+ source: attemptId.length === 0 ? { kind: "runtime", sourceSeq: nextSourceSeq.toString() } : {
29187
30155
  attemptId,
29188
30156
  kind: "attempt",
29189
30157
  sourceSeq: nextSourceSeq.toString()
29190
30158
  }
29191
30159
  };
29192
30160
  const encoded = encodeSessionEventEnvelope(envelope2);
30161
+ const byteLength = new TextEncoder().encode(encoded).byteLength;
30162
+ const state = this.#database.prepare(
30163
+ `SELECT event_count, total_bytes
30164
+ FROM relay_session_event_outbox_state
30165
+ WHERE singleton = 1`
30166
+ ).get();
30167
+ if (rowNumber(state, "event_count") + 1 > maximumEventCount || rowNumber(state, "total_bytes") + byteLength > maximumEventBytes) {
30168
+ throw new SessionEventOutboxCapacityError();
30169
+ }
29193
30170
  this.#database.prepare(
29194
30171
  `INSERT INTO relay_session_event_sources (
29195
30172
  source_key, next_source_seq
@@ -29199,9 +30176,15 @@ var SessionEventOutbox = class {
29199
30176
  ).run(sourceKey, nextSourceSeq + 1);
29200
30177
  this.#database.prepare(
29201
30178
  `INSERT INTO relay_session_event_outbox (
29202
- event_id, session_id, source_key, envelope_json
29203
- ) VALUES (?, ?, ?, ?)`
29204
- ).run(envelope2.eventId, envelope2.sessionId, sourceKey, encoded);
30179
+ event_id, session_id, source_key, byte_length, envelope_json
30180
+ ) VALUES (?, ?, ?, ?, ?)`
30181
+ ).run(envelope2.eventId, envelope2.sessionId, sourceKey, byteLength, encoded);
30182
+ this.#database.prepare(
30183
+ `UPDATE relay_session_event_outbox_state
30184
+ SET event_count = event_count + 1,
30185
+ total_bytes = total_bytes + ?
30186
+ WHERE singleton = 1`
30187
+ ).run(byteLength);
29205
30188
  this.#database.exec("COMMIT");
29206
30189
  return encoded;
29207
30190
  } catch (error61) {
@@ -29209,6 +30192,44 @@ var SessionEventOutbox = class {
29209
30192
  throw error61;
29210
30193
  }
29211
30194
  };
30195
+ #removeAcknowledgedEvent = (eventId, sessionId) => {
30196
+ this.#database.exec("BEGIN IMMEDIATE");
30197
+ try {
30198
+ const stored = this.#database.prepare(
30199
+ `SELECT byte_length FROM relay_session_event_outbox
30200
+ WHERE event_id = ? AND session_id = ?`
30201
+ ).get(eventId, sessionId);
30202
+ if (stored === void 0) {
30203
+ this.#database.exec("COMMIT");
30204
+ return false;
30205
+ }
30206
+ const byteLength = rowNumber(stored, "byte_length");
30207
+ const deletion = this.#database.prepare(
30208
+ `DELETE FROM relay_session_event_outbox
30209
+ WHERE event_id = ? AND session_id = ?`
30210
+ ).run(eventId, sessionId);
30211
+ if (deletion.changes !== 1) {
30212
+ throw new Error("The acknowledged session event could not be removed from the durable outbox");
30213
+ }
30214
+ this.#decrementEventState(byteLength);
30215
+ this.#database.exec("COMMIT");
30216
+ return true;
30217
+ } catch (error61) {
30218
+ this.#database.exec("ROLLBACK");
30219
+ throw error61;
30220
+ }
30221
+ };
30222
+ #decrementEventState = (byteLength) => {
30223
+ const result = this.#database.prepare(
30224
+ `UPDATE relay_session_event_outbox_state
30225
+ SET event_count = event_count - 1,
30226
+ total_bytes = total_bytes - ?
30227
+ WHERE singleton = 1 AND event_count > 0 AND total_bytes >= ?`
30228
+ ).run(byteLength, byteLength);
30229
+ if (result.changes !== 1) {
30230
+ throw new Error("The Session event outbox capacity state is inconsistent");
30231
+ }
30232
+ };
29212
30233
  pending = () => this.#database.prepare(
29213
30234
  `SELECT envelope_json
29214
30235
  FROM relay_session_event_outbox
@@ -29235,7 +30256,68 @@ var SessionEventOutbox = class {
29235
30256
  LIMIT ?`
29236
30257
  ).all(limit).map(readPendingEnvelope);
29237
30258
  };
30259
+ pendingSourceHeads = (limit, excludedEventIds, excludedSourceKeys) => {
30260
+ if (!Number.isSafeInteger(limit) || limit < 1) {
30261
+ throw new Error("Session event replay batch limit must be a positive integer");
30262
+ }
30263
+ const exclusions = [];
30264
+ const parameters = [];
30265
+ if (excludedEventIds.length > 0) {
30266
+ exclusions.push(`event_id NOT IN (${excludedEventIds.map(() => "?").join(", ")})`);
30267
+ parameters.push(...excludedEventIds);
30268
+ }
30269
+ if (excludedSourceKeys.length > 0) {
30270
+ exclusions.push(`source_key NOT IN (${excludedSourceKeys.map(() => "?").join(", ")})`);
30271
+ parameters.push(...excludedSourceKeys);
30272
+ }
30273
+ parameters.push(limit.toString());
30274
+ const where = exclusions.length === 0 ? "" : `WHERE ${exclusions.join(" AND ")}`;
30275
+ return this.#database.prepare(
30276
+ `WITH available_events AS (
30277
+ SELECT ordinal, source_key
30278
+ FROM relay_session_event_outbox
30279
+ ${where}
30280
+ ), ranked_events AS (
30281
+ SELECT ordinal,
30282
+ ROW_NUMBER() OVER (
30283
+ PARTITION BY source_key
30284
+ ORDER BY ordinal
30285
+ ) AS source_position
30286
+ FROM available_events
30287
+ )
30288
+ SELECT outbox.envelope_json
30289
+ FROM ranked_events AS ranked
30290
+ INNER JOIN relay_session_event_outbox AS outbox
30291
+ ON outbox.ordinal = ranked.ordinal
30292
+ WHERE ranked.source_position = 1
30293
+ ORDER BY outbox.ordinal
30294
+ LIMIT ?`
30295
+ ).all(...parameters).map(readPendingEnvelope);
30296
+ };
29238
30297
  };
30298
+ function validateLimits(limits) {
30299
+ const values = [
30300
+ limits.criticalEventBytes,
30301
+ limits.criticalEventCount,
30302
+ limits.runtimeDeliveryBytes,
30303
+ limits.runtimeDeliveryCount,
30304
+ limits.standardEventBytes,
30305
+ limits.standardEventCount
30306
+ ];
30307
+ if (values.some((value) => !Number.isSafeInteger(value) || value < 1)) {
30308
+ throw new Error("Session event outbox limits must be positive integers");
30309
+ }
30310
+ if (limits.criticalEventBytes < limits.standardEventBytes || limits.criticalEventCount < limits.standardEventCount) {
30311
+ throw new Error("Critical Session event capacity must include the standard capacity");
30312
+ }
30313
+ }
30314
+ function runtimeDeliveryState(row) {
30315
+ const state = rowString2(row, "state");
30316
+ if (state !== "received" && state !== "relay_committed" && state !== "processed") {
30317
+ throw new Error("SQLite returned an invalid Runtime delivery state");
30318
+ }
30319
+ return state;
30320
+ }
29239
30321
  function isDaemonExecutionState(value) {
29240
30322
  return value === "cancelled" || value === "dispatching" || value === "failed" || value === "running" || value === "succeeded";
29241
30323
  }
@@ -29261,10 +30343,23 @@ function botIpcSocketPath() {
29261
30343
  return join15("/tmp", `mobius-bot-${randomUUID4()}.sock`);
29262
30344
  }
29263
30345
  var DaemonAcpObserver = class {
30346
+ #config;
29264
30347
  #record;
29265
- constructor(record2) {
29266
- this.#record = record2;
30348
+ constructor(config2, record3) {
30349
+ this.#config = config2;
30350
+ this.#record = record3;
29267
30351
  }
30352
+ importLocalImage = async (sessionId, image, signal) => {
30353
+ try {
30354
+ return (await uploadRuntimeArtifact(this.#config, sessionId, image, signal)).artifactId;
30355
+ } catch (cause) {
30356
+ signal.throwIfAborted();
30357
+ if (cause instanceof Error && cause.name === "AbortError") {
30358
+ throw cause;
30359
+ }
30360
+ return "";
30361
+ }
30362
+ };
29268
30363
  onCommands = (event) => {
29269
30364
  this.#record(event.sessionId, encodeSessionCommandsUpdatedEvent(event));
29270
30365
  return Promise.resolve();
@@ -29454,8 +30549,7 @@ var ActiveTurnReconciliationError = class extends Error {
29454
30549
  }
29455
30550
  };
29456
30551
  function activeTurnReconciliationEndpoint(config2, turn) {
29457
- const endpoint = new URL(config2.relayUrl);
29458
- endpoint.protocol = endpoint.protocol === "wss:" ? "https:" : "http:";
30552
+ const endpoint = relayHttpEndpoint(config2.relayUrl);
29459
30553
  let channelPath = "";
29460
30554
  if (endpoint.pathname.endsWith("/daemon")) {
29461
30555
  channelPath = endpoint.pathname.slice(0, -"/daemon".length);
@@ -29467,7 +30561,6 @@ function activeTurnReconciliationEndpoint(config2, turn) {
29467
30561
  channelPath = `${endpoint.pathname.slice(0, -runtimePath.length)}/channels/${encodeURIComponent(config2.channelId)}`;
29468
30562
  }
29469
30563
  endpoint.pathname = `${channelPath}/sessions/${encodeURIComponent(turn.command.sessionId)}/attempts/${encodeURIComponent(turn.attemptId)}/reconciliation`;
29470
- endpoint.searchParams.delete("liveness");
29471
30564
  return endpoint;
29472
30565
  }
29473
30566
  async function reconcileActiveTurn(config2, turn, signal) {
@@ -29476,10 +30569,10 @@ async function reconcileActiveTurn(config2, turn, signal) {
29476
30569
  const requestSignal = AbortSignal.any([signal, timeoutSignal]);
29477
30570
  let response;
29478
30571
  try {
29479
- response = await fetch5(activeTurnReconciliationEndpoint(config2, turn), {
30572
+ response = await fetch6(activeTurnReconciliationEndpoint(config2, turn), {
29480
30573
  body: JSON.stringify({ outcome: { kind: "running" } }),
29481
30574
  dispatcher: environmentProxyDispatcher,
29482
- headers: { "content-type": "application/json" },
30575
+ headers: { ...runtimeAuthorization(config2.relayUrl), "content-type": "application/json" },
29483
30576
  method: "POST",
29484
30577
  signal: requestSignal
29485
30578
  });
@@ -29547,17 +30640,31 @@ var ConnectedDaemonSessionEventState = class extends DaemonSessionEventConnectio
29547
30640
  }
29548
30641
  };
29549
30642
  };
29550
- var SESSION_EVENT_REPLAY_WINDOW = 4;
30643
+ var SESSION_EVENT_REPLAY_WINDOW = 16;
30644
+ var SESSION_EVENT_SOURCE_REPLAY_WINDOW = 4;
30645
+ var SESSION_EVENT_REPLAY_BYTE_LIMIT = 32 * 1024 * 1024;
30646
+ var InFlightSessionEvent = class {
30647
+ byteLength;
30648
+ sourceKey;
30649
+ constructor(sourceKey, byteLength) {
30650
+ this.byteLength = byteLength;
30651
+ this.sourceKey = sourceKey;
30652
+ }
30653
+ };
30654
+ function sessionEventSourceKey(envelope2) {
30655
+ return envelope2.source.kind === "attempt" ? `attempt:${envelope2.sessionId}:${envelope2.source.attemptId}` : `runtime:${envelope2.sessionId}`;
30656
+ }
29551
30657
  var DaemonSessionEventPublisher = class {
29552
30658
  #outbox;
29553
- #inFlightEventIds = /* @__PURE__ */ new Set();
30659
+ #inFlightEvents = /* @__PURE__ */ new Map();
30660
+ #inFlightBytes = 0;
29554
30661
  #connection = new DisconnectedDaemonSessionEventState();
29555
30662
  constructor(outbox) {
29556
30663
  this.#outbox = outbox;
29557
30664
  }
29558
30665
  connect = (socket) => {
29559
30666
  this.#connection = new ConnectedDaemonSessionEventState(socket);
29560
- this.#inFlightEventIds.clear();
30667
+ this.#clearInFlight();
29561
30668
  this.#publishNextBatch();
29562
30669
  };
29563
30670
  disconnect = (socket) => {
@@ -29565,10 +30672,15 @@ var DaemonSessionEventPublisher = class {
29565
30672
  return;
29566
30673
  }
29567
30674
  this.#connection = this.#connection.disconnect(socket);
29568
- this.#inFlightEventIds.clear();
30675
+ this.#clearInFlight();
29569
30676
  };
29570
30677
  recordAttempt = (sessionId, payload, attemptId) => {
29571
- this.#outbox.enqueue(sessionId, payload, attemptId);
30678
+ const kind = decodeMessageKind(payload);
30679
+ if (kind === SESSION_COMPLETED_KIND || kind === SESSION_FAILED_KIND) {
30680
+ this.#outbox.enqueueCritical(sessionId, payload, attemptId);
30681
+ } else {
30682
+ this.#outbox.enqueue(sessionId, payload, attemptId);
30683
+ }
29572
30684
  this.#publishNextBatch();
29573
30685
  };
29574
30686
  recordRuntime = (sessionId, payload) => {
@@ -29579,7 +30691,7 @@ var DaemonSessionEventPublisher = class {
29579
30691
  if (!this.#outbox.acknowledge(acknowledgement)) {
29580
30692
  return;
29581
30693
  }
29582
- this.#inFlightEventIds.delete(acknowledgement.eventId);
30694
+ this.#removeInFlight(acknowledgement.eventId);
29583
30695
  this.#publishNextBatch();
29584
30696
  };
29585
30697
  quarantine = (rejection) => {
@@ -29587,24 +30699,60 @@ var DaemonSessionEventPublisher = class {
29587
30699
  if (!quarantined) {
29588
30700
  return false;
29589
30701
  }
29590
- this.#inFlightEventIds.delete(rejection.eventId);
30702
+ this.#removeInFlight(rejection.eventId);
29591
30703
  this.#publishNextBatch();
29592
30704
  return true;
29593
30705
  };
29594
30706
  #publishNextBatch = () => {
29595
- if (this.#inFlightEventIds.size > 0) {
29596
- return;
29597
- }
29598
- const batch = this.#outbox.pendingBatch(SESSION_EVENT_REPLAY_WINDOW);
29599
- for (const encoded of batch) {
29600
- const envelope2 = decodeSessionEventEnvelope(encoded);
29601
- if (!this.#connection.send(encoded)) {
29602
- this.#inFlightEventIds.clear();
30707
+ while (this.#inFlightEvents.size < SESSION_EVENT_REPLAY_WINDOW) {
30708
+ const sourceCounts = /* @__PURE__ */ new Map();
30709
+ for (const inFlight of this.#inFlightEvents.values()) {
30710
+ sourceCounts.set(inFlight.sourceKey, (sourceCounts.get(inFlight.sourceKey) ?? 0) + 1);
30711
+ }
30712
+ const saturatedSources = [...sourceCounts.entries()].filter(([, count]) => count >= SESSION_EVENT_SOURCE_REPLAY_WINDOW).map(([sourceKey]) => sourceKey);
30713
+ const batch = this.#outbox.pendingSourceHeads(
30714
+ SESSION_EVENT_REPLAY_WINDOW - this.#inFlightEvents.size,
30715
+ [...this.#inFlightEvents.keys()],
30716
+ saturatedSources
30717
+ );
30718
+ let sent = 0;
30719
+ for (const encoded of batch) {
30720
+ const envelope2 = decodeSessionEventEnvelope(encoded);
30721
+ const sourceKey = sessionEventSourceKey(envelope2);
30722
+ const sourceCount = sourceCounts.get(sourceKey) ?? 0;
30723
+ if (sourceCount >= SESSION_EVENT_SOURCE_REPLAY_WINDOW) {
30724
+ continue;
30725
+ }
30726
+ const byteLength = new TextEncoder().encode(encoded).byteLength;
30727
+ if (this.#inFlightBytes + byteLength > SESSION_EVENT_REPLAY_BYTE_LIMIT) {
30728
+ continue;
30729
+ }
30730
+ if (!this.#connection.send(encoded)) {
30731
+ this.#clearInFlight();
30732
+ return;
30733
+ }
30734
+ this.#inFlightEvents.set(envelope2.eventId, new InFlightSessionEvent(sourceKey, byteLength));
30735
+ this.#inFlightBytes += byteLength;
30736
+ sourceCounts.set(sourceKey, sourceCount + 1);
30737
+ sent += 1;
30738
+ }
30739
+ if (sent === 0) {
29603
30740
  return;
29604
30741
  }
29605
- this.#inFlightEventIds.add(envelope2.eventId);
29606
30742
  }
29607
30743
  };
30744
+ #removeInFlight = (eventId) => {
30745
+ const inFlight = this.#inFlightEvents.get(eventId);
30746
+ if (inFlight === void 0) {
30747
+ return;
30748
+ }
30749
+ this.#inFlightEvents.delete(eventId);
30750
+ this.#inFlightBytes -= inFlight.byteLength;
30751
+ };
30752
+ #clearInFlight = () => {
30753
+ this.#inFlightEvents.clear();
30754
+ this.#inFlightBytes = 0;
30755
+ };
29608
30756
  };
29609
30757
  var CoalescingDaemonActivityPublisher = class {
29610
30758
  #pending = /* @__PURE__ */ new Map();
@@ -29737,7 +30885,7 @@ async function resolveSessionDirectories(directories, bindingId, directoryId2, a
29737
30885
  additionalDirectories.push(directory);
29738
30886
  additionalDirectoryEntries.push({
29739
30887
  directoryId: additionalDirectoryId,
29740
- name: basename3(directory)
30888
+ name: basename4(directory)
29741
30889
  });
29742
30890
  }
29743
30891
  return new ResolvedSessionDirectories(cwd, additionalDirectories, additionalDirectoryEntries);
@@ -29856,6 +31004,9 @@ async function executeSessionConfigure(publisher, socket, command, config2, dire
29856
31004
  })
29857
31005
  );
29858
31006
  } catch (error61) {
31007
+ if (signal.aborted) {
31008
+ signal.throwIfAborted();
31009
+ }
29859
31010
  reportOperationFailure(socket, command.requestId, command.sessionId, error61);
29860
31011
  }
29861
31012
  }
@@ -30195,6 +31346,7 @@ async function publishAgentCatalogUntilAvailable(config2, diagnostics, signal, t
30195
31346
  }
30196
31347
  async function runRelayConnection(config2, directories, audit, sessions, installations, installationObserver, nativeSessions, outbox, publisher, grants, contexts, applicator, ipc, activeTurns, activeAttemptIds, connectionEpoch, diagnostics, onConnected, signal, timer) {
30197
31348
  const relayUrl = new URL(config2.relayUrl);
31349
+ relayUrl.searchParams.set("deliveryReceipts", "1");
30198
31350
  relayUrl.searchParams.set("liveness", "1");
30199
31351
  const socket = await connectRelay(relayUrl, signal);
30200
31352
  const reconnectingTurns = [...activeTurns.values()];
@@ -30243,6 +31395,239 @@ async function runRelayConnection(config2, directories, audit, sessions, install
30243
31395
  closeRelaySocket(socket, code, reason);
30244
31396
  rejectConnection(failure);
30245
31397
  };
31398
+ const processingDeliveryIds = /* @__PURE__ */ new Set();
31399
+ const processDeliveredPrompt = async (delivery, command, trackActiveAttempt, execute) => {
31400
+ if (command.sessionId !== delivery.sessionId) {
31401
+ throw new Error("Runtime delivery Session identity does not match its payload");
31402
+ }
31403
+ const active = activeTurns.get(command.commandId);
31404
+ if (active !== void 0) {
31405
+ await active.completion;
31406
+ return;
31407
+ }
31408
+ const receipt = outbox.claimExecution(command.commandId, command.sessionId, delivery.payload);
31409
+ if (receipt.kind === "duplicate") {
31410
+ if (receipt.state === "running") {
31411
+ reportFailure(
31412
+ publisher,
31413
+ command,
31414
+ "agent_execution_interrupted",
31415
+ "The local Agent execution was interrupted before it completed",
31416
+ receipt.attemptId
31417
+ );
31418
+ outbox.transitionExecution(command.commandId, "failed");
31419
+ return;
31420
+ }
31421
+ if (receipt.state !== "dispatching") {
31422
+ return;
31423
+ }
31424
+ }
31425
+ const turn = new ActiveDaemonTurn(command, receipt.attemptId);
31426
+ activeTurns.set(command.commandId, turn);
31427
+ if (trackActiveAttempt) {
31428
+ activeAttemptIds.set(command.sessionId, receipt.attemptId);
31429
+ }
31430
+ try {
31431
+ await execute(receipt.attemptId, turn.signal);
31432
+ } finally {
31433
+ activeTurns.delete(command.commandId);
31434
+ if (activeAttemptIds.get(command.sessionId) === receipt.attemptId) {
31435
+ activeAttemptIds.delete(command.sessionId);
31436
+ }
31437
+ turn.finish();
31438
+ }
31439
+ };
31440
+ const processDeliveredPayload = async (delivery) => {
31441
+ const kind = decodeMessageKind(delivery.payload);
31442
+ if (kind === SESSION_CANCEL_KIND) {
31443
+ const cancellation = decodeSessionCancelCommand(delivery.payload);
31444
+ if (cancellation.sessionId !== delivery.sessionId) {
31445
+ throw new Error("Runtime delivery Session identity does not match its payload");
31446
+ }
31447
+ const turn = activeTurns.get(cancellation.commandId);
31448
+ if (turn === void 0 || !turn.matches(cancellation) || !turn.requestCancellation()) {
31449
+ return;
31450
+ }
31451
+ audit.record({
31452
+ commandId: cancellation.commandId,
31453
+ event: "session_cancellation_requested",
31454
+ sessionId: cancellation.sessionId
31455
+ });
31456
+ await sessions.cancelPrompt(cancellation.sessionId);
31457
+ return;
31458
+ }
31459
+ if (kind === SESSION_CONFIGURE_KIND) {
31460
+ const command = decodeSessionConfigureCommand(delivery.payload);
31461
+ if (command.sessionId !== delivery.sessionId) {
31462
+ throw new Error("Runtime delivery Session identity does not match its payload");
31463
+ }
31464
+ await executeSessionConfigure(
31465
+ publisher,
31466
+ socket,
31467
+ command,
31468
+ config2,
31469
+ directories,
31470
+ audit,
31471
+ sessions,
31472
+ connectionController.signal
31473
+ );
31474
+ return;
31475
+ }
31476
+ if (kind === SESSION_PERMISSION_RESPOND_KIND) {
31477
+ const command = decodeSessionPermissionRespondCommand(delivery.payload);
31478
+ if (command.sessionId !== delivery.sessionId) {
31479
+ throw new Error("Runtime delivery Session identity does not match its payload");
31480
+ }
31481
+ try {
31482
+ await sessions.respondPermission(command);
31483
+ audit.record({
31484
+ commandId: command.interactionId,
31485
+ event: "session_permission_resolved",
31486
+ sessionId: command.sessionId
31487
+ });
31488
+ } catch (error61) {
31489
+ reportOperationFailure(socket, command.interactionId, command.sessionId, error61);
31490
+ }
31491
+ return;
31492
+ }
31493
+ if (kind === SESSION_ELICITATION_RESPOND_KIND) {
31494
+ const command = decodeSessionElicitationRespondCommand(delivery.payload);
31495
+ if (command.sessionId !== delivery.sessionId) {
31496
+ throw new Error("Runtime delivery Session identity does not match its payload");
31497
+ }
31498
+ try {
31499
+ await sessions.respondElicitation(command);
31500
+ audit.record({
31501
+ commandId: command.interactionId,
31502
+ event: "session_elicitation_resolved",
31503
+ sessionId: command.sessionId
31504
+ });
31505
+ } catch (error61) {
31506
+ reportOperationFailure(socket, command.interactionId, command.sessionId, error61);
31507
+ }
31508
+ return;
31509
+ }
31510
+ if (kind === BOT_SESSION_PROMPT_KIND) {
31511
+ const command = decodeBotSessionPromptCommand(delivery.payload);
31512
+ await processDeliveredPrompt(
31513
+ delivery,
31514
+ command,
31515
+ true,
31516
+ (attemptId, executionSignal) => executeBotPrompt(
31517
+ outbox,
31518
+ publisher,
31519
+ command,
31520
+ config2,
31521
+ directories,
31522
+ audit,
31523
+ sessions,
31524
+ grants,
31525
+ contexts,
31526
+ applicator,
31527
+ ipc,
31528
+ attemptId,
31529
+ timer,
31530
+ executionSignal
31531
+ )
31532
+ );
31533
+ return;
31534
+ }
31535
+ if (kind === SESSION_PROMPT_KIND) {
31536
+ const command = decodeSessionPromptCommand(delivery.payload);
31537
+ await processDeliveredPrompt(
31538
+ delivery,
31539
+ command,
31540
+ command.disposition !== SessionPromptDisposition.Steer,
31541
+ (attemptId, executionSignal) => executePrompt(
31542
+ outbox,
31543
+ publisher,
31544
+ command,
31545
+ config2,
31546
+ directories,
31547
+ audit,
31548
+ sessions,
31549
+ attemptId,
31550
+ timer,
31551
+ executionSignal
31552
+ )
31553
+ );
31554
+ return;
31555
+ }
31556
+ throw new Error("Runtime delivery contains an unsupported protocol message");
31557
+ };
31558
+ const processRuntimeDelivery = (delivery, state) => {
31559
+ if (state === "processed" || processingDeliveryIds.has(delivery.deliveryId)) {
31560
+ return;
31561
+ }
31562
+ processingDeliveryIds.add(delivery.deliveryId);
31563
+ void processDeliveredPayload(delivery).then(() => {
31564
+ outbox.markRuntimeDeliveryProcessed(delivery.deliveryId, delivery.sessionId);
31565
+ }).catch((error61) => {
31566
+ if (connectionController.signal.aborted) {
31567
+ return;
31568
+ }
31569
+ console.error("Mobius daemon could not process a durable Runtime delivery", error61);
31570
+ failAndClose(
31571
+ new Error("Runtime delivery processing failed", { cause: error61 }),
31572
+ 4008,
31573
+ "Invalid Runtime delivery",
31574
+ "delivery"
31575
+ );
31576
+ }).finally(() => processingDeliveryIds.delete(delivery.deliveryId));
31577
+ };
31578
+ const receiveRuntimeDelivery = (delivery) => {
31579
+ const payloadKind = decodeMessageKind(delivery.payload);
31580
+ let payloadSessionId = "";
31581
+ if (payloadKind === SESSION_CANCEL_KIND) {
31582
+ payloadSessionId = decodeSessionCancelCommand(delivery.payload).sessionId;
31583
+ } else if (payloadKind === SESSION_CONFIGURE_KIND) {
31584
+ payloadSessionId = decodeSessionConfigureCommand(delivery.payload).sessionId;
31585
+ } else if (payloadKind === SESSION_PERMISSION_RESPOND_KIND) {
31586
+ payloadSessionId = decodeSessionPermissionRespondCommand(delivery.payload).sessionId;
31587
+ } else if (payloadKind === SESSION_ELICITATION_RESPOND_KIND) {
31588
+ payloadSessionId = decodeSessionElicitationRespondCommand(delivery.payload).sessionId;
31589
+ } else if (payloadKind === SESSION_PROMPT_KIND) {
31590
+ payloadSessionId = decodeSessionPromptCommand(delivery.payload).sessionId;
31591
+ } else if (payloadKind === BOT_SESSION_PROMPT_KIND) {
31592
+ payloadSessionId = decodeBotSessionPromptCommand(delivery.payload).sessionId;
31593
+ } else {
31594
+ throw new Error("Runtime delivery contains an unsupported protocol message");
31595
+ }
31596
+ if (payloadSessionId !== delivery.sessionId) {
31597
+ throw new Error("Runtime delivery Session identity does not match its payload");
31598
+ }
31599
+ const stored = outbox.claimRuntimeDelivery(delivery);
31600
+ send(
31601
+ socket,
31602
+ encodeRuntimeDeliveryReceived({
31603
+ deliveryId: delivery.deliveryId,
31604
+ kind: RUNTIME_DELIVERY_RECEIVED_KIND,
31605
+ sessionId: delivery.sessionId
31606
+ })
31607
+ );
31608
+ processRuntimeDelivery(delivery, stored.state);
31609
+ };
31610
+ const resumeRuntimeDeliveries = () => {
31611
+ for (const stored of outbox.runtimeDeliveries()) {
31612
+ const delivery = {
31613
+ deliveryId: stored.deliveryId,
31614
+ kind: RUNTIME_DELIVERY_KIND,
31615
+ payload: stored.payload,
31616
+ sessionId: stored.sessionId
31617
+ };
31618
+ if (stored.state !== "relay_committed") {
31619
+ send(
31620
+ socket,
31621
+ encodeRuntimeDeliveryReceived({
31622
+ deliveryId: stored.deliveryId,
31623
+ kind: RUNTIME_DELIVERY_RECEIVED_KIND,
31624
+ sessionId: stored.sessionId
31625
+ })
31626
+ );
31627
+ }
31628
+ processRuntimeDelivery(delivery, stored.state);
31629
+ }
31630
+ };
30246
31631
  const connectionLiveness = new RelayConnectionLiveness(timer, {
30247
31632
  send: (message) => send(socket, message),
30248
31633
  unresponsive: (heartbeatId, timeoutMilliseconds) => {
@@ -30281,6 +31666,17 @@ async function runRelayConnection(config2, directories, audit, sessions, install
30281
31666
  }
30282
31667
  try {
30283
31668
  const kind = decodeMessageKind(encoded);
31669
+ if (kind === RUNTIME_DELIVERY_COMMITTED_KIND) {
31670
+ const committed = decodeRuntimeDeliveryCommitted(encoded);
31671
+ if (!outbox.markRuntimeDeliveryCommitted(committed.deliveryId, committed.sessionId)) {
31672
+ console.warn("Mobius daemon ignored confirmation for an unknown Runtime delivery");
31673
+ }
31674
+ return;
31675
+ }
31676
+ if (kind === RUNTIME_DELIVERY_KIND) {
31677
+ receiveRuntimeDelivery(decodeRuntimeDelivery(encoded));
31678
+ return;
31679
+ }
30284
31680
  if (kind === SESSION_EVENT_ACK_KIND) {
30285
31681
  publisher.acknowledge(decodeSessionEventAcknowledgement(encoded));
30286
31682
  return;
@@ -30717,6 +32113,10 @@ async function runRelayConnection(config2, directories, audit, sessions, install
30717
32113
  });
30718
32114
  } catch (error61) {
30719
32115
  console.error("Mobius daemon rejected a message", error61);
32116
+ if (error61 instanceof RuntimeDeliveryInboxCapacityError) {
32117
+ failAndClose(error61, 4013, "Runtime delivery queue full", "delivery_backpressure");
32118
+ return;
32119
+ }
30720
32120
  failAndClose(
30721
32121
  new Error("Relay sent an invalid protocol message", { cause: error61 }),
30722
32122
  4008,
@@ -30734,6 +32134,7 @@ async function runRelayConnection(config2, directories, audit, sessions, install
30734
32134
  return;
30735
32135
  }
30736
32136
  publisher.connect(socket);
32137
+ resumeRuntimeDeliveries();
30737
32138
  },
30738
32139
  (error61) => {
30739
32140
  if (finished) {
@@ -30786,7 +32187,7 @@ async function runDaemon(config2, audit, signal, timer = systemDaemonTimer) {
30786
32187
  }
30787
32188
  publisher.recordAttempt(sessionId, payload, attemptId);
30788
32189
  };
30789
- const sessions = new AcpSessionManager(new DaemonAcpObserver(recordSessionEvent), sessionStore);
32190
+ const sessions = new AcpSessionManager(new DaemonAcpObserver(config2, recordSessionEvent), sessionStore);
30790
32191
  const directories = new WorkspaceDirectoryService(config2.bindingId, config2.defaultWorkspace);
30791
32192
  const installationObserver = new DaemonInstallationObserver();
30792
32193
  const diagnostics = new RelayConnectionDiagnostics(audit, config2.channelId, config2.relayUrl);
@@ -30885,13 +32286,13 @@ async function runDaemon(config2, audit, signal, timer = systemDaemonTimer) {
30885
32286
 
30886
32287
  // src/pairing/pair-local-machine.ts
30887
32288
  import { randomUUID as randomUUID5 } from "node:crypto";
30888
- import { mkdir as mkdir4, open as open4, realpath as realpath7, rename as rename3, stat as stat7, writeFile as writeFile2 } from "node:fs/promises";
32289
+ import { mkdir as mkdir4, open as open4, realpath as realpath8, rename as rename3, stat as stat8, writeFile as writeFile2 } from "node:fs/promises";
30889
32290
  import { hostname as hostname3 } from "node:os";
30890
- import { basename as basename4, join as join16, resolve as resolve4 } from "node:path";
30891
- import { fetch as fetch6 } from "undici";
32291
+ import { basename as basename5, join as join16, resolve as resolve4 } from "node:path";
32292
+ import { fetch as fetch7 } from "undici";
30892
32293
  var PAIRING_TIMEOUT_MILLISECONDS = 2e4;
30893
32294
  var PAIRING_CODE_PATTERN = /^[A-HJ-NP-Z2-9]{4}(?:-[A-HJ-NP-Z2-9]{4}){4}$/;
30894
- var IDENTIFIER_PATTERN7 = /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/;
32295
+ var IDENTIFIER_PATTERN8 = /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/;
30895
32296
  var TOKEN_PATTERN2 = /^[a-zA-Z0-9_-]{32,256}$/;
30896
32297
  var MAX_CONNECTION_FILE_LENGTH = 16 * 1024;
30897
32298
  var CLAIM_RESPONSE_KEYS = ["channelId", "daemonToken", "runtimeId"];
@@ -30906,7 +32307,7 @@ var PairingClientError = class extends Error {
30906
32307
  this.name = "PairingClientError";
30907
32308
  }
30908
32309
  };
30909
- function isRecord10(value) {
32310
+ function isRecord11(value) {
30910
32311
  return typeof value === "object" && value !== null && !Array.isArray(value);
30911
32312
  }
30912
32313
  function hasExactKeys(value, expectedKeys) {
@@ -30945,7 +32346,7 @@ function parsePairingCode(value) {
30945
32346
  return code;
30946
32347
  }
30947
32348
  function validatePairingId(value) {
30948
- if (!IDENTIFIER_PATTERN7.test(value)) {
32349
+ if (!IDENTIFIER_PATTERN8.test(value)) {
30949
32350
  throw new PairingClientError("invalid_pairing_id", "The Runtime pairing ID is invalid");
30950
32351
  }
30951
32352
  return value;
@@ -30954,8 +32355,8 @@ async function resolveDefaultWorkspace2(path2) {
30954
32355
  const requestedWorkspace = resolve4(path2);
30955
32356
  try {
30956
32357
  await mkdir4(requestedWorkspace, { recursive: true, mode: 448 });
30957
- const defaultWorkspace = await realpath7(requestedWorkspace);
30958
- const metadata = await stat7(defaultWorkspace);
32358
+ const defaultWorkspace = await realpath8(requestedWorkspace);
32359
+ const metadata = await stat8(defaultWorkspace);
30959
32360
  if (!metadata.isDirectory()) {
30960
32361
  throw new PairingClientError("invalid_workspace", "The default workspace is not a directory");
30961
32362
  }
@@ -30984,9 +32385,9 @@ async function readJsonResponse(response) {
30984
32385
  }
30985
32386
  }
30986
32387
  function readRelayError(value) {
30987
- if (isRecord10(value)) {
32388
+ if (isRecord11(value)) {
30988
32389
  const error61 = value["error"];
30989
- if (isRecord10(error61)) {
32390
+ if (isRecord11(error61)) {
30990
32391
  const code = error61["code"];
30991
32392
  const message = error61["message"];
30992
32393
  if (typeof code === "string" && typeof message === "string") {
@@ -30997,16 +32398,16 @@ function readRelayError(value) {
30997
32398
  return new PairingClientError("pairing_failed", "The relay could not pair this machine");
30998
32399
  }
30999
32400
  function decodePairingResponse(value, credentialField, expectedKeys) {
31000
- if (!isRecord10(value) || !hasExactKeys(value, expectedKeys)) {
32401
+ if (!isRecord11(value) || !hasExactKeys(value, expectedKeys)) {
31001
32402
  throw new PairingClientError("invalid_relay_response", "The relay returned an invalid pairing response");
31002
32403
  }
31003
32404
  const channelId = value["channelId"];
31004
- const runtimeCredential = value[credentialField];
32405
+ const runtimeCredential2 = value[credentialField];
31005
32406
  const runtimeId = value["runtimeId"];
31006
- if (typeof channelId !== "string" || !IDENTIFIER_PATTERN7.test(channelId) || typeof runtimeCredential !== "string" || !TOKEN_PATTERN2.test(runtimeCredential) || typeof runtimeId !== "string" || !IDENTIFIER_PATTERN7.test(runtimeId)) {
32407
+ if (typeof channelId !== "string" || !IDENTIFIER_PATTERN8.test(channelId) || typeof runtimeCredential2 !== "string" || !TOKEN_PATTERN2.test(runtimeCredential2) || typeof runtimeId !== "string" || !IDENTIFIER_PATTERN8.test(runtimeId)) {
31007
32408
  throw new PairingClientError("invalid_relay_response", "The relay returned an invalid pairing response");
31008
32409
  }
31009
- return { channelId, runtimeCredential, runtimeId };
32410
+ return { channelId, runtimeCredential: runtimeCredential2, runtimeId };
31010
32411
  }
31011
32412
  async function claimPairing(options, defaultWorkspace, localAgents, installableAgents, signal) {
31012
32413
  const agents = localAgents.map((agent) => ({
@@ -31019,13 +32420,13 @@ async function claimPairing(options, defaultWorkspace, localAgents, installableA
31019
32420
  const endpoint = options.pairingId.length > 0 ? mobiusApiUrl(options.relayOrigin, `/v1/runtime-pairings/${encodeURIComponent(options.pairingId)}/redeem`) : mobiusApiUrl(options.relayOrigin, "/pairings/claim");
31020
32421
  let response;
31021
32422
  try {
31022
- response = await fetch6(endpoint, {
32423
+ response = await fetch7(endpoint, {
31023
32424
  body: JSON.stringify({
31024
32425
  agents,
31025
32426
  installableAgents,
31026
32427
  machineName: hostname3(),
31027
32428
  pairingCode: options.code,
31028
- workspaceName: basename4(defaultWorkspace) || "Local workspace"
32429
+ workspaceName: basename5(defaultWorkspace) || "Local workspace"
31029
32430
  }),
31030
32431
  dispatcher: environmentProxyDispatcher,
31031
32432
  headers: { "content-type": "application/json" },
@@ -31041,7 +32442,7 @@ async function claimPairing(options, defaultWorkspace, localAgents, installableA
31041
32442
  }
31042
32443
  return options.pairingId.length > 0 ? decodePairingResponse(value, "runtimeCredential", REDEEM_RESPONSE_KEYS) : decodePairingResponse(value, "daemonToken", CLAIM_RESPONSE_KEYS);
31043
32444
  }
31044
- async function persistConnection(channelId, relayOrigin, runtimeCredential, defaultWorkspace, environment) {
32445
+ async function persistConnection(channelId, relayOrigin, runtimeCredential2, defaultWorkspace, environment) {
31045
32446
  const connectionsDirectory = join16(readStateDirectory(environment), "connections");
31046
32447
  await mkdir4(connectionsDirectory, { mode: 448, recursive: true });
31047
32448
  const connectionPath = join16(connectionsDirectory, `${channelId}.json`);
@@ -31053,7 +32454,7 @@ async function persistConnection(channelId, relayOrigin, runtimeCredential, defa
31053
32454
  defaultWorkspace,
31054
32455
  channelId,
31055
32456
  relayOrigin: relayOrigin.toString(),
31056
- runtimeCredential
32457
+ runtimeCredential: runtimeCredential2
31057
32458
  },
31058
32459
  null,
31059
32460
  2
@@ -31065,21 +32466,21 @@ async function persistConnection(channelId, relayOrigin, runtimeCredential, defa
31065
32466
  return connectionPath;
31066
32467
  }
31067
32468
  function decodeSavedConnection(value, expectedChannelId) {
31068
- if (!isRecord10(value) || !hasExactKeys(value, SAVED_CONNECTION_KEYS) && !hasExactKeys(value, LEGACY_SAVED_CONNECTION_KEYS)) {
32469
+ if (!isRecord11(value) || !hasExactKeys(value, SAVED_CONNECTION_KEYS) && !hasExactKeys(value, LEGACY_SAVED_CONNECTION_KEYS)) {
31069
32470
  throw new PairingClientError("invalid_connection", "The saved connection is invalid");
31070
32471
  }
31071
32472
  const defaultWorkspace = value["defaultWorkspace"];
31072
32473
  const channelId = value["channelId"];
31073
- const runtimeCredential = value["runtimeCredential"] ?? value["daemonToken"];
32474
+ const runtimeCredential2 = value["runtimeCredential"] ?? value["daemonToken"];
31074
32475
  const relayOrigin = value["relayOrigin"];
31075
- if (typeof defaultWorkspace !== "string" || typeof channelId !== "string" || channelId !== expectedChannelId || !IDENTIFIER_PATTERN7.test(channelId) || typeof runtimeCredential !== "string" || !TOKEN_PATTERN2.test(runtimeCredential) || typeof relayOrigin !== "string") {
32476
+ if (typeof defaultWorkspace !== "string" || typeof channelId !== "string" || channelId !== expectedChannelId || !IDENTIFIER_PATTERN8.test(channelId) || typeof runtimeCredential2 !== "string" || !TOKEN_PATTERN2.test(runtimeCredential2) || typeof relayOrigin !== "string") {
31076
32477
  throw new PairingClientError("invalid_connection", "The saved connection is invalid");
31077
32478
  }
31078
32479
  return {
31079
32480
  defaultWorkspace,
31080
32481
  channelId,
31081
32482
  relayOrigin: parseRelayOrigin(relayOrigin),
31082
- runtimeCredential
32483
+ runtimeCredential: runtimeCredential2
31083
32484
  };
31084
32485
  }
31085
32486
  async function readSavedConnection(channelId, environment) {
@@ -31191,7 +32592,7 @@ async function resumeMobiusRuntime(channelId, signal, environment = process.env)
31191
32592
  // src/runtime.ts
31192
32593
  var APP_CREDENTIAL_PATTERN = /^mapp_[a-zA-Z0-9_-]{22}_[a-zA-Z0-9_-]{43}$/;
31193
32594
  var CONVERSATION_CREDENTIAL_PATTERN = /^mconv_[a-zA-Z0-9_-]{22}_[a-zA-Z0-9_-]{43}$/;
31194
- var IDENTIFIER_PATTERN8 = /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/;
32595
+ var IDENTIFIER_PATTERN9 = /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/;
31195
32596
  var RUNTIME_CREDENTIAL_PATTERN = /^[a-zA-Z0-9_-]{32,256}$/;
31196
32597
  var MobiusRuntimeConfigurationError = class extends Error {
31197
32598
  code = "runtime_configuration_invalid";
@@ -31249,7 +32650,7 @@ function relayUrlFromConnection(connection) {
31249
32650
  }
31250
32651
  function loadMobiusRuntimeConnection(environment = process.env) {
31251
32652
  const channelId = requiredEnvironmentValue(environment, "MOBIUS_CHANNEL_ID");
31252
- if (!IDENTIFIER_PATTERN8.test(channelId)) {
32653
+ if (!IDENTIFIER_PATTERN9.test(channelId)) {
31253
32654
  throw new MobiusRuntimeConfigurationError("MOBIUS_CHANNEL_ID is invalid");
31254
32655
  }
31255
32656
  return Object.freeze({
@@ -31264,8 +32665,8 @@ async function resolveWorkspace(path2) {
31264
32665
  const requested = resolve5(path2);
31265
32666
  try {
31266
32667
  await mkdir5(requested, { recursive: true, mode: 448 });
31267
- const resolved = await realpath8(requested);
31268
- const metadata = await stat8(resolved);
32668
+ const resolved = await realpath9(requested);
32669
+ const metadata = await stat9(resolved);
31269
32670
  if (!metadata.isDirectory()) {
31270
32671
  throw new MobiusRuntimeConfigurationError("The Runtime workspace is not a directory");
31271
32672
  }