@moxt-ai/mobius 0.0.26 → 0.0.27

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.
package/dist/cli.js CHANGED
@@ -11,7 +11,7 @@ import { mkdir as mkdir5 } from "node:fs/promises";
11
11
  // package.json
12
12
  var package_default = {
13
13
  name: "@moxt-ai/mobius",
14
- version: "0.0.26",
14
+ version: "0.0.27",
15
15
  description: "Mobius CLI for pairing and running local AI agent services.",
16
16
  type: "module",
17
17
  bin: {
@@ -22094,6 +22094,9 @@ var SESSION_CANCEL_KIND = "session.cancel";
22094
22094
  var RUNTIME_LIVENESS_READY_KIND = "runtime.liveness.ready";
22095
22095
  var RUNTIME_HEARTBEAT_KIND = "runtime.heartbeat";
22096
22096
  var RUNTIME_HEARTBEAT_ACK_KIND = "runtime.heartbeat.ack";
22097
+ var RUNTIME_DELIVERY_KIND = "runtime.delivery";
22098
+ var RUNTIME_DELIVERY_RECEIVED_KIND = "runtime.delivery.received";
22099
+ var RUNTIME_DELIVERY_COMMITTED_KIND = "runtime.delivery.committed";
22097
22100
  var SESSION_STARTED_KIND = "session.started";
22098
22101
  var AGENT_MESSAGE_DELTA_KIND = "agent.message.delta";
22099
22102
  var AGENT_ACTIVITY_KIND = "agent.activity";
@@ -22116,6 +22119,7 @@ var DIRECTORY_IDENTIFIER_PATTERN2 = /^[a-zA-Z0-9][a-zA-Z0-9_-]{0,2047}$/;
22116
22119
  var MAX_PROMPT_LENGTH = 1e4;
22117
22120
  var MAX_PROMPT_ATTACHMENT_LENGTH = 6e6;
22118
22121
  var MAX_EVENT_TEXT_LENGTH = 1e5;
22122
+ var MAX_RUNTIME_DELIVERY_PAYLOAD_LENGTH = 8 * 1024 * 1024;
22119
22123
  var ACTIVITY_TYPES = /* @__PURE__ */ new Set(["plan", "progress", "reasoning", "tool"]);
22120
22124
  var ACTIVITY_STATUSES = /* @__PURE__ */ new Set(["pending", "running", "completed", "failed"]);
22121
22125
  var TOOL_KINDS = /* @__PURE__ */ new Set([
@@ -22394,6 +22398,37 @@ function decodeRuntimeHeartbeatAckEvent(encoded) {
22394
22398
  kind: RUNTIME_HEARTBEAT_ACK_KIND
22395
22399
  };
22396
22400
  }
22401
+ function decodeRuntimeDelivery(encoded) {
22402
+ const value = parseJson2(encoded);
22403
+ assertExactKeys(value, ["deliveryId", "kind", "payload", "sessionId"]);
22404
+ assertKind(value, RUNTIME_DELIVERY_KIND);
22405
+ return {
22406
+ deliveryId: readIdentifier(value, "deliveryId"),
22407
+ kind: RUNTIME_DELIVERY_KIND,
22408
+ payload: readString(value, "payload", MAX_RUNTIME_DELIVERY_PAYLOAD_LENGTH),
22409
+ sessionId: readIdentifier(value, "sessionId")
22410
+ };
22411
+ }
22412
+ function decodeRuntimeDeliveryReceived(encoded) {
22413
+ const value = parseJson2(encoded);
22414
+ assertExactKeys(value, ["deliveryId", "kind", "sessionId"]);
22415
+ assertKind(value, RUNTIME_DELIVERY_RECEIVED_KIND);
22416
+ return {
22417
+ deliveryId: readIdentifier(value, "deliveryId"),
22418
+ kind: RUNTIME_DELIVERY_RECEIVED_KIND,
22419
+ sessionId: readIdentifier(value, "sessionId")
22420
+ };
22421
+ }
22422
+ function decodeRuntimeDeliveryCommitted(encoded) {
22423
+ const value = parseJson2(encoded);
22424
+ assertExactKeys(value, ["deliveryId", "kind", "sessionId"]);
22425
+ assertKind(value, RUNTIME_DELIVERY_COMMITTED_KIND);
22426
+ return {
22427
+ deliveryId: readIdentifier(value, "deliveryId"),
22428
+ kind: RUNTIME_DELIVERY_COMMITTED_KIND,
22429
+ sessionId: readIdentifier(value, "sessionId")
22430
+ };
22431
+ }
22397
22432
  function decodeSessionStartedEvent(encoded) {
22398
22433
  const value = parseJson2(encoded);
22399
22434
  assertExactKeys(value, ["commandId", "kind", "attemptId", "sessionId"]);
@@ -22481,6 +22516,9 @@ function decodeSessionFailedEvent(encoded) {
22481
22516
  function encodeRuntimeHeartbeatEvent(message) {
22482
22517
  return JSON.stringify(decodeRuntimeHeartbeatEvent(JSON.stringify(message)));
22483
22518
  }
22519
+ function encodeRuntimeDeliveryReceived(message) {
22520
+ return JSON.stringify(decodeRuntimeDeliveryReceived(JSON.stringify(message)));
22521
+ }
22484
22522
  function encodeSessionStartedEvent(message) {
22485
22523
  return JSON.stringify(decodeSessionStartedEvent(JSON.stringify(message)));
22486
22524
  }
@@ -23179,7 +23217,8 @@ var SESSION_EVENT_COMMITTED_KIND = "session.event.committed";
23179
23217
  var SESSION_EVENT_REJECTED_KIND = "session.event.rejected";
23180
23218
  var SessionEventRejectionCode = {
23181
23219
  SessionDeleted: "session_deleted",
23182
- SessionNotFound: "session_not_found"
23220
+ SessionNotFound: "session_not_found",
23221
+ SessionRejected: "session_rejected"
23183
23222
  };
23184
23223
  var IDENTIFIER_PATTERN4 = /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/;
23185
23224
  var CURSOR_PATTERN = /^[A-Za-z0-9_-]{1,512}$/;
@@ -23437,12 +23476,12 @@ function decodePairingResponse(value, credentialField, expectedKeys) {
23437
23476
  throw new PairingClientError("invalid_relay_response", "The relay returned an invalid pairing response");
23438
23477
  }
23439
23478
  const channelId = value["channelId"];
23440
- const runtimeCredential = value[credentialField];
23479
+ const runtimeCredential2 = value[credentialField];
23441
23480
  const runtimeId = value["runtimeId"];
23442
- if (typeof channelId !== "string" || !IDENTIFIER_PATTERN5.test(channelId) || typeof runtimeCredential !== "string" || !TOKEN_PATTERN2.test(runtimeCredential) || typeof runtimeId !== "string" || !IDENTIFIER_PATTERN5.test(runtimeId)) {
23481
+ if (typeof channelId !== "string" || !IDENTIFIER_PATTERN5.test(channelId) || typeof runtimeCredential2 !== "string" || !TOKEN_PATTERN2.test(runtimeCredential2) || typeof runtimeId !== "string" || !IDENTIFIER_PATTERN5.test(runtimeId)) {
23443
23482
  throw new PairingClientError("invalid_relay_response", "The relay returned an invalid pairing response");
23444
23483
  }
23445
- return { channelId, runtimeCredential, runtimeId };
23484
+ return { channelId, runtimeCredential: runtimeCredential2, runtimeId };
23446
23485
  }
23447
23486
  async function claimPairing(options, defaultWorkspace, localAgents, installableAgents, signal) {
23448
23487
  const agents = localAgents.map((agent) => ({
@@ -23477,7 +23516,7 @@ async function claimPairing(options, defaultWorkspace, localAgents, installableA
23477
23516
  }
23478
23517
  return options.pairingId.length > 0 ? decodePairingResponse(value, "runtimeCredential", REDEEM_RESPONSE_KEYS) : decodePairingResponse(value, "daemonToken", CLAIM_RESPONSE_KEYS);
23479
23518
  }
23480
- async function persistConnection(channelId, relayOrigin, runtimeCredential, defaultWorkspace, environment) {
23519
+ async function persistConnection(channelId, relayOrigin, runtimeCredential2, defaultWorkspace, environment) {
23481
23520
  const connectionsDirectory = join14(readStateDirectory(environment), "connections");
23482
23521
  await mkdir3(connectionsDirectory, { mode: 448, recursive: true });
23483
23522
  const connectionPath = join14(connectionsDirectory, `${channelId}.json`);
@@ -23489,7 +23528,7 @@ async function persistConnection(channelId, relayOrigin, runtimeCredential, defa
23489
23528
  defaultWorkspace,
23490
23529
  channelId,
23491
23530
  relayOrigin: relayOrigin.toString(),
23492
- runtimeCredential
23531
+ runtimeCredential: runtimeCredential2
23493
23532
  },
23494
23533
  null,
23495
23534
  2
@@ -23506,16 +23545,16 @@ function decodeSavedConnection(value, expectedChannelId) {
23506
23545
  }
23507
23546
  const defaultWorkspace = value["defaultWorkspace"];
23508
23547
  const channelId = value["channelId"];
23509
- const runtimeCredential = value["runtimeCredential"] ?? value["daemonToken"];
23548
+ const runtimeCredential2 = value["runtimeCredential"] ?? value["daemonToken"];
23510
23549
  const relayOrigin = value["relayOrigin"];
23511
- if (typeof defaultWorkspace !== "string" || typeof channelId !== "string" || channelId !== expectedChannelId || !IDENTIFIER_PATTERN5.test(channelId) || typeof runtimeCredential !== "string" || !TOKEN_PATTERN2.test(runtimeCredential) || typeof relayOrigin !== "string") {
23550
+ if (typeof defaultWorkspace !== "string" || typeof channelId !== "string" || channelId !== expectedChannelId || !IDENTIFIER_PATTERN5.test(channelId) || typeof runtimeCredential2 !== "string" || !TOKEN_PATTERN2.test(runtimeCredential2) || typeof relayOrigin !== "string") {
23512
23551
  throw new PairingClientError("invalid_connection", "The saved connection is invalid");
23513
23552
  }
23514
23553
  return {
23515
23554
  defaultWorkspace,
23516
23555
  channelId,
23517
23556
  relayOrigin: parseRelayOrigin(relayOrigin),
23518
- runtimeCredential
23557
+ runtimeCredential: runtimeCredential2
23519
23558
  };
23520
23559
  }
23521
23560
  async function readSavedConnection(channelId, environment) {
@@ -27048,6 +27087,23 @@ var AcpSessionManager = class {
27048
27087
 
27049
27088
  // src/agent-catalog/publish-agent-catalog.ts
27050
27089
  import { fetch as fetch3 } from "undici";
27090
+
27091
+ // src/relay-connection/runtime-authentication.ts
27092
+ function runtimeCredential(relayUrl) {
27093
+ return relayUrl.searchParams.get("token") ?? "";
27094
+ }
27095
+ function runtimeAuthorization(relayUrl) {
27096
+ const credential = runtimeCredential(relayUrl);
27097
+ return credential.length === 0 ? {} : { authorization: `Bearer ${credential}` };
27098
+ }
27099
+ function relayHttpEndpoint(relayUrl) {
27100
+ const endpoint = new URL(relayUrl);
27101
+ endpoint.protocol = endpoint.protocol === "wss:" ? "https:" : "http:";
27102
+ endpoint.search = "";
27103
+ return endpoint;
27104
+ }
27105
+
27106
+ // src/agent-catalog/publish-agent-catalog.ts
27051
27107
  var CATALOG_UPDATE_TIMEOUT_MILLISECONDS = 2e4;
27052
27108
  var AgentCatalogPublishError = class extends Error {
27053
27109
  code = "agent_catalog_update_failed";
@@ -27057,8 +27113,7 @@ var AgentCatalogPublishError = class extends Error {
27057
27113
  }
27058
27114
  };
27059
27115
  function catalogEndpoint(config2) {
27060
- const endpoint = new URL(config2.relayUrl);
27061
- endpoint.protocol = endpoint.protocol === "wss:" ? "https:" : "http:";
27116
+ const endpoint = relayHttpEndpoint(config2.relayUrl);
27062
27117
  if (endpoint.pathname.endsWith("/daemon")) {
27063
27118
  endpoint.pathname = `${endpoint.pathname.slice(0, -"/daemon".length)}/catalog`;
27064
27119
  return endpoint;
@@ -27089,7 +27144,7 @@ async function publishAgentCatalog(config2, signal) {
27089
27144
  installableAgents: catalog.installableAgents
27090
27145
  }),
27091
27146
  dispatcher: environmentProxyDispatcher,
27092
- headers: { "content-type": "application/json" },
27147
+ headers: { ...runtimeAuthorization(config2.relayUrl), "content-type": "application/json" },
27093
27148
  method: "PUT",
27094
27149
  signal: requestSignal
27095
27150
  });
@@ -29131,8 +29186,7 @@ function parseReference(resource) {
29131
29186
  return new PromptArtifactReference(artifactId, byteLength, sha256, resource);
29132
29187
  }
29133
29188
  function downloadUrl(config2, command, reference) {
29134
- const url2 = new URL(config2.relayUrl);
29135
- url2.protocol = url2.protocol === "wss:" ? "https:" : "http:";
29189
+ const url2 = relayHttpEndpoint(config2.relayUrl);
29136
29190
  let channelPath = "";
29137
29191
  if (url2.pathname.endsWith("/daemon")) {
29138
29192
  channelPath = url2.pathname.slice(0, -"/daemon".length);
@@ -29144,7 +29198,6 @@ function downloadUrl(config2, command, reference) {
29144
29198
  channelPath = `${url2.pathname.slice(0, -runtimePath.length)}/channels/${encodeURIComponent(config2.channelId)}`;
29145
29199
  }
29146
29200
  url2.pathname = `${channelPath}/sessions/${encodeURIComponent(command.sessionId)}/commands/${encodeURIComponent(command.commandId)}/artifacts/${encodeURIComponent(reference.artifactId)}/content`;
29147
- url2.searchParams.delete("liveness");
29148
29201
  return url2;
29149
29202
  }
29150
29203
  async function responseBytes(response, expectedByteLength, signal) {
@@ -29195,7 +29248,11 @@ async function download(config2, command, reference, signal) {
29195
29248
  try {
29196
29249
  response = await fetch5(downloadUrl(config2, command, reference), {
29197
29250
  dispatcher: environmentProxyDispatcher,
29198
- headers: { accept: reference.resource.mimeType },
29251
+ headers: {
29252
+ accept: reference.resource.mimeType,
29253
+ "accept-encoding": "identity",
29254
+ ...runtimeAuthorization(config2.relayUrl)
29255
+ },
29199
29256
  signal: requestSignal
29200
29257
  });
29201
29258
  if (!response.ok) {
@@ -29305,12 +29362,8 @@ function connectRelay(url2, signal) {
29305
29362
  signal.throwIfAborted();
29306
29363
  return new Promise((resolve5, reject) => {
29307
29364
  const endpoint = new URL(url2);
29308
- const headers = {};
29309
- if (endpoint.pathname.endsWith("/v1/runtimes/connect")) {
29310
- const runtimeCredential = endpoint.searchParams.get("token") ?? "";
29311
- endpoint.searchParams.delete("token");
29312
- headers["authorization"] = `Bearer ${runtimeCredential}`;
29313
- }
29365
+ const headers = runtimeAuthorization(endpoint);
29366
+ endpoint.searchParams.delete("token");
29314
29367
  const socket = new WebSocket(endpoint, {
29315
29368
  dispatcher: environmentProxyDispatcher,
29316
29369
  headers
@@ -29633,6 +29686,42 @@ var RelayConnectionLiveness = class {
29633
29686
  import { mkdirSync as mkdirSync3 } from "node:fs";
29634
29687
  import { dirname as dirname7 } from "node:path";
29635
29688
  import { DatabaseSync as DatabaseSync4 } from "node:sqlite";
29689
+ var DEFAULT_OUTBOX_LIMITS = {
29690
+ criticalEventBytes: 136 * 1024 * 1024,
29691
+ criticalEventCount: 10128,
29692
+ runtimeDeliveryBytes: 64 * 1024 * 1024,
29693
+ runtimeDeliveryCount: 64,
29694
+ standardEventBytes: 128 * 1024 * 1024,
29695
+ standardEventCount: 1e4
29696
+ };
29697
+ var SessionEventOutboxCapacityError = class extends Error {
29698
+ code = "session_event_outbox_full";
29699
+ constructor() {
29700
+ super("The durable Session event outbox is full");
29701
+ this.name = "SessionEventOutboxCapacityError";
29702
+ }
29703
+ };
29704
+ var RuntimeDeliveryInboxCapacityError = class extends Error {
29705
+ code = "runtime_delivery_inbox_full";
29706
+ constructor() {
29707
+ super("The durable Runtime delivery inbox is full");
29708
+ this.name = "RuntimeDeliveryInboxCapacityError";
29709
+ }
29710
+ };
29711
+ var StoredRuntimeDelivery = class {
29712
+ deliveryId;
29713
+ duplicate;
29714
+ payload;
29715
+ sessionId;
29716
+ state;
29717
+ constructor(deliveryId, sessionId, payload, state, duplicate) {
29718
+ this.deliveryId = deliveryId;
29719
+ this.duplicate = duplicate;
29720
+ this.payload = payload;
29721
+ this.sessionId = sessionId;
29722
+ this.state = state;
29723
+ }
29724
+ };
29636
29725
  function readPendingEnvelope(row) {
29637
29726
  if (typeof row !== "object" || row === null || Array.isArray(row)) {
29638
29727
  throw new Error("SQLite returned an invalid session event outbox row");
@@ -29643,9 +29732,26 @@ function readPendingEnvelope(row) {
29643
29732
  }
29644
29733
  return envelope2;
29645
29734
  }
29735
+ function rowNumber(row, field) {
29736
+ const value = typeof row === "object" && row !== null ? Reflect.get(row, field) : void 0;
29737
+ if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0) {
29738
+ throw new Error(`SQLite returned an invalid ${field} value`);
29739
+ }
29740
+ return value;
29741
+ }
29742
+ function rowString2(row, field) {
29743
+ const value = typeof row === "object" && row !== null ? Reflect.get(row, field) : void 0;
29744
+ if (typeof value !== "string" || value.length === 0) {
29745
+ throw new Error(`SQLite returned an invalid ${field} value`);
29746
+ }
29747
+ return value;
29748
+ }
29646
29749
  var SessionEventOutbox = class {
29647
29750
  #database;
29648
- constructor(path2) {
29751
+ #limits;
29752
+ constructor(path2, limits = DEFAULT_OUTBOX_LIMITS) {
29753
+ validateLimits(limits);
29754
+ this.#limits = limits;
29649
29755
  mkdirSync3(dirname7(path2), { recursive: true });
29650
29756
  this.#database = new DatabaseSync4(path2);
29651
29757
  this.#database.exec(`
@@ -29654,6 +29760,7 @@ var SessionEventOutbox = class {
29654
29760
  event_id TEXT NOT NULL UNIQUE,
29655
29761
  session_id TEXT NOT NULL,
29656
29762
  source_key TEXT NOT NULL,
29763
+ byte_length INTEGER NOT NULL,
29657
29764
  envelope_json TEXT NOT NULL
29658
29765
  ) STRICT;
29659
29766
  CREATE INDEX IF NOT EXISTS relay_session_event_outbox_order
@@ -29664,7 +29771,7 @@ var SessionEventOutbox = class {
29664
29771
  session_id TEXT NOT NULL,
29665
29772
  envelope_json TEXT NOT NULL,
29666
29773
  rejection_code TEXT NOT NULL CHECK (
29667
- rejection_code IN ('session_deleted', 'session_not_found')
29774
+ rejection_code IN ('session_deleted', 'session_not_found', 'session_rejected')
29668
29775
  )
29669
29776
  ) STRICT;
29670
29777
  CREATE TABLE IF NOT EXISTS relay_session_event_sources (
@@ -29680,7 +29787,53 @@ var SessionEventOutbox = class {
29680
29787
  state IN ('dispatching', 'running', 'succeeded', 'failed', 'cancelled')
29681
29788
  )
29682
29789
  ) STRICT;
29790
+ CREATE TABLE IF NOT EXISTS relay_session_event_outbox_state (
29791
+ singleton INTEGER PRIMARY KEY CHECK (singleton = 1),
29792
+ event_count INTEGER NOT NULL,
29793
+ total_bytes INTEGER NOT NULL
29794
+ ) STRICT;
29795
+ INSERT OR IGNORE INTO relay_session_event_outbox_state (
29796
+ singleton, event_count, total_bytes
29797
+ ) VALUES (1, 0, 0);
29798
+ CREATE TABLE IF NOT EXISTS relay_runtime_deliveries (
29799
+ delivery_id TEXT PRIMARY KEY,
29800
+ session_id TEXT NOT NULL,
29801
+ payload_json TEXT NOT NULL,
29802
+ payload_bytes INTEGER NOT NULL,
29803
+ state TEXT NOT NULL CHECK (
29804
+ state IN ('received', 'relay_committed', 'processed')
29805
+ ),
29806
+ received_at INTEGER NOT NULL
29807
+ ) STRICT;
29683
29808
  `);
29809
+ const deadLetterTable = this.#database.prepare(
29810
+ `SELECT sql FROM sqlite_master
29811
+ WHERE type = 'table' AND name = 'relay_session_event_dead_letters'`
29812
+ ).get();
29813
+ const deadLetterSql = typeof deadLetterTable === "object" && deadLetterTable !== null ? Reflect.get(deadLetterTable, "sql") : void 0;
29814
+ if (typeof deadLetterSql !== "string" || !deadLetterSql.includes("'session_rejected'")) {
29815
+ this.#database.exec(`
29816
+ BEGIN IMMEDIATE;
29817
+ ALTER TABLE relay_session_event_dead_letters
29818
+ RENAME TO relay_session_event_dead_letters_legacy;
29819
+ CREATE TABLE relay_session_event_dead_letters (
29820
+ ordinal INTEGER PRIMARY KEY,
29821
+ event_id TEXT NOT NULL UNIQUE,
29822
+ session_id TEXT NOT NULL,
29823
+ envelope_json TEXT NOT NULL,
29824
+ rejection_code TEXT NOT NULL CHECK (
29825
+ rejection_code IN ('session_deleted', 'session_not_found', 'session_rejected')
29826
+ )
29827
+ ) STRICT;
29828
+ INSERT INTO relay_session_event_dead_letters (
29829
+ ordinal, event_id, session_id, envelope_json, rejection_code
29830
+ )
29831
+ SELECT ordinal, event_id, session_id, envelope_json, rejection_code
29832
+ FROM relay_session_event_dead_letters_legacy;
29833
+ DROP TABLE relay_session_event_dead_letters_legacy;
29834
+ COMMIT;
29835
+ `);
29836
+ }
29684
29837
  const outboxColumns = this.#database.prepare("PRAGMA table_info(relay_session_event_outbox)").all();
29685
29838
  const hasSourceKey = outboxColumns.some(
29686
29839
  (column) => typeof column === "object" && column !== null && Reflect.get(column, "name") === "source_key"
@@ -29691,6 +29844,15 @@ var SessionEventOutbox = class {
29691
29844
  ADD COLUMN source_key TEXT NOT NULL DEFAULT '';
29692
29845
  `);
29693
29846
  }
29847
+ const hasByteLength = outboxColumns.some(
29848
+ (column) => typeof column === "object" && column !== null && Reflect.get(column, "name") === "byte_length"
29849
+ );
29850
+ if (!hasByteLength) {
29851
+ this.#database.exec(`
29852
+ ALTER TABLE relay_session_event_outbox
29853
+ ADD COLUMN byte_length INTEGER NOT NULL DEFAULT 0;
29854
+ `);
29855
+ }
29694
29856
  this.#database.exec(`
29695
29857
  UPDATE relay_session_event_outbox
29696
29858
  SET source_key = CASE json_extract(envelope_json, '$.source.kind')
@@ -29699,6 +29861,16 @@ var SessionEventOutbox = class {
29699
29861
  ELSE 'runtime:' || session_id
29700
29862
  END
29701
29863
  WHERE source_key = '';
29864
+ UPDATE relay_session_event_outbox
29865
+ SET byte_length = length(CAST(envelope_json AS BLOB))
29866
+ WHERE byte_length = 0;
29867
+ UPDATE relay_session_event_outbox_state
29868
+ SET event_count = (SELECT COUNT(*) FROM relay_session_event_outbox),
29869
+ total_bytes = (
29870
+ SELECT COALESCE(SUM(byte_length), 0)
29871
+ FROM relay_session_event_outbox
29872
+ )
29873
+ WHERE singleton = 1;
29702
29874
  CREATE INDEX IF NOT EXISTS relay_session_event_outbox_source_order
29703
29875
  ON relay_session_event_outbox(source_key, ordinal);
29704
29876
  `);
@@ -29759,13 +29931,19 @@ var SessionEventOutbox = class {
29759
29931
  const state = typeof row === "object" && row !== null ? Reflect.get(row, "state") : void 0;
29760
29932
  return state === "succeeded" || state === "failed" || state === "cancelled";
29761
29933
  };
29762
- acknowledge = (acknowledgement) => this.#database.prepare(
29763
- `DELETE FROM relay_session_event_outbox
29764
- WHERE event_id = ? AND session_id = ?`
29765
- ).run(acknowledgement.eventId, acknowledgement.sessionId).changes === 1;
29934
+ acknowledge = (acknowledgement) => this.#removeAcknowledgedEvent(acknowledgement.eventId, acknowledgement.sessionId);
29766
29935
  quarantine = (rejection) => {
29767
29936
  this.#database.exec("BEGIN IMMEDIATE");
29768
29937
  try {
29938
+ const stored = this.#database.prepare(
29939
+ `SELECT byte_length FROM relay_session_event_outbox
29940
+ WHERE event_id = ? AND session_id = ?`
29941
+ ).get(rejection.eventId, rejection.sessionId);
29942
+ if (stored === void 0) {
29943
+ this.#database.exec("COMMIT");
29944
+ return false;
29945
+ }
29946
+ const byteLength = rowNumber(stored, "byte_length");
29769
29947
  const insertion = this.#database.prepare(
29770
29948
  `INSERT INTO relay_session_event_dead_letters (
29771
29949
  ordinal, event_id, session_id, envelope_json, rejection_code
@@ -29785,6 +29963,7 @@ var SessionEventOutbox = class {
29785
29963
  if (deletion.changes !== 1) {
29786
29964
  throw new Error("The rejected session event could not be removed from the durable outbox");
29787
29965
  }
29966
+ this.#decrementEventState(byteLength);
29788
29967
  this.#database.exec("COMMIT");
29789
29968
  return true;
29790
29969
  } catch (error61) {
@@ -29796,7 +29975,129 @@ var SessionEventOutbox = class {
29796
29975
  this.#database.close();
29797
29976
  };
29798
29977
  enqueue = (sessionId, payload, attemptId = null) => {
29799
- const sourceKey = attemptId === null ? `runtime:${sessionId}` : `attempt:${sessionId}:${attemptId}`;
29978
+ return this.#enqueueBounded(
29979
+ sessionId,
29980
+ payload,
29981
+ attemptId ?? "",
29982
+ this.#limits.standardEventCount,
29983
+ this.#limits.standardEventBytes
29984
+ );
29985
+ };
29986
+ enqueueCritical = (sessionId, payload, attemptId = "") => this.#enqueueBounded(
29987
+ sessionId,
29988
+ payload,
29989
+ attemptId,
29990
+ this.#limits.criticalEventCount,
29991
+ this.#limits.criticalEventBytes
29992
+ );
29993
+ claimRuntimeDelivery = (delivery) => {
29994
+ const payloadBytes = new TextEncoder().encode(delivery.payload).byteLength;
29995
+ this.#database.exec("BEGIN IMMEDIATE");
29996
+ try {
29997
+ const existing = this.#database.prepare(
29998
+ `SELECT session_id, payload_json, state
29999
+ FROM relay_runtime_deliveries
30000
+ WHERE delivery_id = ?`
30001
+ ).get(delivery.deliveryId);
30002
+ if (existing !== void 0) {
30003
+ const sessionId = rowString2(existing, "session_id");
30004
+ const payload = rowString2(existing, "payload_json");
30005
+ const state = runtimeDeliveryState(existing);
30006
+ if (sessionId !== delivery.sessionId || payload !== delivery.payload) {
30007
+ throw new Error("The Runtime delivery identity conflicts with its durable receipt");
30008
+ }
30009
+ this.#database.exec("COMMIT");
30010
+ return new StoredRuntimeDelivery(delivery.deliveryId, sessionId, payload, state, true);
30011
+ }
30012
+ const usage = this.#database.prepare(
30013
+ `SELECT COUNT(*) AS delivery_count,
30014
+ COALESCE(SUM(payload_bytes), 0) AS delivery_bytes
30015
+ FROM relay_runtime_deliveries`
30016
+ ).get();
30017
+ if (rowNumber(usage, "delivery_count") + 1 > this.#limits.runtimeDeliveryCount || rowNumber(usage, "delivery_bytes") + payloadBytes > this.#limits.runtimeDeliveryBytes) {
30018
+ throw new RuntimeDeliveryInboxCapacityError();
30019
+ }
30020
+ this.#database.prepare(
30021
+ `INSERT INTO relay_runtime_deliveries (
30022
+ delivery_id, session_id, payload_json, payload_bytes, state, received_at
30023
+ ) VALUES (?, ?, ?, ?, 'received', ?)`
30024
+ ).run(delivery.deliveryId, delivery.sessionId, delivery.payload, payloadBytes, Date.now());
30025
+ this.#database.exec("COMMIT");
30026
+ return new StoredRuntimeDelivery(
30027
+ delivery.deliveryId,
30028
+ delivery.sessionId,
30029
+ delivery.payload,
30030
+ "received",
30031
+ false
30032
+ );
30033
+ } catch (error61) {
30034
+ this.#database.exec("ROLLBACK");
30035
+ throw error61;
30036
+ }
30037
+ };
30038
+ markRuntimeDeliveryCommitted = (deliveryId, sessionId) => {
30039
+ this.#database.exec("BEGIN IMMEDIATE");
30040
+ try {
30041
+ const row = this.#database.prepare(
30042
+ `SELECT state FROM relay_runtime_deliveries
30043
+ WHERE delivery_id = ? AND session_id = ?`
30044
+ ).get(deliveryId, sessionId);
30045
+ if (row === void 0) {
30046
+ this.#database.exec("COMMIT");
30047
+ return false;
30048
+ }
30049
+ const state = runtimeDeliveryState(row);
30050
+ if (state === "processed") {
30051
+ this.#database.prepare(`DELETE FROM relay_runtime_deliveries WHERE delivery_id = ?`).run(deliveryId);
30052
+ } else if (state === "received") {
30053
+ this.#database.prepare(`UPDATE relay_runtime_deliveries SET state = 'relay_committed' WHERE delivery_id = ?`).run(deliveryId);
30054
+ }
30055
+ this.#database.exec("COMMIT");
30056
+ return true;
30057
+ } catch (error61) {
30058
+ this.#database.exec("ROLLBACK");
30059
+ throw error61;
30060
+ }
30061
+ };
30062
+ markRuntimeDeliveryProcessed = (deliveryId, sessionId) => {
30063
+ this.#database.exec("BEGIN IMMEDIATE");
30064
+ try {
30065
+ const row = this.#database.prepare(
30066
+ `SELECT state FROM relay_runtime_deliveries
30067
+ WHERE delivery_id = ? AND session_id = ?`
30068
+ ).get(deliveryId, sessionId);
30069
+ if (row === void 0) {
30070
+ this.#database.exec("COMMIT");
30071
+ return false;
30072
+ }
30073
+ const state = runtimeDeliveryState(row);
30074
+ if (state === "relay_committed") {
30075
+ this.#database.prepare(`DELETE FROM relay_runtime_deliveries WHERE delivery_id = ?`).run(deliveryId);
30076
+ } else if (state === "received") {
30077
+ this.#database.prepare(`UPDATE relay_runtime_deliveries SET state = 'processed' WHERE delivery_id = ?`).run(deliveryId);
30078
+ }
30079
+ this.#database.exec("COMMIT");
30080
+ return true;
30081
+ } catch (error61) {
30082
+ this.#database.exec("ROLLBACK");
30083
+ throw error61;
30084
+ }
30085
+ };
30086
+ runtimeDeliveries = () => this.#database.prepare(
30087
+ `SELECT delivery_id, session_id, payload_json, state
30088
+ FROM relay_runtime_deliveries
30089
+ ORDER BY received_at, delivery_id`
30090
+ ).all().map(
30091
+ (row) => new StoredRuntimeDelivery(
30092
+ rowString2(row, "delivery_id"),
30093
+ rowString2(row, "session_id"),
30094
+ rowString2(row, "payload_json"),
30095
+ runtimeDeliveryState(row),
30096
+ true
30097
+ )
30098
+ );
30099
+ #enqueueBounded = (sessionId, payload, attemptId, maximumEventCount, maximumEventBytes) => {
30100
+ const sourceKey = attemptId.length === 0 ? `runtime:${sessionId}` : `attempt:${sessionId}:${attemptId}`;
29800
30101
  this.#database.exec("BEGIN IMMEDIATE");
29801
30102
  try {
29802
30103
  const row = this.#database.prepare(
@@ -29813,13 +30114,22 @@ var SessionEventOutbox = class {
29813
30114
  kind: SESSION_EVENT_KIND,
29814
30115
  payload,
29815
30116
  sessionId,
29816
- source: attemptId === null ? { kind: "runtime", sourceSeq: nextSourceSeq.toString() } : {
30117
+ source: attemptId.length === 0 ? { kind: "runtime", sourceSeq: nextSourceSeq.toString() } : {
29817
30118
  attemptId,
29818
30119
  kind: "attempt",
29819
30120
  sourceSeq: nextSourceSeq.toString()
29820
30121
  }
29821
30122
  };
29822
30123
  const encoded = encodeSessionEventEnvelope(envelope2);
30124
+ const byteLength = new TextEncoder().encode(encoded).byteLength;
30125
+ const state = this.#database.prepare(
30126
+ `SELECT event_count, total_bytes
30127
+ FROM relay_session_event_outbox_state
30128
+ WHERE singleton = 1`
30129
+ ).get();
30130
+ if (rowNumber(state, "event_count") + 1 > maximumEventCount || rowNumber(state, "total_bytes") + byteLength > maximumEventBytes) {
30131
+ throw new SessionEventOutboxCapacityError();
30132
+ }
29823
30133
  this.#database.prepare(
29824
30134
  `INSERT INTO relay_session_event_sources (
29825
30135
  source_key, next_source_seq
@@ -29829,9 +30139,15 @@ var SessionEventOutbox = class {
29829
30139
  ).run(sourceKey, nextSourceSeq + 1);
29830
30140
  this.#database.prepare(
29831
30141
  `INSERT INTO relay_session_event_outbox (
29832
- event_id, session_id, source_key, envelope_json
29833
- ) VALUES (?, ?, ?, ?)`
29834
- ).run(envelope2.eventId, envelope2.sessionId, sourceKey, encoded);
30142
+ event_id, session_id, source_key, byte_length, envelope_json
30143
+ ) VALUES (?, ?, ?, ?, ?)`
30144
+ ).run(envelope2.eventId, envelope2.sessionId, sourceKey, byteLength, encoded);
30145
+ this.#database.prepare(
30146
+ `UPDATE relay_session_event_outbox_state
30147
+ SET event_count = event_count + 1,
30148
+ total_bytes = total_bytes + ?
30149
+ WHERE singleton = 1`
30150
+ ).run(byteLength);
29835
30151
  this.#database.exec("COMMIT");
29836
30152
  return encoded;
29837
30153
  } catch (error61) {
@@ -29839,6 +30155,44 @@ var SessionEventOutbox = class {
29839
30155
  throw error61;
29840
30156
  }
29841
30157
  };
30158
+ #removeAcknowledgedEvent = (eventId, sessionId) => {
30159
+ this.#database.exec("BEGIN IMMEDIATE");
30160
+ try {
30161
+ const stored = this.#database.prepare(
30162
+ `SELECT byte_length FROM relay_session_event_outbox
30163
+ WHERE event_id = ? AND session_id = ?`
30164
+ ).get(eventId, sessionId);
30165
+ if (stored === void 0) {
30166
+ this.#database.exec("COMMIT");
30167
+ return false;
30168
+ }
30169
+ const byteLength = rowNumber(stored, "byte_length");
30170
+ const deletion = this.#database.prepare(
30171
+ `DELETE FROM relay_session_event_outbox
30172
+ WHERE event_id = ? AND session_id = ?`
30173
+ ).run(eventId, sessionId);
30174
+ if (deletion.changes !== 1) {
30175
+ throw new Error("The acknowledged session event could not be removed from the durable outbox");
30176
+ }
30177
+ this.#decrementEventState(byteLength);
30178
+ this.#database.exec("COMMIT");
30179
+ return true;
30180
+ } catch (error61) {
30181
+ this.#database.exec("ROLLBACK");
30182
+ throw error61;
30183
+ }
30184
+ };
30185
+ #decrementEventState = (byteLength) => {
30186
+ const result = this.#database.prepare(
30187
+ `UPDATE relay_session_event_outbox_state
30188
+ SET event_count = event_count - 1,
30189
+ total_bytes = total_bytes - ?
30190
+ WHERE singleton = 1 AND event_count > 0 AND total_bytes >= ?`
30191
+ ).run(byteLength, byteLength);
30192
+ if (result.changes !== 1) {
30193
+ throw new Error("The Session event outbox capacity state is inconsistent");
30194
+ }
30195
+ };
29842
30196
  pending = () => this.#database.prepare(
29843
30197
  `SELECT envelope_json
29844
30198
  FROM relay_session_event_outbox
@@ -29865,7 +30219,68 @@ var SessionEventOutbox = class {
29865
30219
  LIMIT ?`
29866
30220
  ).all(limit).map(readPendingEnvelope);
29867
30221
  };
30222
+ pendingSourceHeads = (limit, excludedEventIds, excludedSourceKeys) => {
30223
+ if (!Number.isSafeInteger(limit) || limit < 1) {
30224
+ throw new Error("Session event replay batch limit must be a positive integer");
30225
+ }
30226
+ const exclusions = [];
30227
+ const parameters = [];
30228
+ if (excludedEventIds.length > 0) {
30229
+ exclusions.push(`event_id NOT IN (${excludedEventIds.map(() => "?").join(", ")})`);
30230
+ parameters.push(...excludedEventIds);
30231
+ }
30232
+ if (excludedSourceKeys.length > 0) {
30233
+ exclusions.push(`source_key NOT IN (${excludedSourceKeys.map(() => "?").join(", ")})`);
30234
+ parameters.push(...excludedSourceKeys);
30235
+ }
30236
+ parameters.push(limit.toString());
30237
+ const where = exclusions.length === 0 ? "" : `WHERE ${exclusions.join(" AND ")}`;
30238
+ return this.#database.prepare(
30239
+ `WITH available_events AS (
30240
+ SELECT ordinal, source_key
30241
+ FROM relay_session_event_outbox
30242
+ ${where}
30243
+ ), ranked_events AS (
30244
+ SELECT ordinal,
30245
+ ROW_NUMBER() OVER (
30246
+ PARTITION BY source_key
30247
+ ORDER BY ordinal
30248
+ ) AS source_position
30249
+ FROM available_events
30250
+ )
30251
+ SELECT outbox.envelope_json
30252
+ FROM ranked_events AS ranked
30253
+ INNER JOIN relay_session_event_outbox AS outbox
30254
+ ON outbox.ordinal = ranked.ordinal
30255
+ WHERE ranked.source_position = 1
30256
+ ORDER BY outbox.ordinal
30257
+ LIMIT ?`
30258
+ ).all(...parameters).map(readPendingEnvelope);
30259
+ };
29868
30260
  };
30261
+ function validateLimits(limits) {
30262
+ const values = [
30263
+ limits.criticalEventBytes,
30264
+ limits.criticalEventCount,
30265
+ limits.runtimeDeliveryBytes,
30266
+ limits.runtimeDeliveryCount,
30267
+ limits.standardEventBytes,
30268
+ limits.standardEventCount
30269
+ ];
30270
+ if (values.some((value) => !Number.isSafeInteger(value) || value < 1)) {
30271
+ throw new Error("Session event outbox limits must be positive integers");
30272
+ }
30273
+ if (limits.criticalEventBytes < limits.standardEventBytes || limits.criticalEventCount < limits.standardEventCount) {
30274
+ throw new Error("Critical Session event capacity must include the standard capacity");
30275
+ }
30276
+ }
30277
+ function runtimeDeliveryState(row) {
30278
+ const state = rowString2(row, "state");
30279
+ if (state !== "received" && state !== "relay_committed" && state !== "processed") {
30280
+ throw new Error("SQLite returned an invalid Runtime delivery state");
30281
+ }
30282
+ return state;
30283
+ }
29869
30284
  function isDaemonExecutionState(value) {
29870
30285
  return value === "cancelled" || value === "dispatching" || value === "failed" || value === "running" || value === "succeeded";
29871
30286
  }
@@ -30084,8 +30499,7 @@ var ActiveTurnReconciliationError = class extends Error {
30084
30499
  }
30085
30500
  };
30086
30501
  function activeTurnReconciliationEndpoint(config2, turn) {
30087
- const endpoint = new URL(config2.relayUrl);
30088
- endpoint.protocol = endpoint.protocol === "wss:" ? "https:" : "http:";
30502
+ const endpoint = relayHttpEndpoint(config2.relayUrl);
30089
30503
  let channelPath = "";
30090
30504
  if (endpoint.pathname.endsWith("/daemon")) {
30091
30505
  channelPath = endpoint.pathname.slice(0, -"/daemon".length);
@@ -30097,7 +30511,6 @@ function activeTurnReconciliationEndpoint(config2, turn) {
30097
30511
  channelPath = `${endpoint.pathname.slice(0, -runtimePath.length)}/channels/${encodeURIComponent(config2.channelId)}`;
30098
30512
  }
30099
30513
  endpoint.pathname = `${channelPath}/sessions/${encodeURIComponent(turn.command.sessionId)}/attempts/${encodeURIComponent(turn.attemptId)}/reconciliation`;
30100
- endpoint.searchParams.delete("liveness");
30101
30514
  return endpoint;
30102
30515
  }
30103
30516
  async function reconcileActiveTurn(config2, turn, signal) {
@@ -30109,7 +30522,7 @@ async function reconcileActiveTurn(config2, turn, signal) {
30109
30522
  response = await fetch6(activeTurnReconciliationEndpoint(config2, turn), {
30110
30523
  body: JSON.stringify({ outcome: { kind: "running" } }),
30111
30524
  dispatcher: environmentProxyDispatcher,
30112
- headers: { "content-type": "application/json" },
30525
+ headers: { ...runtimeAuthorization(config2.relayUrl), "content-type": "application/json" },
30113
30526
  method: "POST",
30114
30527
  signal: requestSignal
30115
30528
  });
@@ -30177,17 +30590,31 @@ var ConnectedDaemonSessionEventState = class extends DaemonSessionEventConnectio
30177
30590
  }
30178
30591
  };
30179
30592
  };
30180
- var SESSION_EVENT_REPLAY_WINDOW = 4;
30593
+ var SESSION_EVENT_REPLAY_WINDOW = 16;
30594
+ var SESSION_EVENT_SOURCE_REPLAY_WINDOW = 4;
30595
+ var SESSION_EVENT_REPLAY_BYTE_LIMIT = 32 * 1024 * 1024;
30596
+ var InFlightSessionEvent = class {
30597
+ byteLength;
30598
+ sourceKey;
30599
+ constructor(sourceKey, byteLength) {
30600
+ this.byteLength = byteLength;
30601
+ this.sourceKey = sourceKey;
30602
+ }
30603
+ };
30604
+ function sessionEventSourceKey(envelope2) {
30605
+ return envelope2.source.kind === "attempt" ? `attempt:${envelope2.sessionId}:${envelope2.source.attemptId}` : `runtime:${envelope2.sessionId}`;
30606
+ }
30181
30607
  var DaemonSessionEventPublisher = class {
30182
30608
  #outbox;
30183
- #inFlightEventIds = /* @__PURE__ */ new Set();
30609
+ #inFlightEvents = /* @__PURE__ */ new Map();
30610
+ #inFlightBytes = 0;
30184
30611
  #connection = new DisconnectedDaemonSessionEventState();
30185
30612
  constructor(outbox) {
30186
30613
  this.#outbox = outbox;
30187
30614
  }
30188
30615
  connect = (socket) => {
30189
30616
  this.#connection = new ConnectedDaemonSessionEventState(socket);
30190
- this.#inFlightEventIds.clear();
30617
+ this.#clearInFlight();
30191
30618
  this.#publishNextBatch();
30192
30619
  };
30193
30620
  disconnect = (socket) => {
@@ -30195,10 +30622,15 @@ var DaemonSessionEventPublisher = class {
30195
30622
  return;
30196
30623
  }
30197
30624
  this.#connection = this.#connection.disconnect(socket);
30198
- this.#inFlightEventIds.clear();
30625
+ this.#clearInFlight();
30199
30626
  };
30200
30627
  recordAttempt = (sessionId, payload, attemptId) => {
30201
- this.#outbox.enqueue(sessionId, payload, attemptId);
30628
+ const kind = decodeMessageKind(payload);
30629
+ if (kind === SESSION_COMPLETED_KIND || kind === SESSION_FAILED_KIND) {
30630
+ this.#outbox.enqueueCritical(sessionId, payload, attemptId);
30631
+ } else {
30632
+ this.#outbox.enqueue(sessionId, payload, attemptId);
30633
+ }
30202
30634
  this.#publishNextBatch();
30203
30635
  };
30204
30636
  recordRuntime = (sessionId, payload) => {
@@ -30209,7 +30641,7 @@ var DaemonSessionEventPublisher = class {
30209
30641
  if (!this.#outbox.acknowledge(acknowledgement)) {
30210
30642
  return;
30211
30643
  }
30212
- this.#inFlightEventIds.delete(acknowledgement.eventId);
30644
+ this.#removeInFlight(acknowledgement.eventId);
30213
30645
  this.#publishNextBatch();
30214
30646
  };
30215
30647
  quarantine = (rejection) => {
@@ -30217,24 +30649,60 @@ var DaemonSessionEventPublisher = class {
30217
30649
  if (!quarantined) {
30218
30650
  return false;
30219
30651
  }
30220
- this.#inFlightEventIds.delete(rejection.eventId);
30652
+ this.#removeInFlight(rejection.eventId);
30221
30653
  this.#publishNextBatch();
30222
30654
  return true;
30223
30655
  };
30224
30656
  #publishNextBatch = () => {
30225
- if (this.#inFlightEventIds.size > 0) {
30226
- return;
30227
- }
30228
- const batch = this.#outbox.pendingBatch(SESSION_EVENT_REPLAY_WINDOW);
30229
- for (const encoded of batch) {
30230
- const envelope2 = decodeSessionEventEnvelope(encoded);
30231
- if (!this.#connection.send(encoded)) {
30232
- this.#inFlightEventIds.clear();
30657
+ while (this.#inFlightEvents.size < SESSION_EVENT_REPLAY_WINDOW) {
30658
+ const sourceCounts = /* @__PURE__ */ new Map();
30659
+ for (const inFlight of this.#inFlightEvents.values()) {
30660
+ sourceCounts.set(inFlight.sourceKey, (sourceCounts.get(inFlight.sourceKey) ?? 0) + 1);
30661
+ }
30662
+ const saturatedSources = [...sourceCounts.entries()].filter(([, count]) => count >= SESSION_EVENT_SOURCE_REPLAY_WINDOW).map(([sourceKey]) => sourceKey);
30663
+ const batch = this.#outbox.pendingSourceHeads(
30664
+ SESSION_EVENT_REPLAY_WINDOW - this.#inFlightEvents.size,
30665
+ [...this.#inFlightEvents.keys()],
30666
+ saturatedSources
30667
+ );
30668
+ let sent = 0;
30669
+ for (const encoded of batch) {
30670
+ const envelope2 = decodeSessionEventEnvelope(encoded);
30671
+ const sourceKey = sessionEventSourceKey(envelope2);
30672
+ const sourceCount = sourceCounts.get(sourceKey) ?? 0;
30673
+ if (sourceCount >= SESSION_EVENT_SOURCE_REPLAY_WINDOW) {
30674
+ continue;
30675
+ }
30676
+ const byteLength = new TextEncoder().encode(encoded).byteLength;
30677
+ if (this.#inFlightBytes + byteLength > SESSION_EVENT_REPLAY_BYTE_LIMIT) {
30678
+ continue;
30679
+ }
30680
+ if (!this.#connection.send(encoded)) {
30681
+ this.#clearInFlight();
30682
+ return;
30683
+ }
30684
+ this.#inFlightEvents.set(envelope2.eventId, new InFlightSessionEvent(sourceKey, byteLength));
30685
+ this.#inFlightBytes += byteLength;
30686
+ sourceCounts.set(sourceKey, sourceCount + 1);
30687
+ sent += 1;
30688
+ }
30689
+ if (sent === 0) {
30233
30690
  return;
30234
30691
  }
30235
- this.#inFlightEventIds.add(envelope2.eventId);
30236
30692
  }
30237
30693
  };
30694
+ #removeInFlight = (eventId) => {
30695
+ const inFlight = this.#inFlightEvents.get(eventId);
30696
+ if (inFlight === void 0) {
30697
+ return;
30698
+ }
30699
+ this.#inFlightEvents.delete(eventId);
30700
+ this.#inFlightBytes -= inFlight.byteLength;
30701
+ };
30702
+ #clearInFlight = () => {
30703
+ this.#inFlightEvents.clear();
30704
+ this.#inFlightBytes = 0;
30705
+ };
30238
30706
  };
30239
30707
  var CoalescingDaemonActivityPublisher = class {
30240
30708
  #pending = /* @__PURE__ */ new Map();
@@ -30486,6 +30954,9 @@ async function executeSessionConfigure(publisher, socket, command, config2, dire
30486
30954
  })
30487
30955
  );
30488
30956
  } catch (error61) {
30957
+ if (signal.aborted) {
30958
+ signal.throwIfAborted();
30959
+ }
30489
30960
  reportOperationFailure(socket, command.requestId, command.sessionId, error61);
30490
30961
  }
30491
30962
  }
@@ -30825,6 +31296,7 @@ async function publishAgentCatalogUntilAvailable(config2, diagnostics, signal, t
30825
31296
  }
30826
31297
  async function runRelayConnection(config2, directories, audit, sessions, installations, installationObserver, nativeSessions, outbox, publisher, grants, contexts, applicator, ipc, activeTurns, activeAttemptIds, connectionEpoch, diagnostics, onConnected, signal, timer) {
30827
31298
  const relayUrl = new URL(config2.relayUrl);
31299
+ relayUrl.searchParams.set("deliveryReceipts", "1");
30828
31300
  relayUrl.searchParams.set("liveness", "1");
30829
31301
  const socket = await connectRelay(relayUrl, signal);
30830
31302
  const reconnectingTurns = [...activeTurns.values()];
@@ -30873,6 +31345,207 @@ async function runRelayConnection(config2, directories, audit, sessions, install
30873
31345
  closeRelaySocket(socket, code, reason);
30874
31346
  rejectConnection(failure);
30875
31347
  };
31348
+ const processingDeliveryIds = /* @__PURE__ */ new Set();
31349
+ const processDeliveredPrompt = async (delivery) => {
31350
+ const command = decodeSessionPromptCommand(delivery.payload);
31351
+ if (command.sessionId !== delivery.sessionId) {
31352
+ throw new Error("Runtime delivery Session identity does not match its payload");
31353
+ }
31354
+ const active = activeTurns.get(command.commandId);
31355
+ if (active !== void 0) {
31356
+ await active.completion;
31357
+ return;
31358
+ }
31359
+ const receipt = outbox.claimExecution(command.commandId, command.sessionId, delivery.payload);
31360
+ if (receipt.kind === "duplicate") {
31361
+ if (receipt.state === "running") {
31362
+ reportFailure(
31363
+ publisher,
31364
+ command,
31365
+ "agent_execution_interrupted",
31366
+ "The local Agent execution was interrupted before it completed",
31367
+ receipt.attemptId
31368
+ );
31369
+ outbox.transitionExecution(command.commandId, "failed");
31370
+ return;
31371
+ }
31372
+ if (receipt.state !== "dispatching") {
31373
+ return;
31374
+ }
31375
+ }
31376
+ const turn = new ActiveDaemonTurn(command, receipt.attemptId);
31377
+ activeTurns.set(command.commandId, turn);
31378
+ if (command.disposition !== SessionPromptDisposition.Steer) {
31379
+ activeAttemptIds.set(command.sessionId, receipt.attemptId);
31380
+ }
31381
+ try {
31382
+ await executePrompt(
31383
+ outbox,
31384
+ publisher,
31385
+ command,
31386
+ config2,
31387
+ directories,
31388
+ audit,
31389
+ sessions,
31390
+ receipt.attemptId,
31391
+ timer,
31392
+ turn.signal
31393
+ );
31394
+ } finally {
31395
+ activeTurns.delete(command.commandId);
31396
+ if (activeAttemptIds.get(command.sessionId) === receipt.attemptId) {
31397
+ activeAttemptIds.delete(command.sessionId);
31398
+ }
31399
+ turn.finish();
31400
+ }
31401
+ };
31402
+ const processDeliveredPayload = async (delivery) => {
31403
+ const kind = decodeMessageKind(delivery.payload);
31404
+ if (kind === SESSION_CANCEL_KIND) {
31405
+ const cancellation = decodeSessionCancelCommand(delivery.payload);
31406
+ if (cancellation.sessionId !== delivery.sessionId) {
31407
+ throw new Error("Runtime delivery Session identity does not match its payload");
31408
+ }
31409
+ const turn = activeTurns.get(cancellation.commandId);
31410
+ if (turn === void 0 || !turn.matches(cancellation) || !turn.requestCancellation()) {
31411
+ return;
31412
+ }
31413
+ audit.record({
31414
+ commandId: cancellation.commandId,
31415
+ event: "session_cancellation_requested",
31416
+ sessionId: cancellation.sessionId
31417
+ });
31418
+ await sessions.cancelPrompt(cancellation.sessionId);
31419
+ return;
31420
+ }
31421
+ if (kind === SESSION_CONFIGURE_KIND) {
31422
+ const command = decodeSessionConfigureCommand(delivery.payload);
31423
+ if (command.sessionId !== delivery.sessionId) {
31424
+ throw new Error("Runtime delivery Session identity does not match its payload");
31425
+ }
31426
+ await executeSessionConfigure(
31427
+ publisher,
31428
+ socket,
31429
+ command,
31430
+ config2,
31431
+ directories,
31432
+ audit,
31433
+ sessions,
31434
+ connectionController.signal
31435
+ );
31436
+ return;
31437
+ }
31438
+ if (kind === SESSION_PERMISSION_RESPOND_KIND) {
31439
+ const command = decodeSessionPermissionRespondCommand(delivery.payload);
31440
+ if (command.sessionId !== delivery.sessionId) {
31441
+ throw new Error("Runtime delivery Session identity does not match its payload");
31442
+ }
31443
+ try {
31444
+ await sessions.respondPermission(command);
31445
+ audit.record({
31446
+ commandId: command.interactionId,
31447
+ event: "session_permission_resolved",
31448
+ sessionId: command.sessionId
31449
+ });
31450
+ } catch (error61) {
31451
+ reportOperationFailure(socket, command.interactionId, command.sessionId, error61);
31452
+ }
31453
+ return;
31454
+ }
31455
+ if (kind === SESSION_ELICITATION_RESPOND_KIND) {
31456
+ const command = decodeSessionElicitationRespondCommand(delivery.payload);
31457
+ if (command.sessionId !== delivery.sessionId) {
31458
+ throw new Error("Runtime delivery Session identity does not match its payload");
31459
+ }
31460
+ try {
31461
+ await sessions.respondElicitation(command);
31462
+ audit.record({
31463
+ commandId: command.interactionId,
31464
+ event: "session_elicitation_resolved",
31465
+ sessionId: command.sessionId
31466
+ });
31467
+ } catch (error61) {
31468
+ reportOperationFailure(socket, command.interactionId, command.sessionId, error61);
31469
+ }
31470
+ return;
31471
+ }
31472
+ if (kind === SESSION_PROMPT_KIND) {
31473
+ await processDeliveredPrompt(delivery);
31474
+ return;
31475
+ }
31476
+ throw new Error("Runtime delivery contains an unsupported protocol message");
31477
+ };
31478
+ const processRuntimeDelivery = (delivery, state) => {
31479
+ if (state === "processed" || processingDeliveryIds.has(delivery.deliveryId)) {
31480
+ return;
31481
+ }
31482
+ processingDeliveryIds.add(delivery.deliveryId);
31483
+ void processDeliveredPayload(delivery).then(() => {
31484
+ outbox.markRuntimeDeliveryProcessed(delivery.deliveryId, delivery.sessionId);
31485
+ }).catch((error61) => {
31486
+ if (connectionController.signal.aborted) {
31487
+ return;
31488
+ }
31489
+ console.error("Mobius daemon could not process a durable Runtime delivery", error61);
31490
+ failAndClose(
31491
+ new Error("Runtime delivery processing failed", { cause: error61 }),
31492
+ 4008,
31493
+ "Invalid Runtime delivery",
31494
+ "delivery"
31495
+ );
31496
+ }).finally(() => processingDeliveryIds.delete(delivery.deliveryId));
31497
+ };
31498
+ const receiveRuntimeDelivery = (delivery) => {
31499
+ const payloadKind = decodeMessageKind(delivery.payload);
31500
+ let payloadSessionId = "";
31501
+ if (payloadKind === SESSION_CANCEL_KIND) {
31502
+ payloadSessionId = decodeSessionCancelCommand(delivery.payload).sessionId;
31503
+ } else if (payloadKind === SESSION_CONFIGURE_KIND) {
31504
+ payloadSessionId = decodeSessionConfigureCommand(delivery.payload).sessionId;
31505
+ } else if (payloadKind === SESSION_PERMISSION_RESPOND_KIND) {
31506
+ payloadSessionId = decodeSessionPermissionRespondCommand(delivery.payload).sessionId;
31507
+ } else if (payloadKind === SESSION_ELICITATION_RESPOND_KIND) {
31508
+ payloadSessionId = decodeSessionElicitationRespondCommand(delivery.payload).sessionId;
31509
+ } else if (payloadKind === SESSION_PROMPT_KIND) {
31510
+ payloadSessionId = decodeSessionPromptCommand(delivery.payload).sessionId;
31511
+ } else {
31512
+ throw new Error("Runtime delivery contains an unsupported protocol message");
31513
+ }
31514
+ if (payloadSessionId !== delivery.sessionId) {
31515
+ throw new Error("Runtime delivery Session identity does not match its payload");
31516
+ }
31517
+ const stored = outbox.claimRuntimeDelivery(delivery);
31518
+ send(
31519
+ socket,
31520
+ encodeRuntimeDeliveryReceived({
31521
+ deliveryId: delivery.deliveryId,
31522
+ kind: RUNTIME_DELIVERY_RECEIVED_KIND,
31523
+ sessionId: delivery.sessionId
31524
+ })
31525
+ );
31526
+ processRuntimeDelivery(delivery, stored.state);
31527
+ };
31528
+ const resumeRuntimeDeliveries = () => {
31529
+ for (const stored of outbox.runtimeDeliveries()) {
31530
+ const delivery = {
31531
+ deliveryId: stored.deliveryId,
31532
+ kind: RUNTIME_DELIVERY_KIND,
31533
+ payload: stored.payload,
31534
+ sessionId: stored.sessionId
31535
+ };
31536
+ if (stored.state !== "relay_committed") {
31537
+ send(
31538
+ socket,
31539
+ encodeRuntimeDeliveryReceived({
31540
+ deliveryId: stored.deliveryId,
31541
+ kind: RUNTIME_DELIVERY_RECEIVED_KIND,
31542
+ sessionId: stored.sessionId
31543
+ })
31544
+ );
31545
+ }
31546
+ processRuntimeDelivery(delivery, stored.state);
31547
+ }
31548
+ };
30876
31549
  const connectionLiveness = new RelayConnectionLiveness(timer, {
30877
31550
  send: (message) => send(socket, message),
30878
31551
  unresponsive: (heartbeatId, timeoutMilliseconds) => {
@@ -30911,6 +31584,17 @@ async function runRelayConnection(config2, directories, audit, sessions, install
30911
31584
  }
30912
31585
  try {
30913
31586
  const kind = decodeMessageKind(encoded);
31587
+ if (kind === RUNTIME_DELIVERY_COMMITTED_KIND) {
31588
+ const committed = decodeRuntimeDeliveryCommitted(encoded);
31589
+ if (!outbox.markRuntimeDeliveryCommitted(committed.deliveryId, committed.sessionId)) {
31590
+ console.warn("Mobius daemon ignored confirmation for an unknown Runtime delivery");
31591
+ }
31592
+ return;
31593
+ }
31594
+ if (kind === RUNTIME_DELIVERY_KIND) {
31595
+ receiveRuntimeDelivery(decodeRuntimeDelivery(encoded));
31596
+ return;
31597
+ }
30914
31598
  if (kind === SESSION_EVENT_ACK_KIND) {
30915
31599
  publisher.acknowledge(decodeSessionEventAcknowledgement(encoded));
30916
31600
  return;
@@ -31347,6 +32031,10 @@ async function runRelayConnection(config2, directories, audit, sessions, install
31347
32031
  });
31348
32032
  } catch (error61) {
31349
32033
  console.error("Mobius daemon rejected a message", error61);
32034
+ if (error61 instanceof RuntimeDeliveryInboxCapacityError) {
32035
+ failAndClose(error61, 4013, "Runtime delivery queue full", "delivery_backpressure");
32036
+ return;
32037
+ }
31350
32038
  failAndClose(
31351
32039
  new Error("Relay sent an invalid protocol message", { cause: error61 }),
31352
32040
  4008,
@@ -31364,6 +32052,7 @@ async function runRelayConnection(config2, directories, audit, sessions, install
31364
32052
  return;
31365
32053
  }
31366
32054
  publisher.connect(socket);
32055
+ resumeRuntimeDeliveries();
31367
32056
  },
31368
32057
  (error61) => {
31369
32058
  if (finished) {
@@ -31583,12 +32272,14 @@ process.once("SIGTERM", () => shutdown.abort());
31583
32272
  var USAGE = `Mobius CLI
31584
32273
 
31585
32274
  Usage:
32275
+ mobius --version
31586
32276
  mobius pair --url <relay-url> --pairing <runtime-pairing-id> --code <pairing-code> [--workspace <directory>]
31587
32277
  mobius start --channel <channel-id>
31588
32278
  mobius agents [--json]
31589
32279
  mobius bot message send --target <current|alias> --text <message>
31590
32280
 
31591
32281
  Commands:
32282
+ --version Print the installed Mobius CLI version
31592
32283
  pair Pair this machine and start its local daemon
31593
32284
  start Start the local daemon for a saved channel
31594
32285
  agents Show detected, missing, and integration-ready Agents
@@ -31603,6 +32294,11 @@ async function main() {
31603
32294
  process.stdout.write(USAGE);
31604
32295
  return;
31605
32296
  }
32297
+ if (command === "--version" || command === "-v" || command === "version") {
32298
+ process.stdout.write(`${package_default.version}
32299
+ `);
32300
+ return;
32301
+ }
31606
32302
  if (command === "agents") {
31607
32303
  const arguments_ = process.argv.slice(3);
31608
32304
  if (arguments_.length > 1 || arguments_.length === 1 && arguments_[0] !== "--json") {