@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/index.js CHANGED
@@ -16087,8 +16087,8 @@ function rewriteKeyNames(ctx) {
16087
16087
  bySchema.set(entry.schema, entry);
16088
16088
  }
16089
16089
  const rewrites = /* @__PURE__ */ new Map();
16090
- for (const record2 of pendingRecords.get(ctx) ?? []) {
16091
- const seen = ctx.seen.get(record2);
16090
+ for (const record3 of pendingRecords.get(ctx) ?? []) {
16091
+ const seen = ctx.seen.get(record3);
16092
16092
  const names = (seen?.def ?? seen?.schema)?.propertyNames;
16093
16093
  if (!names || names === true || rewrites.has(names))
16094
16094
  continue;
@@ -19045,6 +19045,7 @@ var elicitationFieldSchema = external_exports.strictObject({
19045
19045
  type: external_exports.enum(["boolean", "integer", "multiselect", "number", "select", "string"])
19046
19046
  }).readonly();
19047
19047
  var displayContentSchema = external_exports.strictObject({
19048
+ artifactId: external_exports.string().max(128).default(""),
19048
19049
  data: external_exports.string().max(4e6),
19049
19050
  mimeType: external_exports.string().max(255),
19050
19051
  name: external_exports.string().max(500),
@@ -19057,6 +19058,7 @@ var displayContentSchema = external_exports.strictObject({
19057
19058
  uri: external_exports.string().max(4096)
19058
19059
  }).readonly();
19059
19060
  var recordedDisplayContentSchema = external_exports.strictObject({
19061
+ artifactId: external_exports.string().max(128).default(""),
19060
19062
  data: external_exports.string().max(4e6),
19061
19063
  mimeType: external_exports.string().max(255),
19062
19064
  name: external_exports.string().max(500),
@@ -19340,6 +19342,9 @@ var SESSION_CANCEL_KIND = "session.cancel";
19340
19342
  var RUNTIME_LIVENESS_READY_KIND = "runtime.liveness.ready";
19341
19343
  var RUNTIME_HEARTBEAT_KIND = "runtime.heartbeat";
19342
19344
  var RUNTIME_HEARTBEAT_ACK_KIND = "runtime.heartbeat.ack";
19345
+ var RUNTIME_DELIVERY_KIND = "runtime.delivery";
19346
+ var RUNTIME_DELIVERY_RECEIVED_KIND = "runtime.delivery.received";
19347
+ var RUNTIME_DELIVERY_COMMITTED_KIND = "runtime.delivery.committed";
19343
19348
  var SESSION_STARTED_KIND = "session.started";
19344
19349
  var AGENT_MESSAGE_DELTA_KIND = "agent.message.delta";
19345
19350
  var AGENT_ACTIVITY_KIND = "agent.activity";
@@ -19362,6 +19367,7 @@ var DIRECTORY_IDENTIFIER_PATTERN2 = /^[a-zA-Z0-9][a-zA-Z0-9_-]{0,2047}$/;
19362
19367
  var MAX_PROMPT_LENGTH = 1e4;
19363
19368
  var MAX_PROMPT_ATTACHMENT_LENGTH = 6e6;
19364
19369
  var MAX_EVENT_TEXT_LENGTH = 1e5;
19370
+ var MAX_RUNTIME_DELIVERY_PAYLOAD_LENGTH = 8 * 1024 * 1024;
19365
19371
  var ACTIVITY_TYPES = /* @__PURE__ */ new Set(["plan", "progress", "reasoning", "tool"]);
19366
19372
  var ACTIVITY_STATUSES = /* @__PURE__ */ new Set(["pending", "running", "completed", "failed"]);
19367
19373
  var TOOL_KINDS = /* @__PURE__ */ new Set([
@@ -19640,6 +19646,37 @@ function decodeRuntimeHeartbeatAckEvent(encoded) {
19640
19646
  kind: RUNTIME_HEARTBEAT_ACK_KIND
19641
19647
  };
19642
19648
  }
19649
+ function decodeRuntimeDelivery(encoded) {
19650
+ const value = parseJson2(encoded);
19651
+ assertExactKeys(value, ["deliveryId", "kind", "payload", "sessionId"]);
19652
+ assertKind(value, RUNTIME_DELIVERY_KIND);
19653
+ return {
19654
+ deliveryId: readIdentifier(value, "deliveryId"),
19655
+ kind: RUNTIME_DELIVERY_KIND,
19656
+ payload: readString(value, "payload", MAX_RUNTIME_DELIVERY_PAYLOAD_LENGTH),
19657
+ sessionId: readIdentifier(value, "sessionId")
19658
+ };
19659
+ }
19660
+ function decodeRuntimeDeliveryReceived(encoded) {
19661
+ const value = parseJson2(encoded);
19662
+ assertExactKeys(value, ["deliveryId", "kind", "sessionId"]);
19663
+ assertKind(value, RUNTIME_DELIVERY_RECEIVED_KIND);
19664
+ return {
19665
+ deliveryId: readIdentifier(value, "deliveryId"),
19666
+ kind: RUNTIME_DELIVERY_RECEIVED_KIND,
19667
+ sessionId: readIdentifier(value, "sessionId")
19668
+ };
19669
+ }
19670
+ function decodeRuntimeDeliveryCommitted(encoded) {
19671
+ const value = parseJson2(encoded);
19672
+ assertExactKeys(value, ["deliveryId", "kind", "sessionId"]);
19673
+ assertKind(value, RUNTIME_DELIVERY_COMMITTED_KIND);
19674
+ return {
19675
+ deliveryId: readIdentifier(value, "deliveryId"),
19676
+ kind: RUNTIME_DELIVERY_COMMITTED_KIND,
19677
+ sessionId: readIdentifier(value, "sessionId")
19678
+ };
19679
+ }
19643
19680
  function decodeSessionStartedEvent(encoded) {
19644
19681
  const value = parseJson2(encoded);
19645
19682
  assertExactKeys(value, ["commandId", "kind", "attemptId", "sessionId"]);
@@ -19727,6 +19764,9 @@ function decodeSessionFailedEvent(encoded) {
19727
19764
  function encodeRuntimeHeartbeatEvent(message) {
19728
19765
  return JSON.stringify(decodeRuntimeHeartbeatEvent(JSON.stringify(message)));
19729
19766
  }
19767
+ function encodeRuntimeDeliveryReceived(message) {
19768
+ return JSON.stringify(decodeRuntimeDeliveryReceived(JSON.stringify(message)));
19769
+ }
19730
19770
  function encodeSessionStartedEvent(message) {
19731
19771
  return JSON.stringify(decodeSessionStartedEvent(JSON.stringify(message)));
19732
19772
  }
@@ -20425,7 +20465,8 @@ var SESSION_EVENT_COMMITTED_KIND = "session.event.committed";
20425
20465
  var SESSION_EVENT_REJECTED_KIND = "session.event.rejected";
20426
20466
  var SessionEventRejectionCode = {
20427
20467
  SessionDeleted: "session_deleted",
20428
- SessionNotFound: "session_not_found"
20468
+ SessionNotFound: "session_not_found",
20469
+ SessionRejected: "session_rejected"
20429
20470
  };
20430
20471
  var IDENTIFIER_PATTERN4 = /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/;
20431
20472
  var CURSOR_PATTERN = /^[A-Za-z0-9_-]{1,512}$/;
@@ -21162,6 +21203,212 @@ import {
21162
21203
  RequestError
21163
21204
  } from "@agentclientprotocol/sdk";
21164
21205
 
21206
+ // src/authorization/local-raster.ts
21207
+ import { readFile, realpath as realpath2, stat as stat2 } from "node:fs/promises";
21208
+ import { basename, isAbsolute, normalize, relative, sep } from "node:path";
21209
+ import { fileURLToPath as fileURLToPath2 } from "node:url";
21210
+ var MAX_LOCAL_RASTER_BYTES = 3e6;
21211
+ var PNG_SIGNATURE = Uint8Array.of(137, 80, 78, 71);
21212
+ var JPEG_SIGNATURE = Uint8Array.of(255, 216, 255);
21213
+ var GIF87_SIGNATURE = new TextEncoder().encode("GIF87a");
21214
+ var GIF89_SIGNATURE = new TextEncoder().encode("GIF89a");
21215
+ var RIFF_SIGNATURE = new TextEncoder().encode("RIFF");
21216
+ var WEBP_SIGNATURE = new TextEncoder().encode("WEBP");
21217
+ var LocalRasterImage = class {
21218
+ bytes;
21219
+ mimeType;
21220
+ name;
21221
+ constructor(name, mimeType, bytes) {
21222
+ this.bytes = bytes;
21223
+ this.mimeType = mimeType;
21224
+ this.name = name;
21225
+ }
21226
+ base64 = () => Buffer.from(this.bytes).toString("base64");
21227
+ };
21228
+ function startsWith(bytes, signature, offset = 0) {
21229
+ if (bytes.byteLength < offset + signature.byteLength) {
21230
+ return false;
21231
+ }
21232
+ return signature.every((value, index) => bytes[offset + index] === value);
21233
+ }
21234
+ function sniffRasterMime(bytes) {
21235
+ if (startsWith(bytes, PNG_SIGNATURE)) {
21236
+ return "image/png";
21237
+ }
21238
+ if (startsWith(bytes, JPEG_SIGNATURE)) {
21239
+ return "image/jpeg";
21240
+ }
21241
+ if (startsWith(bytes, GIF87_SIGNATURE) || startsWith(bytes, GIF89_SIGNATURE)) {
21242
+ return "image/gif";
21243
+ }
21244
+ if (startsWith(bytes, RIFF_SIGNATURE) && startsWith(bytes, WEBP_SIGNATURE, 8)) {
21245
+ return "image/webp";
21246
+ }
21247
+ return null;
21248
+ }
21249
+ function isInsideRoot(root, target) {
21250
+ const relation = relative(root, target);
21251
+ return relation !== ".." && !relation.startsWith(`..${sep}`) && !isAbsolute(relation);
21252
+ }
21253
+ async function resolveCanonicalPath(requested, signal) {
21254
+ signal.throwIfAborted();
21255
+ if (!isAbsolute(requested) || requested.includes("\0") || normalize(requested) !== requested) {
21256
+ return null;
21257
+ }
21258
+ try {
21259
+ const target = await realpath2(requested);
21260
+ signal.throwIfAborted();
21261
+ if (!isAbsolute(target) || normalize(target) !== target) {
21262
+ return null;
21263
+ }
21264
+ return target;
21265
+ } catch (cause) {
21266
+ signal.throwIfAborted();
21267
+ if (cause instanceof Error && cause.name === "AbortError") {
21268
+ throw cause;
21269
+ }
21270
+ return null;
21271
+ }
21272
+ }
21273
+ function parseLocalImageUri(uri) {
21274
+ const trimmed = uri.trim();
21275
+ if (trimmed.length === 0 || trimmed.length > 2048 || trimmed.includes("\0")) {
21276
+ return null;
21277
+ }
21278
+ if (trimmed.startsWith("data:")) {
21279
+ return null;
21280
+ }
21281
+ if (trimmed.startsWith("file:")) {
21282
+ try {
21283
+ const url2 = new URL(trimmed);
21284
+ if (url2.protocol !== "file:" || url2.host.length > 0) {
21285
+ return null;
21286
+ }
21287
+ return fileURLToPath2(url2);
21288
+ } catch {
21289
+ return null;
21290
+ }
21291
+ }
21292
+ if (/^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(trimmed)) {
21293
+ return null;
21294
+ }
21295
+ return trimmed;
21296
+ }
21297
+ async function readAuthorizedRaster(uri, roots, signal) {
21298
+ signal.throwIfAborted();
21299
+ const requested = parseLocalImageUri(uri);
21300
+ if (requested === null) {
21301
+ return null;
21302
+ }
21303
+ const target = await resolveCanonicalPath(requested, signal);
21304
+ if (target === null) {
21305
+ return null;
21306
+ }
21307
+ const targetMetadata = await stat2(target);
21308
+ signal.throwIfAborted();
21309
+ if (!targetMetadata.isFile() || targetMetadata.size < 1 || targetMetadata.size > MAX_LOCAL_RASTER_BYTES) {
21310
+ return null;
21311
+ }
21312
+ const authorizedRoots = [];
21313
+ for (const root of roots) {
21314
+ const directory = await resolveCanonicalPath(root, signal);
21315
+ if (directory === null) {
21316
+ continue;
21317
+ }
21318
+ const metadata = await stat2(directory);
21319
+ signal.throwIfAborted();
21320
+ if (metadata.isDirectory()) {
21321
+ authorizedRoots.push(directory);
21322
+ }
21323
+ }
21324
+ if (!authorizedRoots.some((root) => isInsideRoot(root, target))) {
21325
+ return null;
21326
+ }
21327
+ const bytes = new Uint8Array(await readFile(target));
21328
+ signal.throwIfAborted();
21329
+ if (bytes.byteLength < 1 || bytes.byteLength > MAX_LOCAL_RASTER_BYTES) {
21330
+ return null;
21331
+ }
21332
+ const mimeType = sniffRasterMime(bytes);
21333
+ if (mimeType === null) {
21334
+ return null;
21335
+ }
21336
+ return new LocalRasterImage(basename(target) || "Image", mimeType, bytes);
21337
+ }
21338
+
21339
+ // src/native-sessions/history-images.ts
21340
+ var IMAGE_MARKER = /\[@image\]\(([^)\r\n]*)(?:\)|$)/g;
21341
+ async function embedLocalHistoryImages(history, roots, signal) {
21342
+ if (history.status !== "available") {
21343
+ return history;
21344
+ }
21345
+ const messages = [];
21346
+ let imageCharacters = 0;
21347
+ for (const message of history.messages) {
21348
+ signal.throwIfAborted();
21349
+ const resolved = await resolveMessageImages(message, roots, imageCharacters, signal);
21350
+ imageCharacters += (resolved.images ?? []).reduce((size, image) => size + image.data.length, 0);
21351
+ messages.push(resolved);
21352
+ }
21353
+ return {
21354
+ ...history,
21355
+ messages
21356
+ };
21357
+ }
21358
+ async function resolveMessageImages(message, roots, usedCharacters, signal) {
21359
+ const images = [...message.images ?? []];
21360
+ let imageCharacters = images.reduce((size, image) => size + image.data.length, 0);
21361
+ const text = await replaceImageMarkers(message.text, async (uri) => {
21362
+ if (images.length >= 8 || usedCharacters + imageCharacters >= SESSION_HISTORY_IMAGE_CHARACTER_LIMIT) {
21363
+ return "[Image unavailable]";
21364
+ }
21365
+ const embedded = parseNativeHistoryText(`[@image](${uri})`).images[0];
21366
+ if (embedded !== void 0) {
21367
+ if (usedCharacters + imageCharacters + embedded.data.length > SESSION_HISTORY_IMAGE_CHARACTER_LIMIT) {
21368
+ return "[Image unavailable]";
21369
+ }
21370
+ images.push(embedded);
21371
+ imageCharacters += embedded.data.length;
21372
+ return "";
21373
+ }
21374
+ const local = await readAuthorizedRaster(uri, roots, signal);
21375
+ if (local === null) {
21376
+ return "[Image unavailable]";
21377
+ }
21378
+ const data = local.base64();
21379
+ if (usedCharacters + imageCharacters + data.length > SESSION_HISTORY_IMAGE_CHARACTER_LIMIT) {
21380
+ return "[Image unavailable]";
21381
+ }
21382
+ images.push({
21383
+ data,
21384
+ mimeType: local.mimeType,
21385
+ name: local.name
21386
+ });
21387
+ imageCharacters += data.length;
21388
+ return "";
21389
+ });
21390
+ return {
21391
+ ...message,
21392
+ text,
21393
+ ...images.length > 0 ? { images } : {}
21394
+ };
21395
+ }
21396
+ async function replaceImageMarkers(text, replace) {
21397
+ const matches = [...text.matchAll(IMAGE_MARKER)];
21398
+ if (matches.length === 0) {
21399
+ return text;
21400
+ }
21401
+ let cursor = 0;
21402
+ let rewritten = "";
21403
+ for (const match of matches) {
21404
+ const index = match.index ?? 0;
21405
+ rewritten += text.slice(cursor, index);
21406
+ rewritten += await replace(match[1] ?? "");
21407
+ cursor = index + match[0].length;
21408
+ }
21409
+ return `${rewritten}${text.slice(cursor)}`;
21410
+ }
21411
+
21165
21412
  // src/acp/activity.ts
21166
21413
  var TRUNCATION_MARKER = "\n\u2026 output truncated by Mobius";
21167
21414
  function isRecord4(value) {
@@ -21259,6 +21506,7 @@ function readContentOutputDetail(content) {
21259
21506
  function summarizeDisplayContent(content) {
21260
21507
  return {
21261
21508
  ...content,
21509
+ artifactId: truncate(content.artifactId, 128),
21262
21510
  data: truncate(content.data, AGENT_ACTIVITY_DETAIL_LIMIT),
21263
21511
  mimeType: truncate(content.mimeType, 255),
21264
21512
  name: truncate(content.name, 500),
@@ -21271,7 +21519,7 @@ function summarizeDisplayContent(content) {
21271
21519
  };
21272
21520
  }
21273
21521
  function contentFitsRecordingEnvelope(content) {
21274
- 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;
21522
+ 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;
21275
21523
  }
21276
21524
  function encodedByteLength(value) {
21277
21525
  return new TextEncoder().encode(JSON.stringify(value)).byteLength;
@@ -21297,6 +21545,7 @@ function recordedDetail(activity) {
21297
21545
  }
21298
21546
  function emptyDisplayContent(type) {
21299
21547
  return {
21548
+ artifactId: "",
21300
21549
  data: "",
21301
21550
  mimeType: "",
21302
21551
  name: "",
@@ -21309,6 +21558,16 @@ function emptyDisplayContent(type) {
21309
21558
  uri: ""
21310
21559
  };
21311
21560
  }
21561
+ function imageDisplayContent(mimeType, name, data, artifactId = "", uri = "") {
21562
+ return {
21563
+ ...emptyDisplayContent("image"),
21564
+ artifactId,
21565
+ data,
21566
+ mimeType,
21567
+ name,
21568
+ uri
21569
+ };
21570
+ }
21312
21571
  function normalizeContentBlock(content) {
21313
21572
  if (content.type === "text") {
21314
21573
  return { ...emptyDisplayContent("text"), text: content.text };
@@ -22100,7 +22359,6 @@ var AcpHistoryReplay = class {
22100
22359
  #messages = [];
22101
22360
  #lastMessageId = null;
22102
22361
  #characters = 0;
22103
- #imageCharacters = 0;
22104
22362
  #truncated = false;
22105
22363
  record = (update) => {
22106
22364
  if (update.sessionUpdate !== "user_message_chunk" && update.sessionUpdate !== "agent_message_chunk") {
@@ -22111,40 +22369,30 @@ var AcpHistoryReplay = class {
22111
22369
  }
22112
22370
  const role = update.sessionUpdate === "user_message_chunk" ? "user" : "assistant";
22113
22371
  const content = update.content;
22114
- const parsed = parseNativeHistoryText(
22115
- content.type === "text" ? content.text : content.type === "image" ? `[@image](data:${content.mimeType};base64,${content.data})` : `[${content.type} attachment]`
22116
- );
22117
- const text = parsed.text;
22118
- if (text.length === 0 && parsed.images.length === 0) {
22372
+ 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]`;
22373
+ if (text.length === 0) {
22119
22374
  return;
22120
22375
  }
22121
22376
  const previous = this.#messages.at(-1);
22122
22377
  const id = update.messageId ?? null;
22123
22378
  const continuation = previous?.role === role && id === this.#lastMessageId;
22124
22379
  const combined = continuation ? `${previous.text}${text}` : text;
22125
- const allImages = continuation ? [...previous.images ?? [], ...parsed.images] : parsed.images;
22126
- const images = allImages.slice(0, 8);
22127
- this.#truncated ||= images.length < allImages.length;
22128
22380
  if (continuation) {
22129
22381
  this.#messages.pop();
22130
22382
  this.#characters -= previous.text.length;
22131
- this.#imageCharacters -= (previous.images ?? []).reduce((size, image) => size + image.data.length, 0);
22132
22383
  }
22133
22384
  const bounded = combined.slice(-SESSION_HISTORY_CHARACTER_LIMIT);
22134
22385
  this.#truncated ||= bounded.length < combined.length;
22135
22386
  this.#messages.push({
22136
22387
  role,
22137
- text: bounded,
22138
- ...images.length > 0 ? { images } : {}
22388
+ text: bounded
22139
22389
  });
22140
22390
  this.#characters += bounded.length;
22141
- this.#imageCharacters += images.reduce((size, image) => size + image.data.length, 0);
22142
22391
  this.#lastMessageId = id;
22143
- while (this.#messages.length > SESSION_HISTORY_PREVIEW_MESSAGE_LIMIT || this.#characters > SESSION_HISTORY_CHARACTER_LIMIT || this.#imageCharacters > SESSION_HISTORY_IMAGE_CHARACTER_LIMIT) {
22392
+ while (this.#messages.length > SESSION_HISTORY_PREVIEW_MESSAGE_LIMIT || this.#characters > SESSION_HISTORY_CHARACTER_LIMIT) {
22144
22393
  const removed = this.#messages.shift();
22145
22394
  if (removed !== void 0) {
22146
22395
  this.#characters -= removed.text.length;
22147
- this.#imageCharacters -= (removed.images ?? []).reduce((size, image) => size + image.data.length, 0);
22148
22396
  }
22149
22397
  this.#truncated = true;
22150
22398
  }
@@ -22367,6 +22615,10 @@ var MAX_PRE_SESSION_UPDATES = 100;
22367
22615
  var MAX_PRE_SESSION_UPDATE_BYTES = 1024 * 1024;
22368
22616
  var SESSION_CONTROL_COMMAND_ID = "session-control";
22369
22617
  var NullAcpSessionObserver = class {
22618
+ importLocalImage = (_sessionId, _image, signal) => {
22619
+ signal.throwIfAborted();
22620
+ return Promise.resolve("");
22621
+ };
22370
22622
  onCommands = () => Promise.resolve();
22371
22623
  onConfig = () => Promise.resolve();
22372
22624
  onContent = () => Promise.resolve();
@@ -22989,11 +23241,75 @@ var AcpProcessSession = class _AcpProcessSession {
22989
23241
  );
22990
23242
  await this.#updateTail;
22991
23243
  signal.throwIfAborted();
22992
- return history.snapshot();
23244
+ return await embedLocalHistoryImages(
23245
+ history.snapshot(),
23246
+ [this.#cwd, ...this.#additionalDirectories],
23247
+ signal
23248
+ );
22993
23249
  } finally {
22994
23250
  this.#replay = { kind: "idle" };
22995
23251
  }
22996
23252
  };
23253
+ imageRoots = () => [this.#cwd, ...this.#additionalDirectories];
23254
+ emitAgentText = async (text, messageId) => {
23255
+ const signal = AbortSignal.timeout(2e4);
23256
+ const parts = text.split(/(\[@image\]\([^)\r\n]*(?:\)|$))/);
23257
+ let leftover = "";
23258
+ for (const part of parts) {
23259
+ const marker = /^\[@image\]\(([^)\r\n]*)(?:\)|$)/.exec(part);
23260
+ if (marker === null) {
23261
+ leftover += part;
23262
+ continue;
23263
+ }
23264
+ if (leftover.length > 0) {
23265
+ await this.#turn.onText(leftover, messageId);
23266
+ leftover = "";
23267
+ }
23268
+ const raster = await readAuthorizedRaster(marker[1] ?? "", this.imageRoots(), signal);
23269
+ if (raster === null) {
23270
+ leftover += "[Image unavailable]";
23271
+ continue;
23272
+ }
23273
+ await this.emitRaster(raster, messageId, signal);
23274
+ }
23275
+ if (leftover.length > 0) {
23276
+ await this.#turn.onText(leftover, messageId);
23277
+ }
23278
+ };
23279
+ emitAgentContent = async (content, messageId) => {
23280
+ if (content.type === "image" && content.data.length === 0 && content.uri.length > 0) {
23281
+ const signal = AbortSignal.timeout(2e4);
23282
+ const raster = await readAuthorizedRaster(content.uri, this.imageRoots(), signal);
23283
+ if (raster !== null) {
23284
+ await this.emitRaster(raster, messageId, signal);
23285
+ return;
23286
+ }
23287
+ }
23288
+ await this.#getObserver().onContent({
23289
+ commandId: this.#turn.commandId,
23290
+ content,
23291
+ contentId: `content-${crypto.randomUUID()}`,
23292
+ kind: AGENT_CONTENT_KIND,
23293
+ messageId,
23294
+ sessionId: this.#mobiusSessionId
23295
+ });
23296
+ };
23297
+ emitRaster = async (raster, messageId, signal) => {
23298
+ const artifactId = await this.#getObserver().importLocalImage(this.#mobiusSessionId, raster, signal);
23299
+ await this.#getObserver().onContent({
23300
+ commandId: this.#turn.commandId,
23301
+ content: imageDisplayContent(
23302
+ raster.mimeType,
23303
+ raster.name,
23304
+ artifactId.length > 0 ? "" : raster.base64(),
23305
+ artifactId
23306
+ ),
23307
+ contentId: `content-${crypto.randomUUID()}`,
23308
+ kind: AGENT_CONTENT_KIND,
23309
+ messageId,
23310
+ sessionId: this.#mobiusSessionId
23311
+ });
23312
+ };
22997
23313
  async #initializeAgent(signal) {
22998
23314
  const initialized = await this.race(
22999
23315
  this.#connection.agent.request(
@@ -23696,18 +24012,14 @@ var AcpProcessSession = class _AcpProcessSession {
23696
24012
  );
23697
24013
  } else {
23698
24014
  await this.#turn.activities.finishNarrative();
23699
- await this.#turn.onText(update.content.text, truncate3(update.messageId ?? "", 255));
24015
+ await this.emitAgentText(update.content.text, truncate3(update.messageId ?? "", 255));
23700
24016
  }
23701
24017
  } else {
23702
24018
  await this.#turn.activities.finishNarrative();
23703
- await this.#getObserver().onContent({
23704
- commandId: this.#turn.commandId,
23705
- content: normalizeContentBlock(update.content),
23706
- contentId: `content-${crypto.randomUUID()}`,
23707
- kind: AGENT_CONTENT_KIND,
23708
- messageId: truncate3(update.messageId ?? "", 255),
23709
- sessionId: this.#mobiusSessionId
23710
- });
24019
+ await this.emitAgentContent(
24020
+ normalizeContentBlock(update.content),
24021
+ truncate3(update.messageId ?? "", 255)
24022
+ );
23711
24023
  }
23712
24024
  return;
23713
24025
  }
@@ -24573,7 +24885,7 @@ var AuditStore = class {
24573
24885
  this.database.exec("ALTER TABLE audit_events ADD COLUMN details_json TEXT NOT NULL DEFAULT '{}'");
24574
24886
  }
24575
24887
  }
24576
- record(record2) {
24888
+ record(record3) {
24577
24889
  this.database.prepare(
24578
24890
  `
24579
24891
  INSERT INTO audit_events (
@@ -24586,10 +24898,10 @@ var AuditStore = class {
24586
24898
  `
24587
24899
  ).run(
24588
24900
  (/* @__PURE__ */ new Date()).toISOString(),
24589
- record2.event,
24590
- record2.commandId,
24591
- record2.sessionId,
24592
- JSON.stringify(record2.details ?? {})
24901
+ record3.event,
24902
+ record3.commandId,
24903
+ record3.sessionId,
24904
+ JSON.stringify(record3.details ?? {})
24593
24905
  );
24594
24906
  }
24595
24907
  close() {
@@ -24611,7 +24923,7 @@ import { randomBytes } from "node:crypto";
24611
24923
 
24612
24924
  // src/bots/local-bot-grant-store.ts
24613
24925
  import { createHash, randomUUID } from "node:crypto";
24614
- import { stat as stat2 } from "node:fs/promises";
24926
+ import { stat as stat3 } from "node:fs/promises";
24615
24927
  import { DatabaseSync as DatabaseSync3 } from "node:sqlite";
24616
24928
  var LOCAL_BOT_GRANT_LIFETIME_MILLISECONDS = 90 * 24 * 60 * 60 * 1e3;
24617
24929
  var LocalBotAuthorizationError = class extends Error {
@@ -24669,7 +24981,7 @@ function agentDigest(agent) {
24669
24981
  );
24670
24982
  }
24671
24983
  async function workspaceDigest(path2) {
24672
- const metadata = await stat2(path2);
24984
+ const metadata = await stat3(path2);
24673
24985
  if (!metadata.isDirectory()) {
24674
24986
  throw new LocalBotAuthorizationError("binding_incompatible", "The Bot workspace is not a directory");
24675
24987
  }
@@ -25207,7 +25519,7 @@ async function executeBotMessageCommand(arguments_, environment, signal) {
25207
25519
  // src/bots/bot-outbound-ipc.ts
25208
25520
  import { chmod, mkdir, unlink } from "node:fs/promises";
25209
25521
  import { createServer } from "node:net";
25210
- import { dirname as dirname3, isAbsolute } from "node:path";
25522
+ import { dirname as dirname3, isAbsolute as isAbsolute2 } from "node:path";
25211
25523
  import { fetch } from "undici";
25212
25524
  var BOT_IPC_REQUEST_LIMIT = 32 * 1024;
25213
25525
  var BOT_IPC_TIMEOUT_MILLISECONDS2 = 2e4;
@@ -25305,7 +25617,7 @@ var BotOutboundIpcServer = class {
25305
25617
  #usesFilesystemSocket;
25306
25618
  constructor(socketPath, relayUrl, registry2) {
25307
25619
  const usesFilesystemSocket = !socketPath.startsWith(WINDOWS_NAMED_PIPE_PREFIX);
25308
- if (usesFilesystemSocket && !isAbsolute(socketPath)) {
25620
+ if (usesFilesystemSocket && !isAbsolute2(socketPath)) {
25309
25621
  throw new Error("The Bot IPC path must be absolute");
25310
25622
  }
25311
25623
  this.#registry = registry2;
@@ -25445,9 +25757,9 @@ var BotOutboundIpcServer = class {
25445
25757
 
25446
25758
  // src/pairing/pair-local-machine.ts
25447
25759
  import { randomUUID as randomUUID3 } from "node:crypto";
25448
- import { mkdir as mkdir4, open as open4, realpath as realpath6, rename as rename3, stat as stat6, writeFile as writeFile2 } from "node:fs/promises";
25760
+ import { mkdir as mkdir4, open as open4, realpath as realpath7, rename as rename3, stat as stat7, writeFile as writeFile2 } from "node:fs/promises";
25449
25761
  import { hostname as hostname3 } from "node:os";
25450
- import { basename, join as join14, resolve as resolve3 } from "node:path";
25762
+ import { basename as basename2, join as join14, resolve as resolve3 } from "node:path";
25451
25763
  import { fetch as fetch3 } from "undici";
25452
25764
 
25453
25765
  // src/agent-catalog/agent-discovery.ts
@@ -25556,8 +25868,8 @@ var LocalAgentInventory = class {
25556
25868
  };
25557
25869
 
25558
25870
  // src/agent-installation/managed-npm-package.ts
25559
- import { mkdir as mkdir2, mkdtemp, open as open2, realpath as realpath2, rename, rm, stat as stat3 } from "node:fs/promises";
25560
- import { delimiter, dirname as dirname4, isAbsolute as isAbsolute2, join as join4, relative, sep } from "node:path";
25871
+ import { mkdir as mkdir2, mkdtemp, open as open2, realpath as realpath3, rename, rm, stat as stat4 } from "node:fs/promises";
25872
+ import { delimiter, dirname as dirname4, isAbsolute as isAbsolute3, join as join4, relative as relative2, sep as sep2 } from "node:path";
25561
25873
  var INSTALL_TIMEOUT_MILLISECONDS = 5 * 60 * 1e3;
25562
25874
  var PACKAGE_METADATA_LIMIT_BYTES = 64 * 1024;
25563
25875
  var PACKAGE_LOCK_LIMIT_BYTES = 8 * 1024 * 1024;
@@ -25611,8 +25923,8 @@ function packagePath(root, packageName) {
25611
25923
  return join4(root, "node_modules", ...packageName.split("/"));
25612
25924
  }
25613
25925
  function isContainedPath(root, candidate) {
25614
- const difference = relative(root, candidate);
25615
- return difference.length > 0 && difference !== ".." && !difference.startsWith(`..${sep}`) && !isAbsolute2(difference);
25926
+ const difference = relative2(root, candidate);
25927
+ return difference.length > 0 && difference !== ".." && !difference.startsWith(`..${sep2}`) && !isAbsolute3(difference);
25616
25928
  }
25617
25929
  async function readJsonRecord(path2, maximumBytes) {
25618
25930
  try {
@@ -25713,7 +26025,7 @@ function verifyPackageLockEntry(lock, definition, verifyDependencyClosure) {
25713
26025
  }
25714
26026
  }
25715
26027
  async function verifyRequiredDependency(rootPath, lock, definition) {
25716
- const dependencyRoot = await realpath2(packagePath(rootPath, definition.packageName));
26028
+ const dependencyRoot = await realpath3(packagePath(rootPath, definition.packageName));
25717
26029
  if (!isContainedPath(rootPath, dependencyRoot)) {
25718
26030
  throw new ManagedNpmPackageError(
25719
26031
  "managed_package_verification_failed",
@@ -25742,8 +26054,8 @@ async function validateManagedNpmPackage(root, definition) {
25742
26054
  }
25743
26055
  }
25744
26056
  async function validateManagedNpmPackageContents(root, definition) {
25745
- const rootPath = await realpath2(root);
25746
- const packageRoot = await realpath2(packagePath(rootPath, definition.packageName));
26057
+ const rootPath = await realpath3(root);
26058
+ const packageRoot = await realpath3(packagePath(rootPath, definition.packageName));
25747
26059
  if (!isContainedPath(rootPath, packageRoot)) {
25748
26060
  throw new ManagedNpmPackageError(
25749
26061
  "managed_package_verification_failed",
@@ -25778,7 +26090,7 @@ var ManagedNpmPackageInstaller = class {
25778
26090
  install = async (root, definition, environment, signal) => {
25779
26091
  signal.throwIfAborted();
25780
26092
  try {
25781
- const metadata = await stat3(root);
26093
+ const metadata = await stat4(root);
25782
26094
  if (metadata.isDirectory()) {
25783
26095
  return await validateManagedNpmPackage(root, definition);
25784
26096
  }
@@ -26045,8 +26357,8 @@ var CursorCliAgentSpecification = class extends DirectAcpAgentDefinition {
26045
26357
  };
26046
26358
 
26047
26359
  // src/agent-catalog/agents/deepseek-harness-agent.ts
26048
- import { realpath as realpath3, stat as stat4 } from "node:fs/promises";
26049
- import { isAbsolute as isAbsolute3, join as join6, normalize } from "node:path";
26360
+ import { realpath as realpath4, stat as stat5 } from "node:fs/promises";
26361
+ import { isAbsolute as isAbsolute4, join as join6, normalize as normalize2 } from "node:path";
26050
26362
 
26051
26363
  // src/agent-installation/deepseek-managed-package.ts
26052
26364
  var DeepSeekHarnessManagedPackage = class extends SriManagedNpmPackageDefinition {
@@ -26064,12 +26376,12 @@ var DEEPSEEK_HARNESS_PACKAGE = new DeepSeekHarnessManagedPackage(
26064
26376
 
26065
26377
  // src/agent-catalog/agents/deepseek-harness-agent.ts
26066
26378
  async function validateAgentHome(path2) {
26067
- if (!isAbsolute3(path2) || normalize(path2) !== path2) {
26379
+ if (!isAbsolute4(path2) || normalize2(path2) !== path2) {
26068
26380
  throw new AgentProbeError("agent_environment_invalid", "The configured Agent home is invalid");
26069
26381
  }
26070
26382
  try {
26071
- const resolved = await realpath3(path2);
26072
- const metadata = await stat4(resolved);
26383
+ const resolved = await realpath4(path2);
26384
+ const metadata = await stat5(resolved);
26073
26385
  if (!metadata.isDirectory() || typeof process.getuid === "function" && metadata.uid !== process.getuid()) {
26074
26386
  throw new Error("Agent home is not a user-owned directory");
26075
26387
  }
@@ -26151,8 +26463,8 @@ var DeepSeekHarnessAgentSpecification = class extends DirectAcpAgentDefinition {
26151
26463
  };
26152
26464
 
26153
26465
  // src/agent-catalog/agents/grok-build-agent.ts
26154
- import { realpath as realpath4 } from "node:fs/promises";
26155
- import { isAbsolute as isAbsolute4, join as join7, relative as relative2, sep as sep2 } from "node:path";
26466
+ import { realpath as realpath5 } from "node:fs/promises";
26467
+ import { isAbsolute as isAbsolute5, join as join7, relative as relative3, sep as sep3 } from "node:path";
26156
26468
 
26157
26469
  // src/agent-installation/grok-managed-package.ts
26158
26470
  var GROK_BUILD_MANAGED_VERSION = "1.0.21";
@@ -26214,8 +26526,8 @@ function grokBuildManagedPackage(platform, architecture) {
26214
26526
 
26215
26527
  // src/agent-catalog/agents/grok-build-agent.ts
26216
26528
  function isContainedPath2(root, candidate) {
26217
- const difference = relative2(root, candidate);
26218
- return difference.length > 0 && difference !== ".." && !difference.startsWith(`..${sep2}`) && !isAbsolute4(difference);
26529
+ const difference = relative3(root, candidate);
26530
+ return difference.length > 0 && difference !== ".." && !difference.startsWith(`..${sep3}`) && !isAbsolute5(difference);
26219
26531
  }
26220
26532
  var GrokBuildAgentSpecification = class extends DirectAcpAgentDefinition {
26221
26533
  adapterVersion = GROK_BUILD_MANAGED_VERSION;
@@ -26242,7 +26554,7 @@ var GrokBuildAgentSpecification = class extends DirectAcpAgentDefinition {
26242
26554
  );
26243
26555
  if (managed.path === agent.path) {
26244
26556
  return Object.freeze({
26245
- GROK_HOME: await realpath4(
26557
+ GROK_HOME: await realpath5(
26246
26558
  join7(stateDirectory, "agents", this.id, GROK_BUILD_MANAGED_VERSION, "home")
26247
26559
  )
26248
26560
  });
@@ -26254,7 +26566,7 @@ var GrokBuildAgentSpecification = class extends DirectAcpAgentDefinition {
26254
26566
  };
26255
26567
  resolveManagedAgent = async (stateDirectory, platform, signal) => {
26256
26568
  signal.throwIfAborted();
26257
- const versionRoot = await realpath4(join7(stateDirectory, "agents", this.id, GROK_BUILD_MANAGED_VERSION));
26569
+ const versionRoot = await realpath5(join7(stateDirectory, "agents", this.id, GROK_BUILD_MANAGED_VERSION));
26258
26570
  await validateManagedNpmPackage(join7(versionRoot, "package"), grokBuildManagedPackage(platform, process.arch));
26259
26571
  const executable = await resolveExecutablePath(join7(versionRoot, "home", "bin", "grok"), platform);
26260
26572
  signal.throwIfAborted();
@@ -26279,8 +26591,8 @@ import { join as join9 } from "node:path";
26279
26591
  // src/agent-installation/managed-agent-archive.ts
26280
26592
  import { createHash as createHash2 } from "node:crypto";
26281
26593
  import { createReadStream } from "node:fs";
26282
- import { chmod as chmod2, copyFile, mkdir as mkdir3, mkdtemp as mkdtemp2, open as open3, realpath as realpath5, rename as rename2, rm as rm2, stat as stat5, writeFile } from "node:fs/promises";
26283
- import { dirname as dirname5, isAbsolute as isAbsolute5, join as join8, relative as relative3, sep as sep3 } from "node:path";
26594
+ import { chmod as chmod2, copyFile, mkdir as mkdir3, mkdtemp as mkdtemp2, open as open3, realpath as realpath6, rename as rename2, rm as rm2, stat as stat6, writeFile } from "node:fs/promises";
26595
+ import { dirname as dirname5, isAbsolute as isAbsolute6, join as join8, relative as relative4, sep as sep4 } from "node:path";
26284
26596
 
26285
26597
  // src/agent-installation/verified-download.ts
26286
26598
  import { fetch as fetch2 } from "undici";
@@ -26385,8 +26697,8 @@ function isRecord10(value) {
26385
26697
  return typeof value === "object" && value !== null && !Array.isArray(value);
26386
26698
  }
26387
26699
  function isContainedPath3(root, candidate) {
26388
- const difference = relative3(root, candidate);
26389
- return difference.length > 0 && difference !== ".." && !difference.startsWith(`..${sep3}`) && !isAbsolute5(difference);
26700
+ const difference = relative4(root, candidate);
26701
+ return difference.length > 0 && difference !== ".." && !difference.startsWith(`..${sep4}`) && !isAbsolute6(difference);
26390
26702
  }
26391
26703
  async function hashFile(path2, signal) {
26392
26704
  signal.throwIfAborted();
@@ -26460,8 +26772,8 @@ async function readManifest(path2) {
26460
26772
  }
26461
26773
  async function validateManagedAgentArchive(root, definition, signal) {
26462
26774
  try {
26463
- const rootPath = await realpath5(root);
26464
- const rootMetadata = await stat5(rootPath);
26775
+ const rootPath = await realpath6(root);
26776
+ const rootMetadata = await stat6(rootPath);
26465
26777
  if (!rootMetadata.isDirectory() || typeof process.getuid === "function" && rootMetadata.uid !== process.getuid()) {
26466
26778
  throw new Error("Managed Agent root is not user-owned");
26467
26779
  }
@@ -26676,7 +26988,7 @@ var PiAgentSpecification = class extends BridgedAcpAgentDefinition {
26676
26988
  };
26677
26989
 
26678
26990
  // src/agent-catalog/agents/workbuddy-agent.ts
26679
- import { isAbsolute as isAbsolute6, join as join11 } from "node:path";
26991
+ import { isAbsolute as isAbsolute7, join as join11 } from "node:path";
26680
26992
 
26681
26993
  // src/agent-installation/workbuddy-managed-package.ts
26682
26994
  var WORKBUDDY_MANAGED_VERSION = "2.146.0";
@@ -26742,7 +27054,7 @@ var WorkBuddyAgentSpecification = class extends DirectAcpAgentDefinition {
26742
27054
  }
26743
27055
  const requestedPaths = [join11("/Applications", ...WORKBUDDY_MACOS_EXECUTABLE_PATH)];
26744
27056
  const homeDirectory = context.environment["HOME"];
26745
- if (homeDirectory !== void 0 && isAbsolute6(homeDirectory)) {
27057
+ if (homeDirectory !== void 0 && isAbsolute7(homeDirectory)) {
26746
27058
  requestedPaths.unshift(join11(homeDirectory, "Applications", ...WORKBUDDY_MACOS_EXECUTABLE_PATH));
26747
27059
  }
26748
27060
  const executables = [];
@@ -26788,7 +27100,7 @@ import {
26788
27100
  } from "@agentclientprotocol/sdk";
26789
27101
 
26790
27102
  // src/agent-catalog/executable-discovery.ts
26791
- import { isAbsolute as isAbsolute7, join as join13 } from "node:path";
27103
+ import { isAbsolute as isAbsolute8, join as join13 } from "node:path";
26792
27104
 
26793
27105
  // src/agent-installation/managed-adapter-installer.ts
26794
27106
  import { join as join12 } from "node:path";
@@ -26893,7 +27205,7 @@ async function resolveManagedAdapterExecutable(specification, context) {
26893
27205
  async function resolveSpecificationExecutables(executableName, overrideVariable, resolveInstalled, resolveManaged, context) {
26894
27206
  const override = context.environment[overrideVariable];
26895
27207
  if (override !== void 0) {
26896
- if (override.length === 0 || !isAbsolute7(override)) {
27208
+ if (override.length === 0 || !isAbsolute8(override)) {
26897
27209
  return [];
26898
27210
  }
26899
27211
  const executable = await resolveExecutablePath(override, context.platform);
@@ -27421,8 +27733,8 @@ async function resolveDefaultWorkspace(path2) {
27421
27733
  const requestedWorkspace = resolve3(path2);
27422
27734
  try {
27423
27735
  await mkdir4(requestedWorkspace, { recursive: true, mode: 448 });
27424
- const defaultWorkspace = await realpath6(requestedWorkspace);
27425
- const metadata = await stat6(defaultWorkspace);
27736
+ const defaultWorkspace = await realpath7(requestedWorkspace);
27737
+ const metadata = await stat7(defaultWorkspace);
27426
27738
  if (!metadata.isDirectory()) {
27427
27739
  throw new PairingClientError("invalid_workspace", "The default workspace is not a directory");
27428
27740
  }
@@ -27468,12 +27780,12 @@ function decodePairingResponse(value, credentialField, expectedKeys) {
27468
27780
  throw new PairingClientError("invalid_relay_response", "The relay returned an invalid pairing response");
27469
27781
  }
27470
27782
  const channelId = value["channelId"];
27471
- const runtimeCredential = value[credentialField];
27783
+ const runtimeCredential2 = value[credentialField];
27472
27784
  const runtimeId = value["runtimeId"];
27473
- if (typeof channelId !== "string" || !IDENTIFIER_PATTERN6.test(channelId) || typeof runtimeCredential !== "string" || !TOKEN_PATTERN2.test(runtimeCredential) || typeof runtimeId !== "string" || !IDENTIFIER_PATTERN6.test(runtimeId)) {
27785
+ if (typeof channelId !== "string" || !IDENTIFIER_PATTERN6.test(channelId) || typeof runtimeCredential2 !== "string" || !TOKEN_PATTERN2.test(runtimeCredential2) || typeof runtimeId !== "string" || !IDENTIFIER_PATTERN6.test(runtimeId)) {
27474
27786
  throw new PairingClientError("invalid_relay_response", "The relay returned an invalid pairing response");
27475
27787
  }
27476
- return { channelId, runtimeCredential, runtimeId };
27788
+ return { channelId, runtimeCredential: runtimeCredential2, runtimeId };
27477
27789
  }
27478
27790
  async function claimPairing(options, defaultWorkspace, localAgents, installableAgents, signal) {
27479
27791
  const agents = localAgents.map((agent) => ({
@@ -27492,7 +27804,7 @@ async function claimPairing(options, defaultWorkspace, localAgents, installableA
27492
27804
  installableAgents,
27493
27805
  machineName: hostname3(),
27494
27806
  pairingCode: options.code,
27495
- workspaceName: basename(defaultWorkspace) || "Local workspace"
27807
+ workspaceName: basename2(defaultWorkspace) || "Local workspace"
27496
27808
  }),
27497
27809
  dispatcher: environmentProxyDispatcher,
27498
27810
  headers: { "content-type": "application/json" },
@@ -27508,7 +27820,7 @@ async function claimPairing(options, defaultWorkspace, localAgents, installableA
27508
27820
  }
27509
27821
  return options.pairingId.length > 0 ? decodePairingResponse(value, "runtimeCredential", REDEEM_RESPONSE_KEYS) : decodePairingResponse(value, "daemonToken", CLAIM_RESPONSE_KEYS);
27510
27822
  }
27511
- async function persistConnection(channelId, relayOrigin, runtimeCredential, defaultWorkspace, environment) {
27823
+ async function persistConnection(channelId, relayOrigin, runtimeCredential2, defaultWorkspace, environment) {
27512
27824
  const connectionsDirectory = join14(readStateDirectory(environment), "connections");
27513
27825
  await mkdir4(connectionsDirectory, { mode: 448, recursive: true });
27514
27826
  const connectionPath = join14(connectionsDirectory, `${channelId}.json`);
@@ -27520,7 +27832,7 @@ async function persistConnection(channelId, relayOrigin, runtimeCredential, defa
27520
27832
  defaultWorkspace,
27521
27833
  channelId,
27522
27834
  relayOrigin: relayOrigin.toString(),
27523
- runtimeCredential
27835
+ runtimeCredential: runtimeCredential2
27524
27836
  },
27525
27837
  null,
27526
27838
  2
@@ -27537,16 +27849,16 @@ function decodeSavedConnection(value, expectedChannelId) {
27537
27849
  }
27538
27850
  const defaultWorkspace = value["defaultWorkspace"];
27539
27851
  const channelId = value["channelId"];
27540
- const runtimeCredential = value["runtimeCredential"] ?? value["daemonToken"];
27852
+ const runtimeCredential2 = value["runtimeCredential"] ?? value["daemonToken"];
27541
27853
  const relayOrigin = value["relayOrigin"];
27542
- if (typeof defaultWorkspace !== "string" || typeof channelId !== "string" || channelId !== expectedChannelId || !IDENTIFIER_PATTERN6.test(channelId) || typeof runtimeCredential !== "string" || !TOKEN_PATTERN2.test(runtimeCredential) || typeof relayOrigin !== "string") {
27854
+ if (typeof defaultWorkspace !== "string" || typeof channelId !== "string" || channelId !== expectedChannelId || !IDENTIFIER_PATTERN6.test(channelId) || typeof runtimeCredential2 !== "string" || !TOKEN_PATTERN2.test(runtimeCredential2) || typeof relayOrigin !== "string") {
27543
27855
  throw new PairingClientError("invalid_connection", "The saved connection is invalid");
27544
27856
  }
27545
27857
  return {
27546
27858
  defaultWorkspace,
27547
27859
  channelId,
27548
27860
  relayOrigin: parseRelayOrigin(relayOrigin),
27549
- runtimeCredential
27861
+ runtimeCredential: runtimeCredential2
27550
27862
  };
27551
27863
  }
27552
27864
  async function readSavedConnection(channelId, environment) {
@@ -27663,12 +27975,29 @@ async function resumeLocalMachine(arguments_, signal = new AbortController().sig
27663
27975
 
27664
27976
  // src/run-daemon.ts
27665
27977
  import { randomUUID as randomUUID6 } from "node:crypto";
27666
- import { basename as basename4, join as join16 } from "node:path";
27978
+ import { basename as basename5, join as join16 } from "node:path";
27667
27979
  import { styleText } from "node:util";
27668
- import { fetch as fetch6, WebSocket as WebSocket2 } from "undici";
27980
+ import { fetch as fetch7, WebSocket as WebSocket2 } from "undici";
27669
27981
 
27670
27982
  // src/agent-catalog/publish-agent-catalog.ts
27671
27983
  import { fetch as fetch4 } from "undici";
27984
+
27985
+ // src/relay-connection/runtime-authentication.ts
27986
+ function runtimeCredential(relayUrl) {
27987
+ return relayUrl.searchParams.get("token") ?? "";
27988
+ }
27989
+ function runtimeAuthorization(relayUrl) {
27990
+ const credential = runtimeCredential(relayUrl);
27991
+ return credential.length === 0 ? {} : { authorization: `Bearer ${credential}` };
27992
+ }
27993
+ function relayHttpEndpoint(relayUrl) {
27994
+ const endpoint = new URL(relayUrl);
27995
+ endpoint.protocol = endpoint.protocol === "wss:" ? "https:" : "http:";
27996
+ endpoint.search = "";
27997
+ return endpoint;
27998
+ }
27999
+
28000
+ // src/agent-catalog/publish-agent-catalog.ts
27672
28001
  var CATALOG_UPDATE_TIMEOUT_MILLISECONDS = 2e4;
27673
28002
  var AgentCatalogPublishError = class extends Error {
27674
28003
  code = "agent_catalog_update_failed";
@@ -27678,8 +28007,7 @@ var AgentCatalogPublishError = class extends Error {
27678
28007
  }
27679
28008
  };
27680
28009
  function catalogEndpoint(config2) {
27681
- const endpoint = new URL(config2.relayUrl);
27682
- endpoint.protocol = endpoint.protocol === "wss:" ? "https:" : "http:";
28010
+ const endpoint = relayHttpEndpoint(config2.relayUrl);
27683
28011
  if (endpoint.pathname.endsWith("/daemon")) {
27684
28012
  endpoint.pathname = `${endpoint.pathname.slice(0, -"/daemon".length)}/catalog`;
27685
28013
  return endpoint;
@@ -27710,7 +28038,7 @@ async function publishAgentCatalog(config2, signal) {
27710
28038
  installableAgents: catalog.installableAgents
27711
28039
  }),
27712
28040
  dispatcher: environmentProxyDispatcher,
27713
- headers: { "content-type": "application/json" },
28041
+ headers: { ...runtimeAuthorization(config2.relayUrl), "content-type": "application/json" },
27714
28042
  method: "PUT",
27715
28043
  signal: requestSignal
27716
28044
  });
@@ -28192,103 +28520,499 @@ var FixedInstallationExecutor = class {
28192
28520
  };
28193
28521
  };
28194
28522
 
28195
- // src/authorization/workspace-directory.ts
28196
- import { readdir, realpath as realpath7, stat as stat7 } from "node:fs/promises";
28197
- import { homedir as homedir2 } from "node:os";
28198
- import { basename as basename2, dirname as dirname6, isAbsolute as isAbsolute8, join as join15, normalize as normalize2, relative as relative4 } from "node:path";
28199
- var WorkspaceDirectoryListing = class {
28200
- directoryId;
28201
- directoryLabel;
28202
- entries;
28203
- parentDirectoryId;
28204
- constructor(directoryId2, directoryLabel, entries, parentDirectoryId) {
28205
- this.directoryId = directoryId2;
28206
- this.directoryLabel = directoryLabel;
28207
- this.entries = entries;
28208
- this.parentDirectoryId = parentDirectoryId;
28523
+ // src/artifacts/runtime-artifact-uploader.ts
28524
+ import { createHash as createHash3 } from "node:crypto";
28525
+
28526
+ // ../mobius-sdk/src/errors.ts
28527
+ var MobiusError = class extends Error {
28528
+ code;
28529
+ constructor(code, message, options = {}) {
28530
+ super(message, options);
28531
+ this.code = code;
28532
+ this.name = "MobiusError";
28209
28533
  }
28210
28534
  };
28211
- function encodePath(path2) {
28212
- const encoded = Buffer.from(path2, "utf8").toString("base64url");
28213
- if (encoded.length === 0 || encoded.length > 2e3) {
28214
- throw new LocalAuthorizationError("The local directory path is too long to select");
28535
+ var MobiusProtocolError = class extends MobiusError {
28536
+ constructor(message, options = {}) {
28537
+ super("invalid_service_response", message, options);
28538
+ this.name = "MobiusProtocolError";
28215
28539
  }
28216
- return `path-${encoded}`;
28540
+ };
28541
+ var MobiusValidationError = class extends MobiusError {
28542
+ constructor(message, options = {}) {
28543
+ super("invalid_request", message, options);
28544
+ this.name = "MobiusValidationError";
28545
+ }
28546
+ };
28547
+
28548
+ // ../mobius-sdk/src/resources.ts
28549
+ var IDENTIFIER_PATTERN7 = /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/;
28550
+ function invalidResponse(message) {
28551
+ return new MobiusProtocolError(message);
28217
28552
  }
28218
- function decodePath(value, prefix) {
28219
- const encoded = value.slice(prefix.length);
28220
- if (encoded.length === 0 || encoded.length > 2e3 || !/^[a-zA-Z0-9_-]+$/.test(encoded)) {
28221
- throw new LocalAuthorizationError("The directory identifier is invalid");
28553
+ function isRecord12(value) {
28554
+ return typeof value === "object" && value !== null && !Array.isArray(value);
28555
+ }
28556
+ function record2(value, name) {
28557
+ if (!isRecord12(value)) {
28558
+ throw invalidResponse(`The service returned an invalid ${name}`);
28222
28559
  }
28223
- const decoded = Buffer.from(encoded, "base64url").toString("utf8");
28224
- if (Buffer.from(decoded, "utf8").toString("base64url") !== encoded || decoded.includes("\0") || normalize2(decoded) !== decoded) {
28225
- throw new LocalAuthorizationError("The directory identifier is invalid");
28560
+ return value;
28561
+ }
28562
+ function stringField(value, field, maximumLength = 85e5) {
28563
+ const candidate = value[field];
28564
+ if (typeof candidate !== "string" || candidate.length > maximumLength) {
28565
+ throw invalidResponse(`The service returned an invalid ${field}`);
28226
28566
  }
28227
- return decoded;
28567
+ return candidate;
28228
28568
  }
28229
- var WorkspaceDirectoryService = class {
28230
- #bindingId;
28231
- #defaultWorkspace;
28232
- constructor(bindingId, defaultWorkspace) {
28233
- this.#bindingId = bindingId;
28234
- this.#defaultWorkspace = defaultWorkspace;
28569
+ function identifierField(value, field) {
28570
+ const candidate = stringField(value, field, 128);
28571
+ if (!IDENTIFIER_PATTERN7.test(candidate)) {
28572
+ throw invalidResponse(`The service returned an invalid ${field}`);
28235
28573
  }
28236
- authorizeMachine = (bindingId) => {
28237
- if (bindingId !== this.#bindingId) {
28238
- throw new LocalAuthorizationError("The runtime binding is not authorized");
28239
- }
28240
- };
28241
- requestedPath = (id) => {
28242
- if (id === "default") {
28243
- return this.#defaultWorkspace;
28244
- }
28245
- if (id === "home") {
28246
- return homedir2();
28247
- }
28248
- if (id.startsWith("path-")) {
28249
- const path2 = decodePath(id, "path-");
28250
- if (isAbsolute8(path2)) {
28251
- return path2;
28252
- }
28253
- }
28254
- throw new LocalAuthorizationError("The directory identifier is invalid");
28255
- };
28256
- resolvePath = async (requested, signal) => {
28257
- signal.throwIfAborted();
28258
- if (!isAbsolute8(requested) || requested.includes("\0") || normalize2(requested) !== requested) {
28259
- throw new LocalAuthorizationError("The local directory path is invalid");
28260
- }
28261
- try {
28262
- const target = await realpath7(requested);
28263
- signal.throwIfAborted();
28264
- const metadata = await stat7(target);
28265
- signal.throwIfAborted();
28266
- if (!isAbsolute8(target) || normalize2(target) !== target || !metadata.isDirectory()) {
28267
- throw new LocalAuthorizationError("The selected location is not a directory");
28268
- }
28269
- return target;
28270
- } catch (cause) {
28271
- signal.throwIfAborted();
28272
- if (cause instanceof LocalAuthorizationError) {
28273
- throw cause;
28274
- }
28275
- throw new LocalAuthorizationError("This directory is missing or unavailable to your user account", {
28276
- cause
28277
- });
28574
+ return candidate;
28575
+ }
28576
+ function integerField(value, field) {
28577
+ const candidate = value[field];
28578
+ if (typeof candidate !== "number" || !Number.isSafeInteger(candidate) || candidate < 0) {
28579
+ throw invalidResponse(`The service returned an invalid ${field}`);
28580
+ }
28581
+ return candidate;
28582
+ }
28583
+ function validateTimestamp(value, field) {
28584
+ if (Number.isNaN(Date.parse(value))) {
28585
+ throw invalidResponse(`The service returned an invalid ${field}`);
28586
+ }
28587
+ return value;
28588
+ }
28589
+ var MobiusArtifactUploadRequest = class {
28590
+ byteLength;
28591
+ mediaType;
28592
+ name;
28593
+ sha256;
28594
+ constructor(name, mediaType, byteLength, sha256) {
28595
+ 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)) {
28596
+ throw new MobiusValidationError("The artifact upload request is invalid");
28278
28597
  }
28279
- };
28280
- label = (path2) => {
28281
- const suffix = relative4(homedir2(), path2);
28282
- return suffix === "" ? "~" : !isAbsolute8(suffix) && suffix !== ".." && !suffix.startsWith(`..${process.platform === "win32" ? "\\" : "/"}`) ? `~/${suffix.replaceAll("\\", "/")}` : path2;
28283
- };
28284
- identify = async (bindingId, requestedPath, signal) => {
28285
- this.authorizeMachine(bindingId);
28286
- const path2 = await this.resolvePath(requestedPath, signal);
28287
- return {
28288
- path: path2,
28289
- directoryId: encodePath(path2),
28290
- name: basename2(path2) || path2,
28291
- label: this.label(path2)
28598
+ this.byteLength = byteLength;
28599
+ this.mediaType = mediaType;
28600
+ this.name = name;
28601
+ this.sha256 = sha256;
28602
+ }
28603
+ };
28604
+ var MobiusArtifact = class {
28605
+ artifactId;
28606
+ byteLength;
28607
+ createdAt;
28608
+ mediaType;
28609
+ name;
28610
+ sessionId;
28611
+ sha256;
28612
+ constructor(sessionId, artifactId, name, mediaType, byteLength, sha256, createdAt) {
28613
+ this.artifactId = artifactId;
28614
+ this.byteLength = byteLength;
28615
+ this.createdAt = createdAt;
28616
+ this.mediaType = mediaType;
28617
+ this.name = name;
28618
+ this.sessionId = sessionId;
28619
+ this.sha256 = sha256;
28620
+ }
28621
+ };
28622
+ var MobiusUploadingArtifact = class extends MobiusArtifact {
28623
+ expiresAt;
28624
+ state = "uploading";
28625
+ constructor(sessionId, artifactId, name, mediaType, byteLength, sha256, createdAt, expiresAt) {
28626
+ super(sessionId, artifactId, name, mediaType, byteLength, sha256, createdAt);
28627
+ this.expiresAt = expiresAt;
28628
+ }
28629
+ };
28630
+ var MobiusArtifactUpload = class extends MobiusUploadingArtifact {
28631
+ uploadToken;
28632
+ constructor(artifact, uploadToken) {
28633
+ super(
28634
+ artifact.sessionId,
28635
+ artifact.artifactId,
28636
+ artifact.name,
28637
+ artifact.mediaType,
28638
+ artifact.byteLength,
28639
+ artifact.sha256,
28640
+ artifact.createdAt,
28641
+ artifact.expiresAt
28642
+ );
28643
+ this.uploadToken = uploadToken;
28644
+ }
28645
+ };
28646
+ var MobiusAvailableArtifact = class extends MobiusArtifact {
28647
+ availableAt;
28648
+ state = "available";
28649
+ constructor(sessionId, artifactId, name, mediaType, byteLength, sha256, createdAt, availableAt) {
28650
+ super(sessionId, artifactId, name, mediaType, byteLength, sha256, createdAt);
28651
+ this.availableAt = availableAt;
28652
+ }
28653
+ };
28654
+ var MobiusExpiredArtifact = class extends MobiusArtifact {
28655
+ expiredAt;
28656
+ state = "expired";
28657
+ constructor(sessionId, artifactId, name, mediaType, byteLength, sha256, createdAt, expiredAt) {
28658
+ super(sessionId, artifactId, name, mediaType, byteLength, sha256, createdAt);
28659
+ this.expiredAt = expiredAt;
28660
+ }
28661
+ };
28662
+ function artifactFields(value) {
28663
+ const sha256 = stringField(value, "sha256", 64);
28664
+ if (!/^[a-f0-9]{64}$/.test(sha256)) {
28665
+ throw invalidResponse("The service returned an invalid artifact digest");
28666
+ }
28667
+ return {
28668
+ artifactId: identifierField(value, "artifactId"),
28669
+ byteLength: integerField(value, "byteLength"),
28670
+ createdAt: validateTimestamp(stringField(value, "createdAt", 128), "createdAt"),
28671
+ mediaType: stringField(value, "mediaType", 255),
28672
+ name: stringField(value, "name", 500),
28673
+ sessionId: identifierField(value, "sessionId"),
28674
+ sha256
28675
+ };
28676
+ }
28677
+ function uploadingArtifact(value) {
28678
+ const fields = artifactFields(value);
28679
+ return new MobiusUploadingArtifact(
28680
+ fields.sessionId,
28681
+ fields.artifactId,
28682
+ fields.name,
28683
+ fields.mediaType,
28684
+ fields.byteLength,
28685
+ fields.sha256,
28686
+ fields.createdAt,
28687
+ validateTimestamp(stringField(value, "expiresAt", 128), "expiresAt")
28688
+ );
28689
+ }
28690
+ function decodeMobiusArtifactUpload(value) {
28691
+ const artifact = record2(value, "artifact upload authorization");
28692
+ return new MobiusArtifactUpload(uploadingArtifact(artifact), stringField(artifact, "uploadToken", 256));
28693
+ }
28694
+ function decodeMobiusArtifact(value) {
28695
+ const artifact = record2(value, "artifact");
28696
+ const state = stringField(artifact, "state", 32);
28697
+ if (state === "uploading") {
28698
+ return uploadingArtifact(artifact);
28699
+ }
28700
+ const fields = artifactFields(artifact);
28701
+ if (state === "available") {
28702
+ return new MobiusAvailableArtifact(
28703
+ fields.sessionId,
28704
+ fields.artifactId,
28705
+ fields.name,
28706
+ fields.mediaType,
28707
+ fields.byteLength,
28708
+ fields.sha256,
28709
+ fields.createdAt,
28710
+ validateTimestamp(stringField(artifact, "availableAt", 128), "availableAt")
28711
+ );
28712
+ }
28713
+ if (state === "expired") {
28714
+ return new MobiusExpiredArtifact(
28715
+ fields.sessionId,
28716
+ fields.artifactId,
28717
+ fields.name,
28718
+ fields.mediaType,
28719
+ fields.byteLength,
28720
+ fields.sha256,
28721
+ fields.createdAt,
28722
+ validateTimestamp(stringField(artifact, "expiredAt", 128), "expiredAt")
28723
+ );
28724
+ }
28725
+ throw invalidResponse("The service returned an invalid artifact state");
28726
+ }
28727
+ function decodeMobiusAvailableArtifact(value) {
28728
+ const artifact = decodeMobiusArtifact(value);
28729
+ if (!(artifact instanceof MobiusAvailableArtifact)) {
28730
+ throw invalidResponse("The service did not make the artifact available");
28731
+ }
28732
+ return artifact;
28733
+ }
28734
+ var MobiusRuntimePairingLifecycle = Object.freeze({
28735
+ Expired: "expired",
28736
+ Paired: "paired",
28737
+ Pending: "pending",
28738
+ Revoked: "revoked"
28739
+ });
28740
+
28741
+ // src/artifacts/runtime-artifact-uploader.ts
28742
+ import { fetch as fetch5 } from "undici";
28743
+ var UPLOAD_TIMEOUT_MILLISECONDS = 2e4;
28744
+ var RuntimeArtifactUploadError = class extends Error {
28745
+ code;
28746
+ constructor(code, message, options = {}) {
28747
+ super(message, options);
28748
+ this.code = code;
28749
+ this.name = "RuntimeArtifactUploadError";
28750
+ }
28751
+ };
28752
+ var UploadedRuntimeArtifact = class {
28753
+ artifactId;
28754
+ byteLength;
28755
+ mimeType;
28756
+ name;
28757
+ sha256;
28758
+ constructor(artifactId, name, mimeType, byteLength, sha256) {
28759
+ this.artifactId = artifactId;
28760
+ this.byteLength = byteLength;
28761
+ this.mimeType = mimeType;
28762
+ this.name = name;
28763
+ this.sha256 = sha256;
28764
+ }
28765
+ };
28766
+ function daemonToken2(config2) {
28767
+ const token = config2.relayUrl.searchParams.get("token");
28768
+ if (token === null || token.length < 32) {
28769
+ throw new RuntimeArtifactUploadError("artifact_endpoint_invalid", "The Relay daemon token is missing");
28770
+ }
28771
+ return token;
28772
+ }
28773
+ function channelOrigin(config2) {
28774
+ const url2 = new URL(config2.relayUrl);
28775
+ url2.protocol = url2.protocol === "wss:" ? "https:" : "http:";
28776
+ let channelPath = "";
28777
+ if (url2.pathname.endsWith("/daemon")) {
28778
+ channelPath = url2.pathname.slice(0, -"/daemon".length);
28779
+ } else {
28780
+ const runtimePath = `${MOBIUS_API_PREFIX}/v1/runtimes/connect`;
28781
+ if (!url2.pathname.endsWith("/v1/runtimes/connect") && !url2.pathname.endsWith(runtimePath)) {
28782
+ throw new RuntimeArtifactUploadError("artifact_endpoint_invalid", "The Relay artifact endpoint is invalid");
28783
+ }
28784
+ channelPath = `${url2.pathname.replace(/\/v1\/runtimes\/connect$/, "")}/channels/${encodeURIComponent(config2.channelId)}`;
28785
+ }
28786
+ url2.pathname = channelPath;
28787
+ url2.search = "";
28788
+ url2.hash = "";
28789
+ return url2;
28790
+ }
28791
+ function uploadError(code, message, cause) {
28792
+ return new RuntimeArtifactUploadError(code, message, cause === void 0 ? {} : { cause });
28793
+ }
28794
+ function translateSdkError(cause) {
28795
+ if (cause instanceof MobiusValidationError) {
28796
+ throw uploadError("artifact_upload_failed", cause.message, cause);
28797
+ }
28798
+ if (cause instanceof MobiusProtocolError) {
28799
+ throw uploadError("artifact_upload_failed", "The Relay returned an invalid upload response", cause);
28800
+ }
28801
+ throw cause;
28802
+ }
28803
+ async function readJson(response) {
28804
+ try {
28805
+ return await response.json();
28806
+ } catch (cause) {
28807
+ throw uploadError("artifact_upload_failed", "The Relay returned an invalid upload response", cause);
28808
+ }
28809
+ }
28810
+ async function readAuthorization(response) {
28811
+ try {
28812
+ return decodeMobiusArtifactUpload(await readJson(response));
28813
+ } catch (cause) {
28814
+ translateSdkError(cause);
28815
+ }
28816
+ }
28817
+ function sessionArtifactUrl(origin, sessionId, resourcePath, token) {
28818
+ const url2 = new URL(`${origin.pathname}/sessions/${encodeURIComponent(sessionId)}/${resourcePath}`, origin);
28819
+ url2.searchParams.set("token", token);
28820
+ return url2;
28821
+ }
28822
+ async function postLease(url2, request, signal) {
28823
+ return await fetch5(url2, {
28824
+ dispatcher: environmentProxyDispatcher,
28825
+ headers: { "content-type": "application/json" },
28826
+ method: "POST",
28827
+ body: JSON.stringify(request),
28828
+ signal
28829
+ });
28830
+ }
28831
+ async function putContent(url2, authorization, bytes, signal) {
28832
+ return await fetch5(url2, {
28833
+ dispatcher: environmentProxyDispatcher,
28834
+ headers: {
28835
+ "content-type": authorization.mediaType,
28836
+ "x-mobius-upload-token": authorization.uploadToken
28837
+ },
28838
+ method: "PUT",
28839
+ body: bytes,
28840
+ signal
28841
+ });
28842
+ }
28843
+ async function uploadRuntimeArtifact(config2, sessionId, image, signal) {
28844
+ signal.throwIfAborted();
28845
+ let request;
28846
+ try {
28847
+ request = new MobiusArtifactUploadRequest(
28848
+ image.name,
28849
+ image.mimeType,
28850
+ image.bytes.byteLength,
28851
+ createHash3("sha256").update(image.bytes).digest("hex")
28852
+ );
28853
+ } catch (cause) {
28854
+ translateSdkError(cause);
28855
+ }
28856
+ const timeoutSignal = AbortSignal.timeout(UPLOAD_TIMEOUT_MILLISECONDS);
28857
+ const requestSignal = AbortSignal.any([signal, timeoutSignal]);
28858
+ const origin = channelOrigin(config2);
28859
+ const token = daemonToken2(config2);
28860
+ let created;
28861
+ try {
28862
+ created = await postLease(
28863
+ sessionArtifactUrl(origin, sessionId, "artifacts/uploads", token),
28864
+ request,
28865
+ requestSignal
28866
+ );
28867
+ } catch (cause) {
28868
+ signal.throwIfAborted();
28869
+ throw uploadError(
28870
+ timeoutSignal.aborted ? "artifact_upload_timeout" : "artifact_upload_failed",
28871
+ timeoutSignal.aborted ? "The artifact upload authorization timed out" : "The artifact upload could not start",
28872
+ cause
28873
+ );
28874
+ }
28875
+ if (!created.ok) {
28876
+ await created.body?.cancel();
28877
+ throw uploadError("artifact_upload_rejected", "The Relay rejected the artifact upload");
28878
+ }
28879
+ const authorization = await readAuthorization(created);
28880
+ let uploaded;
28881
+ try {
28882
+ uploaded = await putContent(
28883
+ sessionArtifactUrl(
28884
+ origin,
28885
+ sessionId,
28886
+ `artifacts/${encodeURIComponent(authorization.artifactId)}/content`,
28887
+ token
28888
+ ),
28889
+ authorization,
28890
+ image.bytes,
28891
+ requestSignal
28892
+ );
28893
+ } catch (cause) {
28894
+ signal.throwIfAborted();
28895
+ throw uploadError(
28896
+ timeoutSignal.aborted ? "artifact_upload_timeout" : "artifact_upload_failed",
28897
+ timeoutSignal.aborted ? "The artifact upload timed out" : "The artifact content could not be uploaded",
28898
+ cause
28899
+ );
28900
+ }
28901
+ if (!uploaded.ok) {
28902
+ await uploaded.body?.cancel();
28903
+ throw uploadError("artifact_upload_rejected", "The Relay rejected the artifact content");
28904
+ }
28905
+ try {
28906
+ const available = decodeMobiusAvailableArtifact(await readJson(uploaded));
28907
+ return new UploadedRuntimeArtifact(
28908
+ available.artifactId,
28909
+ available.name,
28910
+ available.mediaType,
28911
+ available.byteLength,
28912
+ available.sha256
28913
+ );
28914
+ } catch (cause) {
28915
+ translateSdkError(cause);
28916
+ }
28917
+ }
28918
+
28919
+ // src/authorization/workspace-directory.ts
28920
+ import { readdir, realpath as realpath8, stat as stat8 } from "node:fs/promises";
28921
+ import { homedir as homedir2 } from "node:os";
28922
+ import { basename as basename3, dirname as dirname6, isAbsolute as isAbsolute9, join as join15, normalize as normalize3, relative as relative5 } from "node:path";
28923
+ var WorkspaceDirectoryListing = class {
28924
+ directoryId;
28925
+ directoryLabel;
28926
+ entries;
28927
+ parentDirectoryId;
28928
+ constructor(directoryId2, directoryLabel, entries, parentDirectoryId) {
28929
+ this.directoryId = directoryId2;
28930
+ this.directoryLabel = directoryLabel;
28931
+ this.entries = entries;
28932
+ this.parentDirectoryId = parentDirectoryId;
28933
+ }
28934
+ };
28935
+ function encodePath(path2) {
28936
+ const encoded = Buffer.from(path2, "utf8").toString("base64url");
28937
+ if (encoded.length === 0 || encoded.length > 2e3) {
28938
+ throw new LocalAuthorizationError("The local directory path is too long to select");
28939
+ }
28940
+ return `path-${encoded}`;
28941
+ }
28942
+ function decodePath(value, prefix) {
28943
+ const encoded = value.slice(prefix.length);
28944
+ if (encoded.length === 0 || encoded.length > 2e3 || !/^[a-zA-Z0-9_-]+$/.test(encoded)) {
28945
+ throw new LocalAuthorizationError("The directory identifier is invalid");
28946
+ }
28947
+ const decoded = Buffer.from(encoded, "base64url").toString("utf8");
28948
+ if (Buffer.from(decoded, "utf8").toString("base64url") !== encoded || decoded.includes("\0") || normalize3(decoded) !== decoded) {
28949
+ throw new LocalAuthorizationError("The directory identifier is invalid");
28950
+ }
28951
+ return decoded;
28952
+ }
28953
+ var WorkspaceDirectoryService = class {
28954
+ #bindingId;
28955
+ #defaultWorkspace;
28956
+ constructor(bindingId, defaultWorkspace) {
28957
+ this.#bindingId = bindingId;
28958
+ this.#defaultWorkspace = defaultWorkspace;
28959
+ }
28960
+ authorizeMachine = (bindingId) => {
28961
+ if (bindingId !== this.#bindingId) {
28962
+ throw new LocalAuthorizationError("The runtime binding is not authorized");
28963
+ }
28964
+ };
28965
+ requestedPath = (id) => {
28966
+ if (id === "default") {
28967
+ return this.#defaultWorkspace;
28968
+ }
28969
+ if (id === "home") {
28970
+ return homedir2();
28971
+ }
28972
+ if (id.startsWith("path-")) {
28973
+ const path2 = decodePath(id, "path-");
28974
+ if (isAbsolute9(path2)) {
28975
+ return path2;
28976
+ }
28977
+ }
28978
+ throw new LocalAuthorizationError("The directory identifier is invalid");
28979
+ };
28980
+ resolvePath = async (requested, signal) => {
28981
+ signal.throwIfAborted();
28982
+ if (!isAbsolute9(requested) || requested.includes("\0") || normalize3(requested) !== requested) {
28983
+ throw new LocalAuthorizationError("The local directory path is invalid");
28984
+ }
28985
+ try {
28986
+ const target = await realpath8(requested);
28987
+ signal.throwIfAborted();
28988
+ const metadata = await stat8(target);
28989
+ signal.throwIfAborted();
28990
+ if (!isAbsolute9(target) || normalize3(target) !== target || !metadata.isDirectory()) {
28991
+ throw new LocalAuthorizationError("The selected location is not a directory");
28992
+ }
28993
+ return target;
28994
+ } catch (cause) {
28995
+ signal.throwIfAborted();
28996
+ if (cause instanceof LocalAuthorizationError) {
28997
+ throw cause;
28998
+ }
28999
+ throw new LocalAuthorizationError("This directory is missing or unavailable to your user account", {
29000
+ cause
29001
+ });
29002
+ }
29003
+ };
29004
+ label = (path2) => {
29005
+ const suffix = relative5(homedir2(), path2);
29006
+ return suffix === "" ? "~" : !isAbsolute9(suffix) && suffix !== ".." && !suffix.startsWith(`..${process.platform === "win32" ? "\\" : "/"}`) ? `~/${suffix.replaceAll("\\", "/")}` : path2;
29007
+ };
29008
+ identify = async (bindingId, requestedPath, signal) => {
29009
+ this.authorizeMachine(bindingId);
29010
+ const path2 = await this.resolvePath(requestedPath, signal);
29011
+ return {
29012
+ path: path2,
29013
+ directoryId: encodePath(path2),
29014
+ name: basename3(path2) || path2,
29015
+ label: this.label(path2)
28292
29016
  };
28293
29017
  };
28294
29018
  resolve = async (bindingId, id, signal) => {
@@ -28381,7 +29105,7 @@ var EmbeddedBotContextApplicator = class {
28381
29105
 
28382
29106
  // src/native-sessions/service.ts
28383
29107
  import { randomUUID as randomUUID4 } from "node:crypto";
28384
- import { basename as basename3 } from "node:path";
29108
+ import { basename as basename4 } from "node:path";
28385
29109
 
28386
29110
  // src/native-sessions/codex-history.ts
28387
29111
  import { spawn as spawn4 } from "node:child_process";
@@ -28414,7 +29138,6 @@ function decodeHistory(thread, value) {
28414
29138
  const page = turnsSchema.parse(value);
28415
29139
  const messages = [];
28416
29140
  let characters = 0;
28417
- let imageCharacters = 0;
28418
29141
  let truncated = page.nextCursor != null;
28419
29142
  for (const turn of page.data.toReversed()) {
28420
29143
  for (const item of turn.items) {
@@ -28422,22 +29145,19 @@ function decodeHistory(thread, value) {
28422
29145
  let message;
28423
29146
  if (type === "userMessage") {
28424
29147
  const { content } = userMessageSchema.parse(item);
28425
- const parsed = parseNativeHistoryText(
28426
- content.map((block) => {
28427
- const { type: type2 } = itemTypeSchema.parse(block);
28428
- if (type2 === "text") {
28429
- return textSchema.parse(block).text;
28430
- }
28431
- if (type2 === "image") {
28432
- return `[@image](${imageSchema.parse(block).url})`;
28433
- }
28434
- return "[Attachment]";
28435
- }).join("")
28436
- );
29148
+ const text2 = content.map((block) => {
29149
+ const { type: type2 } = itemTypeSchema.parse(block);
29150
+ if (type2 === "text") {
29151
+ return textSchema.parse(block).text;
29152
+ }
29153
+ if (type2 === "image") {
29154
+ return `[@image](${imageSchema.parse(block).url})`;
29155
+ }
29156
+ return "[Attachment]";
29157
+ }).join("");
28437
29158
  message = {
28438
29159
  role: "user",
28439
- text: parsed.text,
28440
- ...parsed.images.length > 0 ? { images: parsed.images } : {}
29160
+ text: text2
28441
29161
  };
28442
29162
  } else if (type === "agentMessage") {
28443
29163
  const agent = agentMessageSchema.parse(item);
@@ -28455,12 +29175,10 @@ function decodeHistory(thread, value) {
28455
29175
  truncated ||= text.length < message.text.length;
28456
29176
  messages.push({ ...message, text });
28457
29177
  characters += text.length;
28458
- imageCharacters += (message.images ?? []).reduce((size, image) => size + image.data.length, 0);
28459
- while (messages.length > SESSION_HISTORY_PREVIEW_MESSAGE_LIMIT || characters > SESSION_HISTORY_CHARACTER_LIMIT || imageCharacters > SESSION_HISTORY_IMAGE_CHARACTER_LIMIT) {
29178
+ while (messages.length > SESSION_HISTORY_PREVIEW_MESSAGE_LIMIT || characters > SESSION_HISTORY_CHARACTER_LIMIT) {
28460
29179
  const removed = messages.shift();
28461
29180
  if (removed !== void 0) {
28462
29181
  characters -= removed.text.length;
28463
- imageCharacters -= (removed.images ?? []).reduce((size, image) => size + image.data.length, 0);
28464
29182
  }
28465
29183
  truncated = true;
28466
29184
  }
@@ -28618,7 +29336,11 @@ async function readCodexHistory(agent, cwd, nativeSessionId, signal) {
28618
29336
  params: { clientInfo: { name: "mobius_history", version: "1.0.0" } }
28619
29337
  });
28620
29338
  }
28621
- return await response.promise;
29339
+ const snapshot = await response.promise;
29340
+ return {
29341
+ ...snapshot,
29342
+ history: await embedLocalHistoryImages(snapshot.history, [cwd, snapshot.cwd], signal)
29343
+ };
28622
29344
  } finally {
28623
29345
  clearTimeout(timeout);
28624
29346
  signal.removeEventListener("abort", abort);
@@ -28872,7 +29594,7 @@ var NativeSessionService = class {
28872
29594
  }
28873
29595
  resolvedPaths.add(path2);
28874
29596
  additionalDirectories.push(path2);
28875
- additionalEntries.push({ directoryId: directoryId2, name: basename3(path2) });
29597
+ additionalEntries.push({ directoryId: directoryId2, name: basename4(path2) });
28876
29598
  }
28877
29599
  const listing = await this.#directories.list(this.#config.bindingId, command.directoryId, signal);
28878
29600
  const opened = await this.#sessions.forkSessionAtTurn(
@@ -29011,13 +29733,13 @@ var NativeSessionService = class {
29011
29733
  };
29012
29734
 
29013
29735
  // src/prompt-artifact-resolver.ts
29014
- import { createHash as createHash3 } from "node:crypto";
29015
- import { fetch as fetch5 } from "undici";
29736
+ import { createHash as createHash4 } from "node:crypto";
29737
+ import { fetch as fetch6 } from "undici";
29016
29738
  var ARTIFACT_SCHEME = "mobius-artifact:";
29017
29739
  var ARTIFACT_DOWNLOAD_TIMEOUT_MILLISECONDS = 2e4;
29018
29740
  var MAX_AGENT_IMAGE_BASE64_LENGTH = 4e6;
29019
29741
  var MAX_AGENT_RESOURCE_BYTE_LENGTH = 1e6;
29020
- var IDENTIFIER_PATTERN7 = /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/;
29742
+ var IDENTIFIER_PATTERN8 = /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/;
29021
29743
  var PromptArtifactError = class extends Error {
29022
29744
  code;
29023
29745
  constructor(code, message, options = {}) {
@@ -29060,14 +29782,13 @@ function parseReference(resource) {
29060
29782
  const encodedByteLength2 = url2.searchParams.get("byteLength") ?? "";
29061
29783
  const sha256 = url2.searchParams.get("sha256") ?? "";
29062
29784
  const byteLength = Number(encodedByteLength2);
29063
- 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)) {
29785
+ if (url2.protocol !== ARTIFACT_SCHEME || url2.hash.length > 0 || resource.type !== "link" || resource.text.length > 0 || !IDENTIFIER_PATTERN8.test(artifactId) || keys.length !== 2 || keys[0] !== "byteLength" || keys[1] !== "sha256" || !/^[1-9][0-9]*$/.test(encodedByteLength2) || !Number.isSafeInteger(byteLength) || !/^[a-f0-9]{64}$/.test(sha256)) {
29064
29786
  throw new PromptArtifactError("artifact_reference_invalid", "The prompt artifact reference is invalid");
29065
29787
  }
29066
29788
  return new PromptArtifactReference(artifactId, byteLength, sha256, resource);
29067
29789
  }
29068
29790
  function downloadUrl(config2, command, reference) {
29069
- const url2 = new URL(config2.relayUrl);
29070
- url2.protocol = url2.protocol === "wss:" ? "https:" : "http:";
29791
+ const url2 = relayHttpEndpoint(config2.relayUrl);
29071
29792
  let channelPath = "";
29072
29793
  if (url2.pathname.endsWith("/daemon")) {
29073
29794
  channelPath = url2.pathname.slice(0, -"/daemon".length);
@@ -29079,7 +29800,6 @@ function downloadUrl(config2, command, reference) {
29079
29800
  channelPath = `${url2.pathname.slice(0, -runtimePath.length)}/channels/${encodeURIComponent(config2.channelId)}`;
29080
29801
  }
29081
29802
  url2.pathname = `${channelPath}/sessions/${encodeURIComponent(command.sessionId)}/commands/${encodeURIComponent(command.commandId)}/artifacts/${encodeURIComponent(reference.artifactId)}/content`;
29082
- url2.searchParams.delete("liveness");
29083
29803
  return url2;
29084
29804
  }
29085
29805
  async function responseBytes(response, expectedByteLength, signal) {
@@ -29128,9 +29848,13 @@ async function download(config2, command, reference, signal) {
29128
29848
  const requestSignal = AbortSignal.any([signal, timeoutSignal]);
29129
29849
  let response;
29130
29850
  try {
29131
- response = await fetch5(downloadUrl(config2, command, reference), {
29851
+ response = await fetch6(downloadUrl(config2, command, reference), {
29132
29852
  dispatcher: environmentProxyDispatcher,
29133
- headers: { accept: reference.resource.mimeType },
29853
+ headers: {
29854
+ accept: reference.resource.mimeType,
29855
+ "accept-encoding": "identity",
29856
+ ...runtimeAuthorization(config2.relayUrl)
29857
+ },
29134
29858
  signal: requestSignal
29135
29859
  });
29136
29860
  if (!response.ok) {
@@ -29148,7 +29872,7 @@ async function download(config2, command, reference, signal) {
29148
29872
  );
29149
29873
  }
29150
29874
  const bytes = await responseBytes(response, reference.byteLength, requestSignal);
29151
- if (createHash3("sha256").update(bytes).digest("hex") !== reference.sha256) {
29875
+ if (createHash4("sha256").update(bytes).digest("hex") !== reference.sha256) {
29152
29876
  throw new PromptArtifactError(
29153
29877
  "artifact_integrity_failed",
29154
29878
  "The prompt artifact failed integrity validation"
@@ -29240,12 +29964,8 @@ function connectRelay(url2, signal) {
29240
29964
  signal.throwIfAborted();
29241
29965
  return new Promise((resolve6, reject) => {
29242
29966
  const endpoint = new URL(url2);
29243
- const headers = {};
29244
- if (endpoint.pathname.endsWith("/v1/runtimes/connect")) {
29245
- const runtimeCredential = endpoint.searchParams.get("token") ?? "";
29246
- endpoint.searchParams.delete("token");
29247
- headers["authorization"] = `Bearer ${runtimeCredential}`;
29248
- }
29967
+ const headers = runtimeAuthorization(endpoint);
29968
+ endpoint.searchParams.delete("token");
29249
29969
  const socket = new WebSocket(endpoint, {
29250
29970
  dispatcher: environmentProxyDispatcher,
29251
29971
  headers
@@ -29568,6 +30288,42 @@ var RelayConnectionLiveness = class {
29568
30288
  import { mkdirSync as mkdirSync3 } from "node:fs";
29569
30289
  import { dirname as dirname7 } from "node:path";
29570
30290
  import { DatabaseSync as DatabaseSync4 } from "node:sqlite";
30291
+ var DEFAULT_OUTBOX_LIMITS = {
30292
+ criticalEventBytes: 136 * 1024 * 1024,
30293
+ criticalEventCount: 10128,
30294
+ runtimeDeliveryBytes: 64 * 1024 * 1024,
30295
+ runtimeDeliveryCount: 64,
30296
+ standardEventBytes: 128 * 1024 * 1024,
30297
+ standardEventCount: 1e4
30298
+ };
30299
+ var SessionEventOutboxCapacityError = class extends Error {
30300
+ code = "session_event_outbox_full";
30301
+ constructor() {
30302
+ super("The durable Session event outbox is full");
30303
+ this.name = "SessionEventOutboxCapacityError";
30304
+ }
30305
+ };
30306
+ var RuntimeDeliveryInboxCapacityError = class extends Error {
30307
+ code = "runtime_delivery_inbox_full";
30308
+ constructor() {
30309
+ super("The durable Runtime delivery inbox is full");
30310
+ this.name = "RuntimeDeliveryInboxCapacityError";
30311
+ }
30312
+ };
30313
+ var StoredRuntimeDelivery = class {
30314
+ deliveryId;
30315
+ duplicate;
30316
+ payload;
30317
+ sessionId;
30318
+ state;
30319
+ constructor(deliveryId, sessionId, payload, state, duplicate) {
30320
+ this.deliveryId = deliveryId;
30321
+ this.duplicate = duplicate;
30322
+ this.payload = payload;
30323
+ this.sessionId = sessionId;
30324
+ this.state = state;
30325
+ }
30326
+ };
29571
30327
  function readPendingEnvelope(row) {
29572
30328
  if (typeof row !== "object" || row === null || Array.isArray(row)) {
29573
30329
  throw new Error("SQLite returned an invalid session event outbox row");
@@ -29578,9 +30334,26 @@ function readPendingEnvelope(row) {
29578
30334
  }
29579
30335
  return envelope2;
29580
30336
  }
30337
+ function rowNumber(row, field) {
30338
+ const value = typeof row === "object" && row !== null ? Reflect.get(row, field) : void 0;
30339
+ if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0) {
30340
+ throw new Error(`SQLite returned an invalid ${field} value`);
30341
+ }
30342
+ return value;
30343
+ }
30344
+ function rowString2(row, field) {
30345
+ const value = typeof row === "object" && row !== null ? Reflect.get(row, field) : void 0;
30346
+ if (typeof value !== "string" || value.length === 0) {
30347
+ throw new Error(`SQLite returned an invalid ${field} value`);
30348
+ }
30349
+ return value;
30350
+ }
29581
30351
  var SessionEventOutbox = class {
29582
30352
  #database;
29583
- constructor(path2) {
30353
+ #limits;
30354
+ constructor(path2, limits = DEFAULT_OUTBOX_LIMITS) {
30355
+ validateLimits(limits);
30356
+ this.#limits = limits;
29584
30357
  mkdirSync3(dirname7(path2), { recursive: true });
29585
30358
  this.#database = new DatabaseSync4(path2);
29586
30359
  this.#database.exec(`
@@ -29589,6 +30362,7 @@ var SessionEventOutbox = class {
29589
30362
  event_id TEXT NOT NULL UNIQUE,
29590
30363
  session_id TEXT NOT NULL,
29591
30364
  source_key TEXT NOT NULL,
30365
+ byte_length INTEGER NOT NULL,
29592
30366
  envelope_json TEXT NOT NULL
29593
30367
  ) STRICT;
29594
30368
  CREATE INDEX IF NOT EXISTS relay_session_event_outbox_order
@@ -29599,7 +30373,7 @@ var SessionEventOutbox = class {
29599
30373
  session_id TEXT NOT NULL,
29600
30374
  envelope_json TEXT NOT NULL,
29601
30375
  rejection_code TEXT NOT NULL CHECK (
29602
- rejection_code IN ('session_deleted', 'session_not_found')
30376
+ rejection_code IN ('session_deleted', 'session_not_found', 'session_rejected')
29603
30377
  )
29604
30378
  ) STRICT;
29605
30379
  CREATE TABLE IF NOT EXISTS relay_session_event_sources (
@@ -29615,7 +30389,53 @@ var SessionEventOutbox = class {
29615
30389
  state IN ('dispatching', 'running', 'succeeded', 'failed', 'cancelled')
29616
30390
  )
29617
30391
  ) STRICT;
30392
+ CREATE TABLE IF NOT EXISTS relay_session_event_outbox_state (
30393
+ singleton INTEGER PRIMARY KEY CHECK (singleton = 1),
30394
+ event_count INTEGER NOT NULL,
30395
+ total_bytes INTEGER NOT NULL
30396
+ ) STRICT;
30397
+ INSERT OR IGNORE INTO relay_session_event_outbox_state (
30398
+ singleton, event_count, total_bytes
30399
+ ) VALUES (1, 0, 0);
30400
+ CREATE TABLE IF NOT EXISTS relay_runtime_deliveries (
30401
+ delivery_id TEXT PRIMARY KEY,
30402
+ session_id TEXT NOT NULL,
30403
+ payload_json TEXT NOT NULL,
30404
+ payload_bytes INTEGER NOT NULL,
30405
+ state TEXT NOT NULL CHECK (
30406
+ state IN ('received', 'relay_committed', 'processed')
30407
+ ),
30408
+ received_at INTEGER NOT NULL
30409
+ ) STRICT;
29618
30410
  `);
30411
+ const deadLetterTable = this.#database.prepare(
30412
+ `SELECT sql FROM sqlite_master
30413
+ WHERE type = 'table' AND name = 'relay_session_event_dead_letters'`
30414
+ ).get();
30415
+ const deadLetterSql = typeof deadLetterTable === "object" && deadLetterTable !== null ? Reflect.get(deadLetterTable, "sql") : void 0;
30416
+ if (typeof deadLetterSql !== "string" || !deadLetterSql.includes("'session_rejected'")) {
30417
+ this.#database.exec(`
30418
+ BEGIN IMMEDIATE;
30419
+ ALTER TABLE relay_session_event_dead_letters
30420
+ RENAME TO relay_session_event_dead_letters_legacy;
30421
+ CREATE TABLE relay_session_event_dead_letters (
30422
+ ordinal INTEGER PRIMARY KEY,
30423
+ event_id TEXT NOT NULL UNIQUE,
30424
+ session_id TEXT NOT NULL,
30425
+ envelope_json TEXT NOT NULL,
30426
+ rejection_code TEXT NOT NULL CHECK (
30427
+ rejection_code IN ('session_deleted', 'session_not_found', 'session_rejected')
30428
+ )
30429
+ ) STRICT;
30430
+ INSERT INTO relay_session_event_dead_letters (
30431
+ ordinal, event_id, session_id, envelope_json, rejection_code
30432
+ )
30433
+ SELECT ordinal, event_id, session_id, envelope_json, rejection_code
30434
+ FROM relay_session_event_dead_letters_legacy;
30435
+ DROP TABLE relay_session_event_dead_letters_legacy;
30436
+ COMMIT;
30437
+ `);
30438
+ }
29619
30439
  const outboxColumns = this.#database.prepare("PRAGMA table_info(relay_session_event_outbox)").all();
29620
30440
  const hasSourceKey = outboxColumns.some(
29621
30441
  (column) => typeof column === "object" && column !== null && Reflect.get(column, "name") === "source_key"
@@ -29626,6 +30446,15 @@ var SessionEventOutbox = class {
29626
30446
  ADD COLUMN source_key TEXT NOT NULL DEFAULT '';
29627
30447
  `);
29628
30448
  }
30449
+ const hasByteLength = outboxColumns.some(
30450
+ (column) => typeof column === "object" && column !== null && Reflect.get(column, "name") === "byte_length"
30451
+ );
30452
+ if (!hasByteLength) {
30453
+ this.#database.exec(`
30454
+ ALTER TABLE relay_session_event_outbox
30455
+ ADD COLUMN byte_length INTEGER NOT NULL DEFAULT 0;
30456
+ `);
30457
+ }
29629
30458
  this.#database.exec(`
29630
30459
  UPDATE relay_session_event_outbox
29631
30460
  SET source_key = CASE json_extract(envelope_json, '$.source.kind')
@@ -29634,6 +30463,16 @@ var SessionEventOutbox = class {
29634
30463
  ELSE 'runtime:' || session_id
29635
30464
  END
29636
30465
  WHERE source_key = '';
30466
+ UPDATE relay_session_event_outbox
30467
+ SET byte_length = length(CAST(envelope_json AS BLOB))
30468
+ WHERE byte_length = 0;
30469
+ UPDATE relay_session_event_outbox_state
30470
+ SET event_count = (SELECT COUNT(*) FROM relay_session_event_outbox),
30471
+ total_bytes = (
30472
+ SELECT COALESCE(SUM(byte_length), 0)
30473
+ FROM relay_session_event_outbox
30474
+ )
30475
+ WHERE singleton = 1;
29637
30476
  CREATE INDEX IF NOT EXISTS relay_session_event_outbox_source_order
29638
30477
  ON relay_session_event_outbox(source_key, ordinal);
29639
30478
  `);
@@ -29694,13 +30533,19 @@ var SessionEventOutbox = class {
29694
30533
  const state = typeof row === "object" && row !== null ? Reflect.get(row, "state") : void 0;
29695
30534
  return state === "succeeded" || state === "failed" || state === "cancelled";
29696
30535
  };
29697
- acknowledge = (acknowledgement) => this.#database.prepare(
29698
- `DELETE FROM relay_session_event_outbox
29699
- WHERE event_id = ? AND session_id = ?`
29700
- ).run(acknowledgement.eventId, acknowledgement.sessionId).changes === 1;
30536
+ acknowledge = (acknowledgement) => this.#removeAcknowledgedEvent(acknowledgement.eventId, acknowledgement.sessionId);
29701
30537
  quarantine = (rejection) => {
29702
30538
  this.#database.exec("BEGIN IMMEDIATE");
29703
30539
  try {
30540
+ const stored = this.#database.prepare(
30541
+ `SELECT byte_length FROM relay_session_event_outbox
30542
+ WHERE event_id = ? AND session_id = ?`
30543
+ ).get(rejection.eventId, rejection.sessionId);
30544
+ if (stored === void 0) {
30545
+ this.#database.exec("COMMIT");
30546
+ return false;
30547
+ }
30548
+ const byteLength = rowNumber(stored, "byte_length");
29704
30549
  const insertion = this.#database.prepare(
29705
30550
  `INSERT INTO relay_session_event_dead_letters (
29706
30551
  ordinal, event_id, session_id, envelope_json, rejection_code
@@ -29720,6 +30565,7 @@ var SessionEventOutbox = class {
29720
30565
  if (deletion.changes !== 1) {
29721
30566
  throw new Error("The rejected session event could not be removed from the durable outbox");
29722
30567
  }
30568
+ this.#decrementEventState(byteLength);
29723
30569
  this.#database.exec("COMMIT");
29724
30570
  return true;
29725
30571
  } catch (error61) {
@@ -29731,7 +30577,129 @@ var SessionEventOutbox = class {
29731
30577
  this.#database.close();
29732
30578
  };
29733
30579
  enqueue = (sessionId, payload, attemptId = null) => {
29734
- const sourceKey = attemptId === null ? `runtime:${sessionId}` : `attempt:${sessionId}:${attemptId}`;
30580
+ return this.#enqueueBounded(
30581
+ sessionId,
30582
+ payload,
30583
+ attemptId ?? "",
30584
+ this.#limits.standardEventCount,
30585
+ this.#limits.standardEventBytes
30586
+ );
30587
+ };
30588
+ enqueueCritical = (sessionId, payload, attemptId = "") => this.#enqueueBounded(
30589
+ sessionId,
30590
+ payload,
30591
+ attemptId,
30592
+ this.#limits.criticalEventCount,
30593
+ this.#limits.criticalEventBytes
30594
+ );
30595
+ claimRuntimeDelivery = (delivery) => {
30596
+ const payloadBytes = new TextEncoder().encode(delivery.payload).byteLength;
30597
+ this.#database.exec("BEGIN IMMEDIATE");
30598
+ try {
30599
+ const existing = this.#database.prepare(
30600
+ `SELECT session_id, payload_json, state
30601
+ FROM relay_runtime_deliveries
30602
+ WHERE delivery_id = ?`
30603
+ ).get(delivery.deliveryId);
30604
+ if (existing !== void 0) {
30605
+ const sessionId = rowString2(existing, "session_id");
30606
+ const payload = rowString2(existing, "payload_json");
30607
+ const state = runtimeDeliveryState(existing);
30608
+ if (sessionId !== delivery.sessionId || payload !== delivery.payload) {
30609
+ throw new Error("The Runtime delivery identity conflicts with its durable receipt");
30610
+ }
30611
+ this.#database.exec("COMMIT");
30612
+ return new StoredRuntimeDelivery(delivery.deliveryId, sessionId, payload, state, true);
30613
+ }
30614
+ const usage = this.#database.prepare(
30615
+ `SELECT COUNT(*) AS delivery_count,
30616
+ COALESCE(SUM(payload_bytes), 0) AS delivery_bytes
30617
+ FROM relay_runtime_deliveries`
30618
+ ).get();
30619
+ if (rowNumber(usage, "delivery_count") + 1 > this.#limits.runtimeDeliveryCount || rowNumber(usage, "delivery_bytes") + payloadBytes > this.#limits.runtimeDeliveryBytes) {
30620
+ throw new RuntimeDeliveryInboxCapacityError();
30621
+ }
30622
+ this.#database.prepare(
30623
+ `INSERT INTO relay_runtime_deliveries (
30624
+ delivery_id, session_id, payload_json, payload_bytes, state, received_at
30625
+ ) VALUES (?, ?, ?, ?, 'received', ?)`
30626
+ ).run(delivery.deliveryId, delivery.sessionId, delivery.payload, payloadBytes, Date.now());
30627
+ this.#database.exec("COMMIT");
30628
+ return new StoredRuntimeDelivery(
30629
+ delivery.deliveryId,
30630
+ delivery.sessionId,
30631
+ delivery.payload,
30632
+ "received",
30633
+ false
30634
+ );
30635
+ } catch (error61) {
30636
+ this.#database.exec("ROLLBACK");
30637
+ throw error61;
30638
+ }
30639
+ };
30640
+ markRuntimeDeliveryCommitted = (deliveryId, sessionId) => {
30641
+ this.#database.exec("BEGIN IMMEDIATE");
30642
+ try {
30643
+ const row = this.#database.prepare(
30644
+ `SELECT state FROM relay_runtime_deliveries
30645
+ WHERE delivery_id = ? AND session_id = ?`
30646
+ ).get(deliveryId, sessionId);
30647
+ if (row === void 0) {
30648
+ this.#database.exec("COMMIT");
30649
+ return false;
30650
+ }
30651
+ const state = runtimeDeliveryState(row);
30652
+ if (state === "processed") {
30653
+ this.#database.prepare(`DELETE FROM relay_runtime_deliveries WHERE delivery_id = ?`).run(deliveryId);
30654
+ } else if (state === "received") {
30655
+ this.#database.prepare(`UPDATE relay_runtime_deliveries SET state = 'relay_committed' WHERE delivery_id = ?`).run(deliveryId);
30656
+ }
30657
+ this.#database.exec("COMMIT");
30658
+ return true;
30659
+ } catch (error61) {
30660
+ this.#database.exec("ROLLBACK");
30661
+ throw error61;
30662
+ }
30663
+ };
30664
+ markRuntimeDeliveryProcessed = (deliveryId, sessionId) => {
30665
+ this.#database.exec("BEGIN IMMEDIATE");
30666
+ try {
30667
+ const row = this.#database.prepare(
30668
+ `SELECT state FROM relay_runtime_deliveries
30669
+ WHERE delivery_id = ? AND session_id = ?`
30670
+ ).get(deliveryId, sessionId);
30671
+ if (row === void 0) {
30672
+ this.#database.exec("COMMIT");
30673
+ return false;
30674
+ }
30675
+ const state = runtimeDeliveryState(row);
30676
+ if (state === "relay_committed") {
30677
+ this.#database.prepare(`DELETE FROM relay_runtime_deliveries WHERE delivery_id = ?`).run(deliveryId);
30678
+ } else if (state === "received") {
30679
+ this.#database.prepare(`UPDATE relay_runtime_deliveries SET state = 'processed' WHERE delivery_id = ?`).run(deliveryId);
30680
+ }
30681
+ this.#database.exec("COMMIT");
30682
+ return true;
30683
+ } catch (error61) {
30684
+ this.#database.exec("ROLLBACK");
30685
+ throw error61;
30686
+ }
30687
+ };
30688
+ runtimeDeliveries = () => this.#database.prepare(
30689
+ `SELECT delivery_id, session_id, payload_json, state
30690
+ FROM relay_runtime_deliveries
30691
+ ORDER BY received_at, delivery_id`
30692
+ ).all().map(
30693
+ (row) => new StoredRuntimeDelivery(
30694
+ rowString2(row, "delivery_id"),
30695
+ rowString2(row, "session_id"),
30696
+ rowString2(row, "payload_json"),
30697
+ runtimeDeliveryState(row),
30698
+ true
30699
+ )
30700
+ );
30701
+ #enqueueBounded = (sessionId, payload, attemptId, maximumEventCount, maximumEventBytes) => {
30702
+ const sourceKey = attemptId.length === 0 ? `runtime:${sessionId}` : `attempt:${sessionId}:${attemptId}`;
29735
30703
  this.#database.exec("BEGIN IMMEDIATE");
29736
30704
  try {
29737
30705
  const row = this.#database.prepare(
@@ -29748,13 +30716,22 @@ var SessionEventOutbox = class {
29748
30716
  kind: SESSION_EVENT_KIND,
29749
30717
  payload,
29750
30718
  sessionId,
29751
- source: attemptId === null ? { kind: "runtime", sourceSeq: nextSourceSeq.toString() } : {
30719
+ source: attemptId.length === 0 ? { kind: "runtime", sourceSeq: nextSourceSeq.toString() } : {
29752
30720
  attemptId,
29753
30721
  kind: "attempt",
29754
30722
  sourceSeq: nextSourceSeq.toString()
29755
30723
  }
29756
30724
  };
29757
30725
  const encoded = encodeSessionEventEnvelope(envelope2);
30726
+ const byteLength = new TextEncoder().encode(encoded).byteLength;
30727
+ const state = this.#database.prepare(
30728
+ `SELECT event_count, total_bytes
30729
+ FROM relay_session_event_outbox_state
30730
+ WHERE singleton = 1`
30731
+ ).get();
30732
+ if (rowNumber(state, "event_count") + 1 > maximumEventCount || rowNumber(state, "total_bytes") + byteLength > maximumEventBytes) {
30733
+ throw new SessionEventOutboxCapacityError();
30734
+ }
29758
30735
  this.#database.prepare(
29759
30736
  `INSERT INTO relay_session_event_sources (
29760
30737
  source_key, next_source_seq
@@ -29764,9 +30741,15 @@ var SessionEventOutbox = class {
29764
30741
  ).run(sourceKey, nextSourceSeq + 1);
29765
30742
  this.#database.prepare(
29766
30743
  `INSERT INTO relay_session_event_outbox (
29767
- event_id, session_id, source_key, envelope_json
29768
- ) VALUES (?, ?, ?, ?)`
29769
- ).run(envelope2.eventId, envelope2.sessionId, sourceKey, encoded);
30744
+ event_id, session_id, source_key, byte_length, envelope_json
30745
+ ) VALUES (?, ?, ?, ?, ?)`
30746
+ ).run(envelope2.eventId, envelope2.sessionId, sourceKey, byteLength, encoded);
30747
+ this.#database.prepare(
30748
+ `UPDATE relay_session_event_outbox_state
30749
+ SET event_count = event_count + 1,
30750
+ total_bytes = total_bytes + ?
30751
+ WHERE singleton = 1`
30752
+ ).run(byteLength);
29770
30753
  this.#database.exec("COMMIT");
29771
30754
  return encoded;
29772
30755
  } catch (error61) {
@@ -29774,6 +30757,44 @@ var SessionEventOutbox = class {
29774
30757
  throw error61;
29775
30758
  }
29776
30759
  };
30760
+ #removeAcknowledgedEvent = (eventId, sessionId) => {
30761
+ this.#database.exec("BEGIN IMMEDIATE");
30762
+ try {
30763
+ const stored = this.#database.prepare(
30764
+ `SELECT byte_length FROM relay_session_event_outbox
30765
+ WHERE event_id = ? AND session_id = ?`
30766
+ ).get(eventId, sessionId);
30767
+ if (stored === void 0) {
30768
+ this.#database.exec("COMMIT");
30769
+ return false;
30770
+ }
30771
+ const byteLength = rowNumber(stored, "byte_length");
30772
+ const deletion = this.#database.prepare(
30773
+ `DELETE FROM relay_session_event_outbox
30774
+ WHERE event_id = ? AND session_id = ?`
30775
+ ).run(eventId, sessionId);
30776
+ if (deletion.changes !== 1) {
30777
+ throw new Error("The acknowledged session event could not be removed from the durable outbox");
30778
+ }
30779
+ this.#decrementEventState(byteLength);
30780
+ this.#database.exec("COMMIT");
30781
+ return true;
30782
+ } catch (error61) {
30783
+ this.#database.exec("ROLLBACK");
30784
+ throw error61;
30785
+ }
30786
+ };
30787
+ #decrementEventState = (byteLength) => {
30788
+ const result = this.#database.prepare(
30789
+ `UPDATE relay_session_event_outbox_state
30790
+ SET event_count = event_count - 1,
30791
+ total_bytes = total_bytes - ?
30792
+ WHERE singleton = 1 AND event_count > 0 AND total_bytes >= ?`
30793
+ ).run(byteLength, byteLength);
30794
+ if (result.changes !== 1) {
30795
+ throw new Error("The Session event outbox capacity state is inconsistent");
30796
+ }
30797
+ };
29777
30798
  pending = () => this.#database.prepare(
29778
30799
  `SELECT envelope_json
29779
30800
  FROM relay_session_event_outbox
@@ -29800,7 +30821,68 @@ var SessionEventOutbox = class {
29800
30821
  LIMIT ?`
29801
30822
  ).all(limit).map(readPendingEnvelope);
29802
30823
  };
30824
+ pendingSourceHeads = (limit, excludedEventIds, excludedSourceKeys) => {
30825
+ if (!Number.isSafeInteger(limit) || limit < 1) {
30826
+ throw new Error("Session event replay batch limit must be a positive integer");
30827
+ }
30828
+ const exclusions = [];
30829
+ const parameters = [];
30830
+ if (excludedEventIds.length > 0) {
30831
+ exclusions.push(`event_id NOT IN (${excludedEventIds.map(() => "?").join(", ")})`);
30832
+ parameters.push(...excludedEventIds);
30833
+ }
30834
+ if (excludedSourceKeys.length > 0) {
30835
+ exclusions.push(`source_key NOT IN (${excludedSourceKeys.map(() => "?").join(", ")})`);
30836
+ parameters.push(...excludedSourceKeys);
30837
+ }
30838
+ parameters.push(limit.toString());
30839
+ const where = exclusions.length === 0 ? "" : `WHERE ${exclusions.join(" AND ")}`;
30840
+ return this.#database.prepare(
30841
+ `WITH available_events AS (
30842
+ SELECT ordinal, source_key
30843
+ FROM relay_session_event_outbox
30844
+ ${where}
30845
+ ), ranked_events AS (
30846
+ SELECT ordinal,
30847
+ ROW_NUMBER() OVER (
30848
+ PARTITION BY source_key
30849
+ ORDER BY ordinal
30850
+ ) AS source_position
30851
+ FROM available_events
30852
+ )
30853
+ SELECT outbox.envelope_json
30854
+ FROM ranked_events AS ranked
30855
+ INNER JOIN relay_session_event_outbox AS outbox
30856
+ ON outbox.ordinal = ranked.ordinal
30857
+ WHERE ranked.source_position = 1
30858
+ ORDER BY outbox.ordinal
30859
+ LIMIT ?`
30860
+ ).all(...parameters).map(readPendingEnvelope);
30861
+ };
29803
30862
  };
30863
+ function validateLimits(limits) {
30864
+ const values = [
30865
+ limits.criticalEventBytes,
30866
+ limits.criticalEventCount,
30867
+ limits.runtimeDeliveryBytes,
30868
+ limits.runtimeDeliveryCount,
30869
+ limits.standardEventBytes,
30870
+ limits.standardEventCount
30871
+ ];
30872
+ if (values.some((value) => !Number.isSafeInteger(value) || value < 1)) {
30873
+ throw new Error("Session event outbox limits must be positive integers");
30874
+ }
30875
+ if (limits.criticalEventBytes < limits.standardEventBytes || limits.criticalEventCount < limits.standardEventCount) {
30876
+ throw new Error("Critical Session event capacity must include the standard capacity");
30877
+ }
30878
+ }
30879
+ function runtimeDeliveryState(row) {
30880
+ const state = rowString2(row, "state");
30881
+ if (state !== "received" && state !== "relay_committed" && state !== "processed") {
30882
+ throw new Error("SQLite returned an invalid Runtime delivery state");
30883
+ }
30884
+ return state;
30885
+ }
29804
30886
  function isDaemonExecutionState(value) {
29805
30887
  return value === "cancelled" || value === "dispatching" || value === "failed" || value === "running" || value === "succeeded";
29806
30888
  }
@@ -29826,10 +30908,23 @@ function botIpcSocketPath() {
29826
30908
  return join16("/tmp", `mobius-bot-${randomUUID6()}.sock`);
29827
30909
  }
29828
30910
  var DaemonAcpObserver = class {
30911
+ #config;
29829
30912
  #record;
29830
- constructor(record2) {
29831
- this.#record = record2;
30913
+ constructor(config2, record3) {
30914
+ this.#config = config2;
30915
+ this.#record = record3;
29832
30916
  }
30917
+ importLocalImage = async (sessionId, image, signal) => {
30918
+ try {
30919
+ return (await uploadRuntimeArtifact(this.#config, sessionId, image, signal)).artifactId;
30920
+ } catch (cause) {
30921
+ signal.throwIfAborted();
30922
+ if (cause instanceof Error && cause.name === "AbortError") {
30923
+ throw cause;
30924
+ }
30925
+ return "";
30926
+ }
30927
+ };
29833
30928
  onCommands = (event) => {
29834
30929
  this.#record(event.sessionId, encodeSessionCommandsUpdatedEvent(event));
29835
30930
  return Promise.resolve();
@@ -30019,8 +31114,7 @@ var ActiveTurnReconciliationError = class extends Error {
30019
31114
  }
30020
31115
  };
30021
31116
  function activeTurnReconciliationEndpoint(config2, turn) {
30022
- const endpoint = new URL(config2.relayUrl);
30023
- endpoint.protocol = endpoint.protocol === "wss:" ? "https:" : "http:";
31117
+ const endpoint = relayHttpEndpoint(config2.relayUrl);
30024
31118
  let channelPath = "";
30025
31119
  if (endpoint.pathname.endsWith("/daemon")) {
30026
31120
  channelPath = endpoint.pathname.slice(0, -"/daemon".length);
@@ -30032,7 +31126,6 @@ function activeTurnReconciliationEndpoint(config2, turn) {
30032
31126
  channelPath = `${endpoint.pathname.slice(0, -runtimePath.length)}/channels/${encodeURIComponent(config2.channelId)}`;
30033
31127
  }
30034
31128
  endpoint.pathname = `${channelPath}/sessions/${encodeURIComponent(turn.command.sessionId)}/attempts/${encodeURIComponent(turn.attemptId)}/reconciliation`;
30035
- endpoint.searchParams.delete("liveness");
30036
31129
  return endpoint;
30037
31130
  }
30038
31131
  async function reconcileActiveTurn(config2, turn, signal) {
@@ -30041,10 +31134,10 @@ async function reconcileActiveTurn(config2, turn, signal) {
30041
31134
  const requestSignal = AbortSignal.any([signal, timeoutSignal]);
30042
31135
  let response;
30043
31136
  try {
30044
- response = await fetch6(activeTurnReconciliationEndpoint(config2, turn), {
31137
+ response = await fetch7(activeTurnReconciliationEndpoint(config2, turn), {
30045
31138
  body: JSON.stringify({ outcome: { kind: "running" } }),
30046
31139
  dispatcher: environmentProxyDispatcher,
30047
- headers: { "content-type": "application/json" },
31140
+ headers: { ...runtimeAuthorization(config2.relayUrl), "content-type": "application/json" },
30048
31141
  method: "POST",
30049
31142
  signal: requestSignal
30050
31143
  });
@@ -30112,17 +31205,31 @@ var ConnectedDaemonSessionEventState = class extends DaemonSessionEventConnectio
30112
31205
  }
30113
31206
  };
30114
31207
  };
30115
- var SESSION_EVENT_REPLAY_WINDOW = 4;
31208
+ var SESSION_EVENT_REPLAY_WINDOW = 16;
31209
+ var SESSION_EVENT_SOURCE_REPLAY_WINDOW = 4;
31210
+ var SESSION_EVENT_REPLAY_BYTE_LIMIT = 32 * 1024 * 1024;
31211
+ var InFlightSessionEvent = class {
31212
+ byteLength;
31213
+ sourceKey;
31214
+ constructor(sourceKey, byteLength) {
31215
+ this.byteLength = byteLength;
31216
+ this.sourceKey = sourceKey;
31217
+ }
31218
+ };
31219
+ function sessionEventSourceKey(envelope2) {
31220
+ return envelope2.source.kind === "attempt" ? `attempt:${envelope2.sessionId}:${envelope2.source.attemptId}` : `runtime:${envelope2.sessionId}`;
31221
+ }
30116
31222
  var DaemonSessionEventPublisher = class {
30117
31223
  #outbox;
30118
- #inFlightEventIds = /* @__PURE__ */ new Set();
31224
+ #inFlightEvents = /* @__PURE__ */ new Map();
31225
+ #inFlightBytes = 0;
30119
31226
  #connection = new DisconnectedDaemonSessionEventState();
30120
31227
  constructor(outbox) {
30121
31228
  this.#outbox = outbox;
30122
31229
  }
30123
31230
  connect = (socket) => {
30124
31231
  this.#connection = new ConnectedDaemonSessionEventState(socket);
30125
- this.#inFlightEventIds.clear();
31232
+ this.#clearInFlight();
30126
31233
  this.#publishNextBatch();
30127
31234
  };
30128
31235
  disconnect = (socket) => {
@@ -30130,10 +31237,15 @@ var DaemonSessionEventPublisher = class {
30130
31237
  return;
30131
31238
  }
30132
31239
  this.#connection = this.#connection.disconnect(socket);
30133
- this.#inFlightEventIds.clear();
31240
+ this.#clearInFlight();
30134
31241
  };
30135
31242
  recordAttempt = (sessionId, payload, attemptId) => {
30136
- this.#outbox.enqueue(sessionId, payload, attemptId);
31243
+ const kind = decodeMessageKind(payload);
31244
+ if (kind === SESSION_COMPLETED_KIND || kind === SESSION_FAILED_KIND) {
31245
+ this.#outbox.enqueueCritical(sessionId, payload, attemptId);
31246
+ } else {
31247
+ this.#outbox.enqueue(sessionId, payload, attemptId);
31248
+ }
30137
31249
  this.#publishNextBatch();
30138
31250
  };
30139
31251
  recordRuntime = (sessionId, payload) => {
@@ -30144,7 +31256,7 @@ var DaemonSessionEventPublisher = class {
30144
31256
  if (!this.#outbox.acknowledge(acknowledgement)) {
30145
31257
  return;
30146
31258
  }
30147
- this.#inFlightEventIds.delete(acknowledgement.eventId);
31259
+ this.#removeInFlight(acknowledgement.eventId);
30148
31260
  this.#publishNextBatch();
30149
31261
  };
30150
31262
  quarantine = (rejection) => {
@@ -30152,24 +31264,60 @@ var DaemonSessionEventPublisher = class {
30152
31264
  if (!quarantined) {
30153
31265
  return false;
30154
31266
  }
30155
- this.#inFlightEventIds.delete(rejection.eventId);
31267
+ this.#removeInFlight(rejection.eventId);
30156
31268
  this.#publishNextBatch();
30157
31269
  return true;
30158
31270
  };
30159
31271
  #publishNextBatch = () => {
30160
- if (this.#inFlightEventIds.size > 0) {
30161
- return;
30162
- }
30163
- const batch = this.#outbox.pendingBatch(SESSION_EVENT_REPLAY_WINDOW);
30164
- for (const encoded of batch) {
30165
- const envelope2 = decodeSessionEventEnvelope(encoded);
30166
- if (!this.#connection.send(encoded)) {
30167
- this.#inFlightEventIds.clear();
31272
+ while (this.#inFlightEvents.size < SESSION_EVENT_REPLAY_WINDOW) {
31273
+ const sourceCounts = /* @__PURE__ */ new Map();
31274
+ for (const inFlight of this.#inFlightEvents.values()) {
31275
+ sourceCounts.set(inFlight.sourceKey, (sourceCounts.get(inFlight.sourceKey) ?? 0) + 1);
31276
+ }
31277
+ const saturatedSources = [...sourceCounts.entries()].filter(([, count]) => count >= SESSION_EVENT_SOURCE_REPLAY_WINDOW).map(([sourceKey]) => sourceKey);
31278
+ const batch = this.#outbox.pendingSourceHeads(
31279
+ SESSION_EVENT_REPLAY_WINDOW - this.#inFlightEvents.size,
31280
+ [...this.#inFlightEvents.keys()],
31281
+ saturatedSources
31282
+ );
31283
+ let sent = 0;
31284
+ for (const encoded of batch) {
31285
+ const envelope2 = decodeSessionEventEnvelope(encoded);
31286
+ const sourceKey = sessionEventSourceKey(envelope2);
31287
+ const sourceCount = sourceCounts.get(sourceKey) ?? 0;
31288
+ if (sourceCount >= SESSION_EVENT_SOURCE_REPLAY_WINDOW) {
31289
+ continue;
31290
+ }
31291
+ const byteLength = new TextEncoder().encode(encoded).byteLength;
31292
+ if (this.#inFlightBytes + byteLength > SESSION_EVENT_REPLAY_BYTE_LIMIT) {
31293
+ continue;
31294
+ }
31295
+ if (!this.#connection.send(encoded)) {
31296
+ this.#clearInFlight();
31297
+ return;
31298
+ }
31299
+ this.#inFlightEvents.set(envelope2.eventId, new InFlightSessionEvent(sourceKey, byteLength));
31300
+ this.#inFlightBytes += byteLength;
31301
+ sourceCounts.set(sourceKey, sourceCount + 1);
31302
+ sent += 1;
31303
+ }
31304
+ if (sent === 0) {
30168
31305
  return;
30169
31306
  }
30170
- this.#inFlightEventIds.add(envelope2.eventId);
30171
31307
  }
30172
31308
  };
31309
+ #removeInFlight = (eventId) => {
31310
+ const inFlight = this.#inFlightEvents.get(eventId);
31311
+ if (inFlight === void 0) {
31312
+ return;
31313
+ }
31314
+ this.#inFlightEvents.delete(eventId);
31315
+ this.#inFlightBytes -= inFlight.byteLength;
31316
+ };
31317
+ #clearInFlight = () => {
31318
+ this.#inFlightEvents.clear();
31319
+ this.#inFlightBytes = 0;
31320
+ };
30173
31321
  };
30174
31322
  var CoalescingDaemonActivityPublisher = class {
30175
31323
  #pending = /* @__PURE__ */ new Map();
@@ -30302,7 +31450,7 @@ async function resolveSessionDirectories(directories, bindingId, directoryId2, a
30302
31450
  additionalDirectories.push(directory);
30303
31451
  additionalDirectoryEntries.push({
30304
31452
  directoryId: additionalDirectoryId,
30305
- name: basename4(directory)
31453
+ name: basename5(directory)
30306
31454
  });
30307
31455
  }
30308
31456
  return new ResolvedSessionDirectories(cwd, additionalDirectories, additionalDirectoryEntries);
@@ -30421,6 +31569,9 @@ async function executeSessionConfigure(publisher, socket, command, config2, dire
30421
31569
  })
30422
31570
  );
30423
31571
  } catch (error61) {
31572
+ if (signal.aborted) {
31573
+ signal.throwIfAborted();
31574
+ }
30424
31575
  reportOperationFailure(socket, command.requestId, command.sessionId, error61);
30425
31576
  }
30426
31577
  }
@@ -30760,6 +31911,7 @@ async function publishAgentCatalogUntilAvailable(config2, diagnostics, signal, t
30760
31911
  }
30761
31912
  async function runRelayConnection(config2, directories, audit, sessions, installations, installationObserver, nativeSessions, outbox, publisher, grants, contexts, applicator, ipc, activeTurns, activeAttemptIds, connectionEpoch, diagnostics, onConnected, signal, timer) {
30762
31913
  const relayUrl = new URL(config2.relayUrl);
31914
+ relayUrl.searchParams.set("deliveryReceipts", "1");
30763
31915
  relayUrl.searchParams.set("liveness", "1");
30764
31916
  const socket = await connectRelay(relayUrl, signal);
30765
31917
  const reconnectingTurns = [...activeTurns.values()];
@@ -30808,6 +31960,239 @@ async function runRelayConnection(config2, directories, audit, sessions, install
30808
31960
  closeRelaySocket(socket, code, reason);
30809
31961
  rejectConnection(failure);
30810
31962
  };
31963
+ const processingDeliveryIds = /* @__PURE__ */ new Set();
31964
+ const processDeliveredPrompt = async (delivery, command, trackActiveAttempt, execute) => {
31965
+ if (command.sessionId !== delivery.sessionId) {
31966
+ throw new Error("Runtime delivery Session identity does not match its payload");
31967
+ }
31968
+ const active = activeTurns.get(command.commandId);
31969
+ if (active !== void 0) {
31970
+ await active.completion;
31971
+ return;
31972
+ }
31973
+ const receipt = outbox.claimExecution(command.commandId, command.sessionId, delivery.payload);
31974
+ if (receipt.kind === "duplicate") {
31975
+ if (receipt.state === "running") {
31976
+ reportFailure(
31977
+ publisher,
31978
+ command,
31979
+ "agent_execution_interrupted",
31980
+ "The local Agent execution was interrupted before it completed",
31981
+ receipt.attemptId
31982
+ );
31983
+ outbox.transitionExecution(command.commandId, "failed");
31984
+ return;
31985
+ }
31986
+ if (receipt.state !== "dispatching") {
31987
+ return;
31988
+ }
31989
+ }
31990
+ const turn = new ActiveDaemonTurn(command, receipt.attemptId);
31991
+ activeTurns.set(command.commandId, turn);
31992
+ if (trackActiveAttempt) {
31993
+ activeAttemptIds.set(command.sessionId, receipt.attemptId);
31994
+ }
31995
+ try {
31996
+ await execute(receipt.attemptId, turn.signal);
31997
+ } finally {
31998
+ activeTurns.delete(command.commandId);
31999
+ if (activeAttemptIds.get(command.sessionId) === receipt.attemptId) {
32000
+ activeAttemptIds.delete(command.sessionId);
32001
+ }
32002
+ turn.finish();
32003
+ }
32004
+ };
32005
+ const processDeliveredPayload = async (delivery) => {
32006
+ const kind = decodeMessageKind(delivery.payload);
32007
+ if (kind === SESSION_CANCEL_KIND) {
32008
+ const cancellation = decodeSessionCancelCommand(delivery.payload);
32009
+ if (cancellation.sessionId !== delivery.sessionId) {
32010
+ throw new Error("Runtime delivery Session identity does not match its payload");
32011
+ }
32012
+ const turn = activeTurns.get(cancellation.commandId);
32013
+ if (turn === void 0 || !turn.matches(cancellation) || !turn.requestCancellation()) {
32014
+ return;
32015
+ }
32016
+ audit.record({
32017
+ commandId: cancellation.commandId,
32018
+ event: "session_cancellation_requested",
32019
+ sessionId: cancellation.sessionId
32020
+ });
32021
+ await sessions.cancelPrompt(cancellation.sessionId);
32022
+ return;
32023
+ }
32024
+ if (kind === SESSION_CONFIGURE_KIND) {
32025
+ const command = decodeSessionConfigureCommand(delivery.payload);
32026
+ if (command.sessionId !== delivery.sessionId) {
32027
+ throw new Error("Runtime delivery Session identity does not match its payload");
32028
+ }
32029
+ await executeSessionConfigure(
32030
+ publisher,
32031
+ socket,
32032
+ command,
32033
+ config2,
32034
+ directories,
32035
+ audit,
32036
+ sessions,
32037
+ connectionController.signal
32038
+ );
32039
+ return;
32040
+ }
32041
+ if (kind === SESSION_PERMISSION_RESPOND_KIND) {
32042
+ const command = decodeSessionPermissionRespondCommand(delivery.payload);
32043
+ if (command.sessionId !== delivery.sessionId) {
32044
+ throw new Error("Runtime delivery Session identity does not match its payload");
32045
+ }
32046
+ try {
32047
+ await sessions.respondPermission(command);
32048
+ audit.record({
32049
+ commandId: command.interactionId,
32050
+ event: "session_permission_resolved",
32051
+ sessionId: command.sessionId
32052
+ });
32053
+ } catch (error61) {
32054
+ reportOperationFailure(socket, command.interactionId, command.sessionId, error61);
32055
+ }
32056
+ return;
32057
+ }
32058
+ if (kind === SESSION_ELICITATION_RESPOND_KIND) {
32059
+ const command = decodeSessionElicitationRespondCommand(delivery.payload);
32060
+ if (command.sessionId !== delivery.sessionId) {
32061
+ throw new Error("Runtime delivery Session identity does not match its payload");
32062
+ }
32063
+ try {
32064
+ await sessions.respondElicitation(command);
32065
+ audit.record({
32066
+ commandId: command.interactionId,
32067
+ event: "session_elicitation_resolved",
32068
+ sessionId: command.sessionId
32069
+ });
32070
+ } catch (error61) {
32071
+ reportOperationFailure(socket, command.interactionId, command.sessionId, error61);
32072
+ }
32073
+ return;
32074
+ }
32075
+ if (kind === BOT_SESSION_PROMPT_KIND) {
32076
+ const command = decodeBotSessionPromptCommand(delivery.payload);
32077
+ await processDeliveredPrompt(
32078
+ delivery,
32079
+ command,
32080
+ true,
32081
+ (attemptId, executionSignal) => executeBotPrompt(
32082
+ outbox,
32083
+ publisher,
32084
+ command,
32085
+ config2,
32086
+ directories,
32087
+ audit,
32088
+ sessions,
32089
+ grants,
32090
+ contexts,
32091
+ applicator,
32092
+ ipc,
32093
+ attemptId,
32094
+ timer,
32095
+ executionSignal
32096
+ )
32097
+ );
32098
+ return;
32099
+ }
32100
+ if (kind === SESSION_PROMPT_KIND) {
32101
+ const command = decodeSessionPromptCommand(delivery.payload);
32102
+ await processDeliveredPrompt(
32103
+ delivery,
32104
+ command,
32105
+ command.disposition !== SessionPromptDisposition.Steer,
32106
+ (attemptId, executionSignal) => executePrompt(
32107
+ outbox,
32108
+ publisher,
32109
+ command,
32110
+ config2,
32111
+ directories,
32112
+ audit,
32113
+ sessions,
32114
+ attemptId,
32115
+ timer,
32116
+ executionSignal
32117
+ )
32118
+ );
32119
+ return;
32120
+ }
32121
+ throw new Error("Runtime delivery contains an unsupported protocol message");
32122
+ };
32123
+ const processRuntimeDelivery = (delivery, state) => {
32124
+ if (state === "processed" || processingDeliveryIds.has(delivery.deliveryId)) {
32125
+ return;
32126
+ }
32127
+ processingDeliveryIds.add(delivery.deliveryId);
32128
+ void processDeliveredPayload(delivery).then(() => {
32129
+ outbox.markRuntimeDeliveryProcessed(delivery.deliveryId, delivery.sessionId);
32130
+ }).catch((error61) => {
32131
+ if (connectionController.signal.aborted) {
32132
+ return;
32133
+ }
32134
+ console.error("Mobius daemon could not process a durable Runtime delivery", error61);
32135
+ failAndClose(
32136
+ new Error("Runtime delivery processing failed", { cause: error61 }),
32137
+ 4008,
32138
+ "Invalid Runtime delivery",
32139
+ "delivery"
32140
+ );
32141
+ }).finally(() => processingDeliveryIds.delete(delivery.deliveryId));
32142
+ };
32143
+ const receiveRuntimeDelivery = (delivery) => {
32144
+ const payloadKind = decodeMessageKind(delivery.payload);
32145
+ let payloadSessionId = "";
32146
+ if (payloadKind === SESSION_CANCEL_KIND) {
32147
+ payloadSessionId = decodeSessionCancelCommand(delivery.payload).sessionId;
32148
+ } else if (payloadKind === SESSION_CONFIGURE_KIND) {
32149
+ payloadSessionId = decodeSessionConfigureCommand(delivery.payload).sessionId;
32150
+ } else if (payloadKind === SESSION_PERMISSION_RESPOND_KIND) {
32151
+ payloadSessionId = decodeSessionPermissionRespondCommand(delivery.payload).sessionId;
32152
+ } else if (payloadKind === SESSION_ELICITATION_RESPOND_KIND) {
32153
+ payloadSessionId = decodeSessionElicitationRespondCommand(delivery.payload).sessionId;
32154
+ } else if (payloadKind === SESSION_PROMPT_KIND) {
32155
+ payloadSessionId = decodeSessionPromptCommand(delivery.payload).sessionId;
32156
+ } else if (payloadKind === BOT_SESSION_PROMPT_KIND) {
32157
+ payloadSessionId = decodeBotSessionPromptCommand(delivery.payload).sessionId;
32158
+ } else {
32159
+ throw new Error("Runtime delivery contains an unsupported protocol message");
32160
+ }
32161
+ if (payloadSessionId !== delivery.sessionId) {
32162
+ throw new Error("Runtime delivery Session identity does not match its payload");
32163
+ }
32164
+ const stored = outbox.claimRuntimeDelivery(delivery);
32165
+ send(
32166
+ socket,
32167
+ encodeRuntimeDeliveryReceived({
32168
+ deliveryId: delivery.deliveryId,
32169
+ kind: RUNTIME_DELIVERY_RECEIVED_KIND,
32170
+ sessionId: delivery.sessionId
32171
+ })
32172
+ );
32173
+ processRuntimeDelivery(delivery, stored.state);
32174
+ };
32175
+ const resumeRuntimeDeliveries = () => {
32176
+ for (const stored of outbox.runtimeDeliveries()) {
32177
+ const delivery = {
32178
+ deliveryId: stored.deliveryId,
32179
+ kind: RUNTIME_DELIVERY_KIND,
32180
+ payload: stored.payload,
32181
+ sessionId: stored.sessionId
32182
+ };
32183
+ if (stored.state !== "relay_committed") {
32184
+ send(
32185
+ socket,
32186
+ encodeRuntimeDeliveryReceived({
32187
+ deliveryId: stored.deliveryId,
32188
+ kind: RUNTIME_DELIVERY_RECEIVED_KIND,
32189
+ sessionId: stored.sessionId
32190
+ })
32191
+ );
32192
+ }
32193
+ processRuntimeDelivery(delivery, stored.state);
32194
+ }
32195
+ };
30811
32196
  const connectionLiveness = new RelayConnectionLiveness(timer, {
30812
32197
  send: (message) => send(socket, message),
30813
32198
  unresponsive: (heartbeatId, timeoutMilliseconds) => {
@@ -30846,6 +32231,17 @@ async function runRelayConnection(config2, directories, audit, sessions, install
30846
32231
  }
30847
32232
  try {
30848
32233
  const kind = decodeMessageKind(encoded);
32234
+ if (kind === RUNTIME_DELIVERY_COMMITTED_KIND) {
32235
+ const committed = decodeRuntimeDeliveryCommitted(encoded);
32236
+ if (!outbox.markRuntimeDeliveryCommitted(committed.deliveryId, committed.sessionId)) {
32237
+ console.warn("Mobius daemon ignored confirmation for an unknown Runtime delivery");
32238
+ }
32239
+ return;
32240
+ }
32241
+ if (kind === RUNTIME_DELIVERY_KIND) {
32242
+ receiveRuntimeDelivery(decodeRuntimeDelivery(encoded));
32243
+ return;
32244
+ }
30849
32245
  if (kind === SESSION_EVENT_ACK_KIND) {
30850
32246
  publisher.acknowledge(decodeSessionEventAcknowledgement(encoded));
30851
32247
  return;
@@ -31282,6 +32678,10 @@ async function runRelayConnection(config2, directories, audit, sessions, install
31282
32678
  });
31283
32679
  } catch (error61) {
31284
32680
  console.error("Mobius daemon rejected a message", error61);
32681
+ if (error61 instanceof RuntimeDeliveryInboxCapacityError) {
32682
+ failAndClose(error61, 4013, "Runtime delivery queue full", "delivery_backpressure");
32683
+ return;
32684
+ }
31285
32685
  failAndClose(
31286
32686
  new Error("Relay sent an invalid protocol message", { cause: error61 }),
31287
32687
  4008,
@@ -31299,6 +32699,7 @@ async function runRelayConnection(config2, directories, audit, sessions, install
31299
32699
  return;
31300
32700
  }
31301
32701
  publisher.connect(socket);
32702
+ resumeRuntimeDeliveries();
31302
32703
  },
31303
32704
  (error61) => {
31304
32705
  if (finished) {
@@ -31351,7 +32752,7 @@ async function runDaemon(config2, audit, signal, timer = systemDaemonTimer) {
31351
32752
  }
31352
32753
  publisher.recordAttempt(sessionId, payload, attemptId);
31353
32754
  };
31354
- const sessions = new AcpSessionManager(new DaemonAcpObserver(recordSessionEvent), sessionStore);
32755
+ const sessions = new AcpSessionManager(new DaemonAcpObserver(config2, recordSessionEvent), sessionStore);
31355
32756
  const directories = new WorkspaceDirectoryService(config2.bindingId, config2.defaultWorkspace);
31356
32757
  const installationObserver = new DaemonInstallationObserver();
31357
32758
  const diagnostics = new RelayConnectionDiagnostics(audit, config2.channelId, config2.relayUrl);
@@ -31449,11 +32850,11 @@ async function runDaemon(config2, audit, signal, timer = systemDaemonTimer) {
31449
32850
  }
31450
32851
 
31451
32852
  // src/runtime.ts
31452
- import { mkdir as mkdir5, realpath as realpath8, stat as stat8 } from "node:fs/promises";
32853
+ import { mkdir as mkdir5, realpath as realpath9, stat as stat9 } from "node:fs/promises";
31453
32854
  import { dirname as dirname8, join as join17, resolve as resolve5 } from "node:path";
31454
32855
  var APP_CREDENTIAL_PATTERN = /^mapp_[a-zA-Z0-9_-]{22}_[a-zA-Z0-9_-]{43}$/;
31455
32856
  var CONVERSATION_CREDENTIAL_PATTERN = /^mconv_[a-zA-Z0-9_-]{22}_[a-zA-Z0-9_-]{43}$/;
31456
- var IDENTIFIER_PATTERN8 = /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/;
32857
+ var IDENTIFIER_PATTERN9 = /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/;
31457
32858
  var RUNTIME_CREDENTIAL_PATTERN = /^[a-zA-Z0-9_-]{32,256}$/;
31458
32859
  var MobiusRuntimeConfigurationError = class extends Error {
31459
32860
  code = "runtime_configuration_invalid";
@@ -31511,7 +32912,7 @@ function relayUrlFromConnection(connection) {
31511
32912
  }
31512
32913
  function loadMobiusRuntimeConnection(environment = process.env) {
31513
32914
  const channelId = requiredEnvironmentValue(environment, "MOBIUS_CHANNEL_ID");
31514
- if (!IDENTIFIER_PATTERN8.test(channelId)) {
32915
+ if (!IDENTIFIER_PATTERN9.test(channelId)) {
31515
32916
  throw new MobiusRuntimeConfigurationError("MOBIUS_CHANNEL_ID is invalid");
31516
32917
  }
31517
32918
  return Object.freeze({
@@ -31526,8 +32927,8 @@ async function resolveWorkspace(path2) {
31526
32927
  const requested = resolve5(path2);
31527
32928
  try {
31528
32929
  await mkdir5(requested, { recursive: true, mode: 448 });
31529
- const resolved = await realpath8(requested);
31530
- const metadata = await stat8(resolved);
32930
+ const resolved = await realpath9(requested);
32931
+ const metadata = await stat9(resolved);
31531
32932
  if (!metadata.isDirectory()) {
31532
32933
  throw new MobiusRuntimeConfigurationError("The Runtime workspace is not a directory");
31533
32934
  }