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