@moxt-ai/mobius 0.0.24 → 0.0.26
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/agent-catalog/publish-agent-catalog.d.ts.map +1 -1
- package/dist/agent-catalog/publish-agent-catalog.js +12 -7
- package/dist/agent-catalog/publish-agent-catalog.js.map +1 -1
- package/dist/cli.js +685 -290
- package/dist/cli.js.map +4 -4
- package/dist/config.d.ts +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +3 -3
- package/dist/config.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +746 -254
- package/dist/index.js.map +4 -4
- package/dist/network/environment-proxy.d.ts +1 -0
- package/dist/network/environment-proxy.d.ts.map +1 -1
- package/dist/network/environment-proxy.js +47 -0
- package/dist/network/environment-proxy.js.map +1 -1
- package/dist/pairing/pair-local-machine.d.ts +8 -0
- package/dist/pairing/pair-local-machine.d.ts.map +1 -1
- package/dist/pairing/pair-local-machine.js +64 -37
- package/dist/pairing/pair-local-machine.js.map +1 -1
- package/dist/prompt-artifact-resolver.d.ts.map +1 -1
- package/dist/prompt-artifact-resolver.js +11 -3
- 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 +25 -9
- package/dist/relay-connection/connect.js.map +1 -1
- package/dist/relay-connection/diagnostics.d.ts +11 -0
- package/dist/relay-connection/diagnostics.d.ts.map +1 -0
- package/dist/relay-connection/diagnostics.js +122 -0
- package/dist/relay-connection/diagnostics.js.map +1 -0
- package/dist/relay-connection/liveness.d.ts +1 -1
- package/dist/relay-connection/liveness.d.ts.map +1 -1
- package/dist/relay-connection/liveness.js +2 -1
- package/dist/relay-connection/liveness.js.map +1 -1
- package/dist/relay-connection/session-event-outbox.d.ts +2 -1
- package/dist/relay-connection/session-event-outbox.d.ts.map +1 -1
- package/dist/relay-connection/session-event-outbox.js +48 -8
- 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 +193 -149
- package/dist/run-daemon.js.map +1 -1
- package/dist/runtime.d.ts +23 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +31339 -0
- package/dist/runtime.js.map +7 -0
- package/package.json +6 -2
package/dist/index.js
CHANGED
|
@@ -20497,6 +20497,7 @@ var encode4 = (message, schema) => {
|
|
|
20497
20497
|
}
|
|
20498
20498
|
return JSON.stringify(decoded.data);
|
|
20499
20499
|
};
|
|
20500
|
+
var decodeSessionEventEnvelope = (encoded) => decode5(encoded, eventEnvelopeSchema);
|
|
20500
20501
|
var encodeSessionEventEnvelope = (message) => encode4(message, eventEnvelopeSchema);
|
|
20501
20502
|
var decodeSessionEventAcknowledgement = (encoded) => decode5(encoded, eventAcknowledgementSchema);
|
|
20502
20503
|
var decodeSessionEventRejection = (encoded) => decode5(encoded, eventRejectionSchema);
|
|
@@ -21107,9 +21108,9 @@ function readStateDirectory(environment = process.env) {
|
|
|
21107
21108
|
}
|
|
21108
21109
|
|
|
21109
21110
|
// src/config.ts
|
|
21110
|
-
function loadDefaultWorkspace() {
|
|
21111
|
-
const { MOBIUS_DEFAULT_WORKSPACE: configuredWorkspace } =
|
|
21112
|
-
return configuredWorkspace ?? join3(readStateDirectory(), "workspace");
|
|
21111
|
+
function loadDefaultWorkspace(environment = process.env) {
|
|
21112
|
+
const { MOBIUS_DEFAULT_WORKSPACE: configuredWorkspace } = environment;
|
|
21113
|
+
return configuredWorkspace ?? join3(readStateDirectory(environment), "workspace");
|
|
21113
21114
|
}
|
|
21114
21115
|
function createDaemonConfig(connection, agents = [], installableAgents = []) {
|
|
21115
21116
|
return {
|
|
@@ -22462,7 +22463,7 @@ function createWritableAcpStream(output2) {
|
|
|
22462
22463
|
if (outputFailure !== void 0) {
|
|
22463
22464
|
return Promise.reject(outputFailure);
|
|
22464
22465
|
}
|
|
22465
|
-
return new Promise((
|
|
22466
|
+
return new Promise((resolve6, reject) => {
|
|
22466
22467
|
pendingWriteFailures.add(reject);
|
|
22467
22468
|
output2.write(chunk, (error61) => {
|
|
22468
22469
|
pendingWriteFailures.delete(reject);
|
|
@@ -22475,7 +22476,7 @@ function createWritableAcpStream(output2) {
|
|
|
22475
22476
|
reject(outputFailure);
|
|
22476
22477
|
return;
|
|
22477
22478
|
}
|
|
22478
|
-
|
|
22479
|
+
resolve6();
|
|
22479
22480
|
});
|
|
22480
22481
|
});
|
|
22481
22482
|
}
|
|
@@ -22882,9 +22883,9 @@ var AcpProcessSession = class _AcpProcessSession {
|
|
|
22882
22883
|
stderr.on("data", (chunk) => {
|
|
22883
22884
|
process.stderr.write(`[${agent.id}-acp] ${chunk}`);
|
|
22884
22885
|
});
|
|
22885
|
-
this.#processExit = new Promise((
|
|
22886
|
-
this.#child.once("error",
|
|
22887
|
-
this.#child.once("exit",
|
|
22886
|
+
this.#processExit = new Promise((resolve6) => {
|
|
22887
|
+
this.#child.once("error", resolve6);
|
|
22888
|
+
this.#child.once("exit", resolve6);
|
|
22888
22889
|
});
|
|
22889
22890
|
const stream = ndJsonStream(createWritableAcpStream(stdin), readableWebStream(stdout));
|
|
22890
22891
|
this.#connection = createAcpClient(this).connect(stream);
|
|
@@ -25123,7 +25124,7 @@ function decodeResponse(encoded) {
|
|
|
25123
25124
|
}
|
|
25124
25125
|
async function requestLocalBotService(socketPath, payload, signal) {
|
|
25125
25126
|
signal.throwIfAborted();
|
|
25126
|
-
return await new Promise((
|
|
25127
|
+
return await new Promise((resolve6, reject) => {
|
|
25127
25128
|
const socket = createConnection(socketPath);
|
|
25128
25129
|
const chunks = [];
|
|
25129
25130
|
let length = 0;
|
|
@@ -25172,7 +25173,7 @@ async function requestLocalBotService(socketPath, payload, signal) {
|
|
|
25172
25173
|
finished = true;
|
|
25173
25174
|
signal.removeEventListener("abort", abort);
|
|
25174
25175
|
try {
|
|
25175
|
-
|
|
25176
|
+
resolve6(decodeResponse(Buffer.concat(chunks).toString("utf8")));
|
|
25176
25177
|
} catch (error61) {
|
|
25177
25178
|
reject(error61);
|
|
25178
25179
|
} finally {
|
|
@@ -25326,12 +25327,12 @@ var BotOutboundIpcServer = class {
|
|
|
25326
25327
|
}
|
|
25327
25328
|
});
|
|
25328
25329
|
}
|
|
25329
|
-
await new Promise((
|
|
25330
|
+
await new Promise((resolve6, reject) => {
|
|
25330
25331
|
const fail = (error61) => reject(error61);
|
|
25331
25332
|
this.#server.once("error", fail);
|
|
25332
25333
|
this.#server.listen(this.#socketPath, () => {
|
|
25333
25334
|
this.#server.removeListener("error", fail);
|
|
25334
|
-
|
|
25335
|
+
resolve6();
|
|
25335
25336
|
});
|
|
25336
25337
|
});
|
|
25337
25338
|
if (this.#usesFilesystemSocket) {
|
|
@@ -25344,10 +25345,10 @@ var BotOutboundIpcServer = class {
|
|
|
25344
25345
|
};
|
|
25345
25346
|
close = async () => {
|
|
25346
25347
|
if (this.#server.listening) {
|
|
25347
|
-
await new Promise((
|
|
25348
|
+
await new Promise((resolve6, reject) => {
|
|
25348
25349
|
this.#server.close((error61) => {
|
|
25349
25350
|
if (error61 === void 0) {
|
|
25350
|
-
|
|
25351
|
+
resolve6();
|
|
25351
25352
|
return;
|
|
25352
25353
|
}
|
|
25353
25354
|
reject(error61);
|
|
@@ -26286,7 +26287,53 @@ import { fetch as fetch2 } from "undici";
|
|
|
26286
26287
|
|
|
26287
26288
|
// src/network/environment-proxy.ts
|
|
26288
26289
|
import { EnvHttpProxyAgent } from "undici";
|
|
26290
|
+
var configuredHttpProxy = process.env["http_proxy"] ?? process.env["HTTP_PROXY"] ?? "";
|
|
26291
|
+
var configuredHttpsProxy = process.env["https_proxy"] ?? process.env["HTTPS_PROXY"] ?? configuredHttpProxy;
|
|
26289
26292
|
var environmentProxyDispatcher = new EnvHttpProxyAgent();
|
|
26293
|
+
function bypassesProxy(target) {
|
|
26294
|
+
const noProxy = process.env["no_proxy"] ?? process.env["NO_PROXY"] ?? "";
|
|
26295
|
+
if (noProxy === "*") {
|
|
26296
|
+
return true;
|
|
26297
|
+
}
|
|
26298
|
+
const hostname4 = target.hostname.replace(/^\[|\]$/gu, "").toLowerCase();
|
|
26299
|
+
const defaultPort = target.protocol === "wss:" || target.protocol === "https:" ? 443 : 80;
|
|
26300
|
+
const port = Number.parseInt(target.port, 10) || defaultPort;
|
|
26301
|
+
for (const rawEntry of noProxy.split(/[,\s]/u)) {
|
|
26302
|
+
if (rawEntry.length === 0) {
|
|
26303
|
+
continue;
|
|
26304
|
+
}
|
|
26305
|
+
const parsed = rawEntry.match(/^(.+):(\d+)$/u);
|
|
26306
|
+
const entryHostname = (parsed?.[1] ?? rawEntry).replace(/^\*?\./u, "").toLowerCase();
|
|
26307
|
+
const entryPort = parsed?.[2] === void 0 ? 0 : Number.parseInt(parsed[2], 10);
|
|
26308
|
+
if (entryPort !== 0 && entryPort !== port) {
|
|
26309
|
+
continue;
|
|
26310
|
+
}
|
|
26311
|
+
if (hostname4 === entryHostname || hostname4.endsWith(`.${entryHostname}`)) {
|
|
26312
|
+
return true;
|
|
26313
|
+
}
|
|
26314
|
+
}
|
|
26315
|
+
return false;
|
|
26316
|
+
}
|
|
26317
|
+
function sanitizedProxyOrigin(proxyUrl) {
|
|
26318
|
+
try {
|
|
26319
|
+
return new URL(proxyUrl).origin;
|
|
26320
|
+
} catch {
|
|
26321
|
+
return "configured-invalid-url";
|
|
26322
|
+
}
|
|
26323
|
+
}
|
|
26324
|
+
function describeEnvironmentProxyRoute(target) {
|
|
26325
|
+
if (bypassesProxy(target)) {
|
|
26326
|
+
return { proxyRoute: "direct" };
|
|
26327
|
+
}
|
|
26328
|
+
const proxyUrl = target.protocol === "wss:" || target.protocol === "https:" ? configuredHttpsProxy : configuredHttpProxy;
|
|
26329
|
+
if (proxyUrl.length === 0) {
|
|
26330
|
+
return { proxyRoute: "direct" };
|
|
26331
|
+
}
|
|
26332
|
+
return {
|
|
26333
|
+
proxyOrigin: sanitizedProxyOrigin(proxyUrl),
|
|
26334
|
+
proxyRoute: "proxy"
|
|
26335
|
+
};
|
|
26336
|
+
}
|
|
26290
26337
|
|
|
26291
26338
|
// src/agent-installation/managed-agent-archive.ts
|
|
26292
26339
|
var ARCHIVE_DOWNLOAD_LIMIT_BYTES = 128 * 1024 * 1024;
|
|
@@ -27270,7 +27317,9 @@ var IDENTIFIER_PATTERN6 = /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/;
|
|
|
27270
27317
|
var TOKEN_PATTERN2 = /^[a-zA-Z0-9_-]{32,256}$/;
|
|
27271
27318
|
var MAX_CONNECTION_FILE_LENGTH = 16 * 1024;
|
|
27272
27319
|
var CLAIM_RESPONSE_KEYS = ["channelId", "daemonToken", "runtimeId"];
|
|
27273
|
-
var
|
|
27320
|
+
var REDEEM_RESPONSE_KEYS = ["channelId", "runtimeCredential", "runtimeId"];
|
|
27321
|
+
var LEGACY_SAVED_CONNECTION_KEYS = ["defaultWorkspace", "channelId", "daemonToken", "relayOrigin"];
|
|
27322
|
+
var SAVED_CONNECTION_KEYS = ["defaultWorkspace", "channelId", "relayOrigin", "runtimeCredential"];
|
|
27274
27323
|
var PairingClientError = class extends Error {
|
|
27275
27324
|
code;
|
|
27276
27325
|
constructor(code, message, options = {}) {
|
|
@@ -27307,7 +27356,7 @@ function readSingleOption(arguments_, option2) {
|
|
|
27307
27356
|
function assertKnownArguments(arguments_) {
|
|
27308
27357
|
for (let index = 0; index < arguments_.length; index += 2) {
|
|
27309
27358
|
const option2 = arguments_[index];
|
|
27310
|
-
if (option2 !== "--url" && option2 !== "--code" && option2 !== "--workspace") {
|
|
27359
|
+
if (option2 !== "--url" && option2 !== "--code" && option2 !== "--pairing" && option2 !== "--workspace") {
|
|
27311
27360
|
throw new PairingClientError("invalid_arguments", `Unknown pairing option: ${option2 ?? "missing option"}`);
|
|
27312
27361
|
}
|
|
27313
27362
|
}
|
|
@@ -27347,10 +27396,17 @@ function parsePairCommand(arguments_) {
|
|
|
27347
27396
|
assertKnownArguments(arguments_);
|
|
27348
27397
|
return {
|
|
27349
27398
|
code: parsePairingCode(readSingleOption(arguments_, "--code")),
|
|
27399
|
+
pairingId: arguments_.includes("--pairing") ? validatePairingId(readSingleOption(arguments_, "--pairing")) : "",
|
|
27350
27400
|
relayOrigin: parseRelayOrigin(readSingleOption(arguments_, "--url")),
|
|
27351
27401
|
workspace: arguments_.includes("--workspace") ? readSingleOption(arguments_, "--workspace") : loadDefaultWorkspace()
|
|
27352
27402
|
};
|
|
27353
27403
|
}
|
|
27404
|
+
function validatePairingId(value) {
|
|
27405
|
+
if (!IDENTIFIER_PATTERN6.test(value)) {
|
|
27406
|
+
throw new PairingClientError("invalid_pairing_id", "The Runtime pairing ID is invalid");
|
|
27407
|
+
}
|
|
27408
|
+
return value;
|
|
27409
|
+
}
|
|
27354
27410
|
function parseChannelArgument(arguments_) {
|
|
27355
27411
|
if (arguments_.length !== 2 || arguments_[0] !== "--channel") {
|
|
27356
27412
|
throw new PairingClientError("invalid_arguments", "Usage: mobius start --channel <channel-id>");
|
|
@@ -27407,17 +27463,17 @@ function readRelayError(value) {
|
|
|
27407
27463
|
}
|
|
27408
27464
|
return new PairingClientError("pairing_failed", "The relay could not pair this machine");
|
|
27409
27465
|
}
|
|
27410
|
-
function
|
|
27411
|
-
if (!isRecord11(value) || !hasExactKeys(value,
|
|
27466
|
+
function decodePairingResponse(value, credentialField, expectedKeys) {
|
|
27467
|
+
if (!isRecord11(value) || !hasExactKeys(value, expectedKeys)) {
|
|
27412
27468
|
throw new PairingClientError("invalid_relay_response", "The relay returned an invalid pairing response");
|
|
27413
27469
|
}
|
|
27414
27470
|
const channelId = value["channelId"];
|
|
27415
|
-
const
|
|
27471
|
+
const runtimeCredential = value[credentialField];
|
|
27416
27472
|
const runtimeId = value["runtimeId"];
|
|
27417
|
-
if (typeof channelId !== "string" || !IDENTIFIER_PATTERN6.test(channelId) || typeof
|
|
27473
|
+
if (typeof channelId !== "string" || !IDENTIFIER_PATTERN6.test(channelId) || typeof runtimeCredential !== "string" || !TOKEN_PATTERN2.test(runtimeCredential) || typeof runtimeId !== "string" || !IDENTIFIER_PATTERN6.test(runtimeId)) {
|
|
27418
27474
|
throw new PairingClientError("invalid_relay_response", "The relay returned an invalid pairing response");
|
|
27419
27475
|
}
|
|
27420
|
-
return { channelId,
|
|
27476
|
+
return { channelId, runtimeCredential, runtimeId };
|
|
27421
27477
|
}
|
|
27422
27478
|
async function claimPairing(options, defaultWorkspace, localAgents, installableAgents, signal) {
|
|
27423
27479
|
const agents = localAgents.map((agent) => ({
|
|
@@ -27427,7 +27483,7 @@ async function claimPairing(options, defaultWorkspace, localAgents, installableA
|
|
|
27427
27483
|
id: agent.id,
|
|
27428
27484
|
label: agent.label
|
|
27429
27485
|
}));
|
|
27430
|
-
const endpoint = mobiusApiUrl(options.relayOrigin, "/pairings/claim");
|
|
27486
|
+
const endpoint = options.pairingId.length > 0 ? mobiusApiUrl(options.relayOrigin, `/v1/runtime-pairings/${encodeURIComponent(options.pairingId)}/redeem`) : mobiusApiUrl(options.relayOrigin, "/pairings/claim");
|
|
27431
27487
|
let response;
|
|
27432
27488
|
try {
|
|
27433
27489
|
response = await fetch3(endpoint, {
|
|
@@ -27450,10 +27506,10 @@ async function claimPairing(options, defaultWorkspace, localAgents, installableA
|
|
|
27450
27506
|
if (!response.ok) {
|
|
27451
27507
|
throw readRelayError(value);
|
|
27452
27508
|
}
|
|
27453
|
-
return
|
|
27509
|
+
return options.pairingId.length > 0 ? decodePairingResponse(value, "runtimeCredential", REDEEM_RESPONSE_KEYS) : decodePairingResponse(value, "daemonToken", CLAIM_RESPONSE_KEYS);
|
|
27454
27510
|
}
|
|
27455
|
-
async function persistConnection(channelId, relayOrigin,
|
|
27456
|
-
const connectionsDirectory = join14(readStateDirectory(), "connections");
|
|
27511
|
+
async function persistConnection(channelId, relayOrigin, runtimeCredential, defaultWorkspace, environment) {
|
|
27512
|
+
const connectionsDirectory = join14(readStateDirectory(environment), "connections");
|
|
27457
27513
|
await mkdir4(connectionsDirectory, { mode: 448, recursive: true });
|
|
27458
27514
|
const connectionPath = join14(connectionsDirectory, `${channelId}.json`);
|
|
27459
27515
|
const temporaryPath = join14(connectionsDirectory, `.${channelId}.${randomUUID3()}.tmp`);
|
|
@@ -27463,8 +27519,8 @@ async function persistConnection(channelId, relayOrigin, daemonToken2, defaultWo
|
|
|
27463
27519
|
{
|
|
27464
27520
|
defaultWorkspace,
|
|
27465
27521
|
channelId,
|
|
27466
|
-
|
|
27467
|
-
|
|
27522
|
+
relayOrigin: relayOrigin.toString(),
|
|
27523
|
+
runtimeCredential
|
|
27468
27524
|
},
|
|
27469
27525
|
null,
|
|
27470
27526
|
2
|
|
@@ -27476,25 +27532,25 @@ async function persistConnection(channelId, relayOrigin, daemonToken2, defaultWo
|
|
|
27476
27532
|
return connectionPath;
|
|
27477
27533
|
}
|
|
27478
27534
|
function decodeSavedConnection(value, expectedChannelId) {
|
|
27479
|
-
if (!isRecord11(value) || !hasExactKeys(value, SAVED_CONNECTION_KEYS)) {
|
|
27535
|
+
if (!isRecord11(value) || !hasExactKeys(value, SAVED_CONNECTION_KEYS) && !hasExactKeys(value, LEGACY_SAVED_CONNECTION_KEYS)) {
|
|
27480
27536
|
throw new PairingClientError("invalid_connection", "The saved connection is invalid");
|
|
27481
27537
|
}
|
|
27482
27538
|
const defaultWorkspace = value["defaultWorkspace"];
|
|
27483
27539
|
const channelId = value["channelId"];
|
|
27484
|
-
const
|
|
27540
|
+
const runtimeCredential = value["runtimeCredential"] ?? value["daemonToken"];
|
|
27485
27541
|
const relayOrigin = value["relayOrigin"];
|
|
27486
|
-
if (typeof defaultWorkspace !== "string" || typeof channelId !== "string" || channelId !== expectedChannelId || !IDENTIFIER_PATTERN6.test(channelId) || typeof
|
|
27542
|
+
if (typeof defaultWorkspace !== "string" || typeof channelId !== "string" || channelId !== expectedChannelId || !IDENTIFIER_PATTERN6.test(channelId) || typeof runtimeCredential !== "string" || !TOKEN_PATTERN2.test(runtimeCredential) || typeof relayOrigin !== "string") {
|
|
27487
27543
|
throw new PairingClientError("invalid_connection", "The saved connection is invalid");
|
|
27488
27544
|
}
|
|
27489
27545
|
return {
|
|
27490
27546
|
defaultWorkspace,
|
|
27491
27547
|
channelId,
|
|
27492
|
-
|
|
27493
|
-
|
|
27548
|
+
relayOrigin: parseRelayOrigin(relayOrigin),
|
|
27549
|
+
runtimeCredential
|
|
27494
27550
|
};
|
|
27495
27551
|
}
|
|
27496
|
-
async function readSavedConnection(channelId) {
|
|
27497
|
-
const connectionPath = join14(readStateDirectory(), "connections", `${channelId}.json`);
|
|
27552
|
+
async function readSavedConnection(channelId, environment) {
|
|
27553
|
+
const connectionPath = join14(readStateDirectory(environment), "connections", `${channelId}.json`);
|
|
27498
27554
|
let encoded = "";
|
|
27499
27555
|
const handle = await open4(connectionPath, "r");
|
|
27500
27556
|
try {
|
|
@@ -27516,8 +27572,8 @@ async function readSavedConnection(channelId) {
|
|
|
27516
27572
|
return {
|
|
27517
27573
|
defaultWorkspace: await resolveDefaultWorkspace(connection.defaultWorkspace),
|
|
27518
27574
|
channelId: connection.channelId,
|
|
27519
|
-
|
|
27520
|
-
|
|
27575
|
+
relayOrigin: connection.relayOrigin,
|
|
27576
|
+
runtimeCredential: connection.runtimeCredential
|
|
27521
27577
|
};
|
|
27522
27578
|
}
|
|
27523
27579
|
function assertInventoryUsable(inventory) {
|
|
@@ -27525,15 +27581,12 @@ function assertInventoryUsable(inventory) {
|
|
|
27525
27581
|
throw new PairingClientError("no_supported_agent", "No supported Agent is available for local discovery");
|
|
27526
27582
|
}
|
|
27527
27583
|
}
|
|
27528
|
-
function buildPairedDaemon(connection, connectionPath, inventory) {
|
|
27584
|
+
function buildPairedDaemon(connection, connectionPath, inventory, environment) {
|
|
27529
27585
|
assertInventoryUsable(inventory);
|
|
27530
|
-
const relayUrl = mobiusApiUrl(
|
|
27531
|
-
connection.relayOrigin,
|
|
27532
|
-
`/channels/${encodeURIComponent(connection.channelId)}/daemon`
|
|
27533
|
-
);
|
|
27586
|
+
const relayUrl = mobiusApiUrl(connection.relayOrigin, "/v1/runtimes/connect");
|
|
27534
27587
|
relayUrl.protocol = relayUrl.protocol === "https:" ? "wss:" : "ws:";
|
|
27535
|
-
relayUrl.searchParams.set("token", connection.
|
|
27536
|
-
const auditDatabasePath = join14(readStateDirectory(), "audit", `${connection.channelId}.sqlite`);
|
|
27588
|
+
relayUrl.searchParams.set("token", connection.runtimeCredential);
|
|
27589
|
+
const auditDatabasePath = join14(readStateDirectory(environment), "audit", `${connection.channelId}.sqlite`);
|
|
27537
27590
|
return {
|
|
27538
27591
|
channelUrl: new URL(`/channels/${encodeURIComponent(connection.channelId)}`, connection.relayOrigin).toString(),
|
|
27539
27592
|
config: createDaemonConfig(
|
|
@@ -27549,12 +27602,11 @@ function buildPairedDaemon(connection, connectionPath, inventory) {
|
|
|
27549
27602
|
connectionPath
|
|
27550
27603
|
};
|
|
27551
27604
|
}
|
|
27552
|
-
async function
|
|
27553
|
-
const options = parsePairCommand(arguments_);
|
|
27605
|
+
async function pairRuntime(options, signal, environment) {
|
|
27554
27606
|
const defaultWorkspace = await resolveDefaultWorkspace(options.workspace);
|
|
27555
27607
|
const inventory = await discoverLocalAgentInventory({
|
|
27556
27608
|
defaultWorkspace,
|
|
27557
|
-
environment
|
|
27609
|
+
environment,
|
|
27558
27610
|
signal
|
|
27559
27611
|
});
|
|
27560
27612
|
assertInventoryUsable(inventory);
|
|
@@ -27563,30 +27615,50 @@ async function pairLocalMachine(arguments_, signal = new AbortController().signa
|
|
|
27563
27615
|
const connectionPath = await persistConnection(
|
|
27564
27616
|
claim2.channelId,
|
|
27565
27617
|
options.relayOrigin,
|
|
27566
|
-
claim2.
|
|
27567
|
-
defaultWorkspace
|
|
27618
|
+
claim2.runtimeCredential,
|
|
27619
|
+
defaultWorkspace,
|
|
27620
|
+
environment
|
|
27568
27621
|
);
|
|
27569
27622
|
return buildPairedDaemon(
|
|
27570
27623
|
{
|
|
27571
27624
|
defaultWorkspace,
|
|
27572
27625
|
channelId: claim2.channelId,
|
|
27573
|
-
|
|
27574
|
-
|
|
27626
|
+
relayOrigin: options.relayOrigin,
|
|
27627
|
+
runtimeCredential: claim2.runtimeCredential
|
|
27575
27628
|
},
|
|
27576
27629
|
connectionPath,
|
|
27577
|
-
inventory
|
|
27630
|
+
inventory,
|
|
27631
|
+
environment
|
|
27578
27632
|
);
|
|
27579
27633
|
}
|
|
27580
|
-
async function
|
|
27581
|
-
|
|
27582
|
-
|
|
27583
|
-
|
|
27634
|
+
async function pairMobiusRuntime(options, signal, environment = process.env) {
|
|
27635
|
+
return await pairRuntime(
|
|
27636
|
+
{
|
|
27637
|
+
code: parsePairingCode(options.pairingCode),
|
|
27638
|
+
pairingId: validatePairingId(options.pairingId),
|
|
27639
|
+
relayOrigin: parseRelayOrigin(options.relayOrigin),
|
|
27640
|
+
workspace: options.defaultWorkspace
|
|
27641
|
+
},
|
|
27642
|
+
signal,
|
|
27643
|
+
environment
|
|
27644
|
+
);
|
|
27645
|
+
}
|
|
27646
|
+
async function pairLocalMachine(arguments_, signal = new AbortController().signal) {
|
|
27647
|
+
return await pairRuntime(parsePairCommand(arguments_), signal, process.env);
|
|
27648
|
+
}
|
|
27649
|
+
async function resumeMobiusRuntime(channelId, signal, environment = process.env) {
|
|
27650
|
+
const normalizedChannelId = validatePairingId(channelId);
|
|
27651
|
+
const connectionPath = join14(readStateDirectory(environment), "connections", `${normalizedChannelId}.json`);
|
|
27652
|
+
const connection = await readSavedConnection(normalizedChannelId, environment);
|
|
27584
27653
|
const inventory = await discoverLocalAgentInventory({
|
|
27585
27654
|
defaultWorkspace: connection.defaultWorkspace,
|
|
27586
|
-
environment
|
|
27655
|
+
environment,
|
|
27587
27656
|
signal
|
|
27588
27657
|
});
|
|
27589
|
-
return buildPairedDaemon(connection, connectionPath, inventory);
|
|
27658
|
+
return buildPairedDaemon(connection, connectionPath, inventory, environment);
|
|
27659
|
+
}
|
|
27660
|
+
async function resumeLocalMachine(arguments_, signal = new AbortController().signal) {
|
|
27661
|
+
return await resumeMobiusRuntime(parseChannelArgument(arguments_), signal, process.env);
|
|
27590
27662
|
}
|
|
27591
27663
|
|
|
27592
27664
|
// src/run-daemon.ts
|
|
@@ -27605,14 +27677,19 @@ var AgentCatalogPublishError = class extends Error {
|
|
|
27605
27677
|
this.name = "AgentCatalogPublishError";
|
|
27606
27678
|
}
|
|
27607
27679
|
};
|
|
27608
|
-
function catalogEndpoint(
|
|
27609
|
-
const endpoint = new URL(relayUrl);
|
|
27680
|
+
function catalogEndpoint(config2) {
|
|
27681
|
+
const endpoint = new URL(config2.relayUrl);
|
|
27610
27682
|
endpoint.protocol = endpoint.protocol === "wss:" ? "https:" : "http:";
|
|
27611
|
-
if (
|
|
27612
|
-
|
|
27683
|
+
if (endpoint.pathname.endsWith("/daemon")) {
|
|
27684
|
+
endpoint.pathname = `${endpoint.pathname.slice(0, -"/daemon".length)}/catalog`;
|
|
27685
|
+
return endpoint;
|
|
27613
27686
|
}
|
|
27614
|
-
|
|
27615
|
-
|
|
27687
|
+
const runtimePath = "/v1/runtimes/connect";
|
|
27688
|
+
if (endpoint.pathname.endsWith(runtimePath)) {
|
|
27689
|
+
endpoint.pathname = `${endpoint.pathname.slice(0, -runtimePath.length)}/channels/${encodeURIComponent(config2.channelId)}/catalog`;
|
|
27690
|
+
return endpoint;
|
|
27691
|
+
}
|
|
27692
|
+
throw new AgentCatalogPublishError("The Relay URL is invalid");
|
|
27616
27693
|
}
|
|
27617
27694
|
async function publishAgentCatalog(config2, signal) {
|
|
27618
27695
|
signal.throwIfAborted();
|
|
@@ -27621,7 +27698,7 @@ async function publishAgentCatalog(config2, signal) {
|
|
|
27621
27698
|
let response;
|
|
27622
27699
|
const catalog = config2.catalog.read();
|
|
27623
27700
|
try {
|
|
27624
|
-
response = await fetch4(catalogEndpoint(config2
|
|
27701
|
+
response = await fetch4(catalogEndpoint(config2), {
|
|
27625
27702
|
body: JSON.stringify({
|
|
27626
27703
|
agents: catalog.agents.map((agent) => ({
|
|
27627
27704
|
agentPath: agent.agentIdentity.requestedPath,
|
|
@@ -28991,10 +29068,17 @@ function parseReference(resource) {
|
|
|
28991
29068
|
function downloadUrl(config2, command, reference) {
|
|
28992
29069
|
const url2 = new URL(config2.relayUrl);
|
|
28993
29070
|
url2.protocol = url2.protocol === "wss:" ? "https:" : "http:";
|
|
28994
|
-
|
|
28995
|
-
|
|
29071
|
+
let channelPath = "";
|
|
29072
|
+
if (url2.pathname.endsWith("/daemon")) {
|
|
29073
|
+
channelPath = url2.pathname.slice(0, -"/daemon".length);
|
|
29074
|
+
} else {
|
|
29075
|
+
const runtimePath = "/v1/runtimes/connect";
|
|
29076
|
+
if (!url2.pathname.endsWith(runtimePath)) {
|
|
29077
|
+
throw new PromptArtifactError("artifact_endpoint_invalid", "The Relay artifact endpoint is invalid");
|
|
29078
|
+
}
|
|
29079
|
+
channelPath = `${url2.pathname.slice(0, -runtimePath.length)}/channels/${encodeURIComponent(config2.channelId)}`;
|
|
28996
29080
|
}
|
|
28997
|
-
url2.pathname = `${
|
|
29081
|
+
url2.pathname = `${channelPath}/sessions/${encodeURIComponent(command.sessionId)}/commands/${encodeURIComponent(command.commandId)}/artifacts/${encodeURIComponent(reference.artifactId)}/content`;
|
|
28998
29082
|
url2.searchParams.delete("liveness");
|
|
28999
29083
|
return url2;
|
|
29000
29084
|
}
|
|
@@ -29144,17 +29228,27 @@ import { WebSocket } from "undici";
|
|
|
29144
29228
|
var CONNECTION_TIMEOUT_MILLISECONDS = 15e3;
|
|
29145
29229
|
var RelayConnectionError = class extends Error {
|
|
29146
29230
|
code;
|
|
29147
|
-
|
|
29231
|
+
diagnosticDetails;
|
|
29232
|
+
constructor(code, message, diagnosticDetails = {}, options = {}) {
|
|
29148
29233
|
super(message, options);
|
|
29149
29234
|
this.code = code;
|
|
29235
|
+
this.diagnosticDetails = diagnosticDetails;
|
|
29150
29236
|
this.name = "RelayConnectionError";
|
|
29151
29237
|
}
|
|
29152
29238
|
};
|
|
29153
29239
|
function connectRelay(url2, signal) {
|
|
29154
29240
|
signal.throwIfAborted();
|
|
29155
|
-
return new Promise((
|
|
29156
|
-
const
|
|
29157
|
-
|
|
29241
|
+
return new Promise((resolve6, reject) => {
|
|
29242
|
+
const endpoint = new URL(url2);
|
|
29243
|
+
const headers = {};
|
|
29244
|
+
if (endpoint.pathname.endsWith("/v1/runtimes/connect")) {
|
|
29245
|
+
const runtimeCredential = endpoint.searchParams.get("token") ?? "";
|
|
29246
|
+
endpoint.searchParams.delete("token");
|
|
29247
|
+
headers["authorization"] = `Bearer ${runtimeCredential}`;
|
|
29248
|
+
}
|
|
29249
|
+
const socket = new WebSocket(endpoint, {
|
|
29250
|
+
dispatcher: environmentProxyDispatcher,
|
|
29251
|
+
headers
|
|
29158
29252
|
});
|
|
29159
29253
|
let finished = false;
|
|
29160
29254
|
const timeout = setTimeout(onTimeout, CONNECTION_TIMEOUT_MILLISECONDS);
|
|
@@ -29176,16 +29270,34 @@ function connectRelay(url2, signal) {
|
|
|
29176
29270
|
};
|
|
29177
29271
|
const onAbort = () => {
|
|
29178
29272
|
fail(
|
|
29179
|
-
new RelayConnectionError(
|
|
29180
|
-
|
|
29181
|
-
|
|
29273
|
+
new RelayConnectionError(
|
|
29274
|
+
"relay_connection_cancelled",
|
|
29275
|
+
"Relay connection was cancelled",
|
|
29276
|
+
{
|
|
29277
|
+
cancellation: "requested"
|
|
29278
|
+
},
|
|
29279
|
+
{ cause: signal.reason }
|
|
29280
|
+
)
|
|
29182
29281
|
);
|
|
29183
29282
|
};
|
|
29184
|
-
const onClose = () => {
|
|
29185
|
-
fail(
|
|
29283
|
+
const onClose = (event) => {
|
|
29284
|
+
fail(
|
|
29285
|
+
new RelayConnectionError("relay_connection_closed", "Relay connection closed before it was ready", {
|
|
29286
|
+
closeCode: event.code.toString(),
|
|
29287
|
+
closeReason: event.reason
|
|
29288
|
+
})
|
|
29289
|
+
);
|
|
29186
29290
|
};
|
|
29187
|
-
const onError = () => {
|
|
29188
|
-
|
|
29291
|
+
const onError = (event) => {
|
|
29292
|
+
const cause = Reflect.get(event, "error");
|
|
29293
|
+
fail(
|
|
29294
|
+
new RelayConnectionError(
|
|
29295
|
+
"relay_connection_failed",
|
|
29296
|
+
"Relay connection failed",
|
|
29297
|
+
{},
|
|
29298
|
+
{ cause: cause ?? event }
|
|
29299
|
+
)
|
|
29300
|
+
);
|
|
29189
29301
|
};
|
|
29190
29302
|
const onOpen = () => {
|
|
29191
29303
|
if (finished) {
|
|
@@ -29193,10 +29305,14 @@ function connectRelay(url2, signal) {
|
|
|
29193
29305
|
}
|
|
29194
29306
|
finished = true;
|
|
29195
29307
|
cleanup();
|
|
29196
|
-
|
|
29308
|
+
resolve6(socket);
|
|
29197
29309
|
};
|
|
29198
29310
|
function onTimeout() {
|
|
29199
|
-
fail(
|
|
29311
|
+
fail(
|
|
29312
|
+
new RelayConnectionError("relay_connection_timeout", "Relay connection timed out", {
|
|
29313
|
+
timeoutMilliseconds: CONNECTION_TIMEOUT_MILLISECONDS.toString()
|
|
29314
|
+
})
|
|
29315
|
+
);
|
|
29200
29316
|
}
|
|
29201
29317
|
signal.addEventListener("abort", onAbort, { once: true });
|
|
29202
29318
|
socket.addEventListener("close", onClose, { once: true });
|
|
@@ -29208,6 +29324,142 @@ function connectRelay(url2, signal) {
|
|
|
29208
29324
|
});
|
|
29209
29325
|
}
|
|
29210
29326
|
|
|
29327
|
+
// src/relay-connection/diagnostics.ts
|
|
29328
|
+
var MAX_DIAGNOSTIC_TEXT_LENGTH = 256;
|
|
29329
|
+
function sanitizeDiagnosticText(value) {
|
|
29330
|
+
const printable = Array.from(value, (character) => {
|
|
29331
|
+
const code = character.charCodeAt(0);
|
|
29332
|
+
return code < 32 || code === 127 ? " " : character;
|
|
29333
|
+
}).join("");
|
|
29334
|
+
const withoutSecrets = printable.replace(/([?&](?:access_token|authorization|credential|key|secret|token)=)[^&\s]*/giu, "$1[redacted]").replace(/(?:https?|wss?):\/\/[^\s)]+/giu, (encodedUrl) => {
|
|
29335
|
+
try {
|
|
29336
|
+
return new URL(encodedUrl).origin;
|
|
29337
|
+
} catch {
|
|
29338
|
+
return "[redacted-url]";
|
|
29339
|
+
}
|
|
29340
|
+
});
|
|
29341
|
+
return withoutSecrets.slice(0, MAX_DIAGNOSTIC_TEXT_LENGTH);
|
|
29342
|
+
}
|
|
29343
|
+
function addFailureDetails(details, failure) {
|
|
29344
|
+
let current = failure;
|
|
29345
|
+
for (let depth = 0; depth < 3 && current instanceof Error; depth += 1) {
|
|
29346
|
+
const prefix = depth === 0 ? "failure" : `cause${depth.toString()}`;
|
|
29347
|
+
details[`${prefix}Name`] = current.name;
|
|
29348
|
+
details[`${prefix}Message`] = sanitizeDiagnosticText(current.message);
|
|
29349
|
+
const code = Reflect.get(current, "code");
|
|
29350
|
+
if (typeof code === "string" || typeof code === "number") {
|
|
29351
|
+
details[`${prefix}Code`] = String(code);
|
|
29352
|
+
}
|
|
29353
|
+
const statusCode = Reflect.get(current, "statusCode");
|
|
29354
|
+
if (typeof statusCode === "string" || typeof statusCode === "number") {
|
|
29355
|
+
details[`${prefix}StatusCode`] = String(statusCode);
|
|
29356
|
+
}
|
|
29357
|
+
const diagnosticDetails = Reflect.get(current, "diagnosticDetails");
|
|
29358
|
+
if (typeof diagnosticDetails === "object" && diagnosticDetails !== null) {
|
|
29359
|
+
for (const [key, value] of Object.entries(diagnosticDetails)) {
|
|
29360
|
+
if (typeof value === "string") {
|
|
29361
|
+
details[key] = sanitizeDiagnosticText(value);
|
|
29362
|
+
}
|
|
29363
|
+
}
|
|
29364
|
+
}
|
|
29365
|
+
current = current.cause;
|
|
29366
|
+
}
|
|
29367
|
+
}
|
|
29368
|
+
var RelayConnectionDiagnostics = class {
|
|
29369
|
+
#audit;
|
|
29370
|
+
#channelId;
|
|
29371
|
+
#lastClosedEpoch = 0;
|
|
29372
|
+
#lastFailedEpoch = 0;
|
|
29373
|
+
#relayOrigin;
|
|
29374
|
+
#route;
|
|
29375
|
+
constructor(audit, channelId, relayUrl) {
|
|
29376
|
+
this.#audit = audit;
|
|
29377
|
+
this.#channelId = channelId;
|
|
29378
|
+
this.#relayOrigin = relayUrl.origin;
|
|
29379
|
+
this.#route = describeEnvironmentProxyRoute(relayUrl);
|
|
29380
|
+
}
|
|
29381
|
+
catalogFailed = (failure) => {
|
|
29382
|
+
const details = { ...this.#route, relayOrigin: this.#relayOrigin };
|
|
29383
|
+
addFailureDetails(details, failure);
|
|
29384
|
+
this.#record("agent_catalog_publish_failed", "catalog", details, true);
|
|
29385
|
+
};
|
|
29386
|
+
connectionClosed = (connectionEpoch, code, reason, source) => {
|
|
29387
|
+
if (this.#lastClosedEpoch === connectionEpoch) {
|
|
29388
|
+
return;
|
|
29389
|
+
}
|
|
29390
|
+
this.#lastClosedEpoch = connectionEpoch;
|
|
29391
|
+
this.#record(
|
|
29392
|
+
"relay_connection_closed",
|
|
29393
|
+
connectionEpoch.toString(),
|
|
29394
|
+
{
|
|
29395
|
+
closeCode: code.toString(),
|
|
29396
|
+
closeReason: sanitizeDiagnosticText(reason),
|
|
29397
|
+
connectionEpoch: connectionEpoch.toString(),
|
|
29398
|
+
relayOrigin: this.#relayOrigin,
|
|
29399
|
+
source,
|
|
29400
|
+
...this.#route
|
|
29401
|
+
},
|
|
29402
|
+
true
|
|
29403
|
+
);
|
|
29404
|
+
};
|
|
29405
|
+
connectionFailed = (connectionEpoch, failure, source) => {
|
|
29406
|
+
if (this.#lastFailedEpoch === connectionEpoch) {
|
|
29407
|
+
return;
|
|
29408
|
+
}
|
|
29409
|
+
this.#lastFailedEpoch = connectionEpoch;
|
|
29410
|
+
const details = {
|
|
29411
|
+
connectionEpoch: connectionEpoch.toString(),
|
|
29412
|
+
relayOrigin: this.#relayOrigin,
|
|
29413
|
+
source,
|
|
29414
|
+
...this.#route
|
|
29415
|
+
};
|
|
29416
|
+
addFailureDetails(details, failure);
|
|
29417
|
+
this.#record("relay_connection_failed", connectionEpoch.toString(), details, true);
|
|
29418
|
+
};
|
|
29419
|
+
connectionOpened = (connectionEpoch) => {
|
|
29420
|
+
this.#record(
|
|
29421
|
+
"relay_connection_opened",
|
|
29422
|
+
connectionEpoch.toString(),
|
|
29423
|
+
{
|
|
29424
|
+
connectionEpoch: connectionEpoch.toString(),
|
|
29425
|
+
relayOrigin: this.#relayOrigin,
|
|
29426
|
+
...this.#route
|
|
29427
|
+
},
|
|
29428
|
+
false
|
|
29429
|
+
);
|
|
29430
|
+
};
|
|
29431
|
+
heartbeatTimedOut = (connectionEpoch, heartbeatId, timeoutMilliseconds) => {
|
|
29432
|
+
this.#record(
|
|
29433
|
+
"relay_heartbeat_timed_out",
|
|
29434
|
+
connectionEpoch.toString(),
|
|
29435
|
+
{
|
|
29436
|
+
connectionEpoch: connectionEpoch.toString(),
|
|
29437
|
+
heartbeatId,
|
|
29438
|
+
relayOrigin: this.#relayOrigin,
|
|
29439
|
+
timeoutMilliseconds: timeoutMilliseconds.toString(),
|
|
29440
|
+
...this.#route
|
|
29441
|
+
},
|
|
29442
|
+
true
|
|
29443
|
+
);
|
|
29444
|
+
};
|
|
29445
|
+
#record = (event, commandId, details, warning) => {
|
|
29446
|
+
this.#audit.record({
|
|
29447
|
+
commandId,
|
|
29448
|
+
details,
|
|
29449
|
+
event,
|
|
29450
|
+
sessionId: this.#channelId
|
|
29451
|
+
});
|
|
29452
|
+
const encoded = JSON.stringify({ channelId: this.#channelId, event, ...details });
|
|
29453
|
+
if (warning) {
|
|
29454
|
+
process.stderr.write(`Mobius relay diagnostic ${encoded}
|
|
29455
|
+
`);
|
|
29456
|
+
return;
|
|
29457
|
+
}
|
|
29458
|
+
process.stdout.write(`Mobius relay diagnostic ${encoded}
|
|
29459
|
+
`);
|
|
29460
|
+
};
|
|
29461
|
+
};
|
|
29462
|
+
|
|
29211
29463
|
// src/relay-connection/liveness.ts
|
|
29212
29464
|
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
29213
29465
|
var HEARTBEAT_ACK_TIMEOUT_MILLISECONDS = 1e4;
|
|
@@ -29284,9 +29536,10 @@ var RelayConnectionLiveness = class {
|
|
|
29284
29536
|
if (!(this.#state instanceof AwaitingHeartbeatAckState)) {
|
|
29285
29537
|
throw new Error("Heartbeat timeout occurred in an invalid state");
|
|
29286
29538
|
}
|
|
29539
|
+
const heartbeatId = this.#state.heartbeatId;
|
|
29287
29540
|
this.#state.timeout.cancel();
|
|
29288
29541
|
this.#state = new FinishedRelayLivenessState();
|
|
29289
|
-
this.#transport.unresponsive();
|
|
29542
|
+
this.#transport.unresponsive(heartbeatId, HEARTBEAT_ACK_TIMEOUT_MILLISECONDS);
|
|
29290
29543
|
};
|
|
29291
29544
|
#sendHeartbeat = () => {
|
|
29292
29545
|
if (this.#state instanceof WaitingForHeartbeatState) {
|
|
@@ -29335,6 +29588,7 @@ var SessionEventOutbox = class {
|
|
|
29335
29588
|
ordinal INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
29336
29589
|
event_id TEXT NOT NULL UNIQUE,
|
|
29337
29590
|
session_id TEXT NOT NULL,
|
|
29591
|
+
source_key TEXT NOT NULL,
|
|
29338
29592
|
envelope_json TEXT NOT NULL
|
|
29339
29593
|
) STRICT;
|
|
29340
29594
|
CREATE INDEX IF NOT EXISTS relay_session_event_outbox_order
|
|
@@ -29362,6 +29616,27 @@ var SessionEventOutbox = class {
|
|
|
29362
29616
|
)
|
|
29363
29617
|
) STRICT;
|
|
29364
29618
|
`);
|
|
29619
|
+
const outboxColumns = this.#database.prepare("PRAGMA table_info(relay_session_event_outbox)").all();
|
|
29620
|
+
const hasSourceKey = outboxColumns.some(
|
|
29621
|
+
(column) => typeof column === "object" && column !== null && Reflect.get(column, "name") === "source_key"
|
|
29622
|
+
);
|
|
29623
|
+
if (!hasSourceKey) {
|
|
29624
|
+
this.#database.exec(`
|
|
29625
|
+
ALTER TABLE relay_session_event_outbox
|
|
29626
|
+
ADD COLUMN source_key TEXT NOT NULL DEFAULT '';
|
|
29627
|
+
`);
|
|
29628
|
+
}
|
|
29629
|
+
this.#database.exec(`
|
|
29630
|
+
UPDATE relay_session_event_outbox
|
|
29631
|
+
SET source_key = CASE json_extract(envelope_json, '$.source.kind')
|
|
29632
|
+
WHEN 'attempt' THEN
|
|
29633
|
+
'attempt:' || session_id || ':' || json_extract(envelope_json, '$.source.attemptId')
|
|
29634
|
+
ELSE 'runtime:' || session_id
|
|
29635
|
+
END
|
|
29636
|
+
WHERE source_key = '';
|
|
29637
|
+
CREATE INDEX IF NOT EXISTS relay_session_event_outbox_source_order
|
|
29638
|
+
ON relay_session_event_outbox(source_key, ordinal);
|
|
29639
|
+
`);
|
|
29365
29640
|
}
|
|
29366
29641
|
claimExecution = (commandId, sessionId, commandJson) => {
|
|
29367
29642
|
this.#database.exec("BEGIN IMMEDIATE");
|
|
@@ -29419,12 +29694,10 @@ var SessionEventOutbox = class {
|
|
|
29419
29694
|
const state = typeof row === "object" && row !== null ? Reflect.get(row, "state") : void 0;
|
|
29420
29695
|
return state === "succeeded" || state === "failed" || state === "cancelled";
|
|
29421
29696
|
};
|
|
29422
|
-
acknowledge = (acknowledgement) =>
|
|
29423
|
-
|
|
29424
|
-
`DELETE FROM relay_session_event_outbox
|
|
29697
|
+
acknowledge = (acknowledgement) => this.#database.prepare(
|
|
29698
|
+
`DELETE FROM relay_session_event_outbox
|
|
29425
29699
|
WHERE event_id = ? AND session_id = ?`
|
|
29426
|
-
|
|
29427
|
-
};
|
|
29700
|
+
).run(acknowledgement.eventId, acknowledgement.sessionId).changes === 1;
|
|
29428
29701
|
quarantine = (rejection) => {
|
|
29429
29702
|
this.#database.exec("BEGIN IMMEDIATE");
|
|
29430
29703
|
try {
|
|
@@ -29491,9 +29764,9 @@ var SessionEventOutbox = class {
|
|
|
29491
29764
|
).run(sourceKey, nextSourceSeq + 1);
|
|
29492
29765
|
this.#database.prepare(
|
|
29493
29766
|
`INSERT INTO relay_session_event_outbox (
|
|
29494
|
-
event_id, session_id, envelope_json
|
|
29495
|
-
) VALUES (?, ?, ?)`
|
|
29496
|
-
).run(envelope2.eventId, envelope2.sessionId, encoded);
|
|
29767
|
+
event_id, session_id, source_key, envelope_json
|
|
29768
|
+
) VALUES (?, ?, ?, ?)`
|
|
29769
|
+
).run(envelope2.eventId, envelope2.sessionId, sourceKey, encoded);
|
|
29497
29770
|
this.#database.exec("COMMIT");
|
|
29498
29771
|
return encoded;
|
|
29499
29772
|
} catch (error61) {
|
|
@@ -29506,6 +29779,27 @@ var SessionEventOutbox = class {
|
|
|
29506
29779
|
FROM relay_session_event_outbox
|
|
29507
29780
|
ORDER BY ordinal`
|
|
29508
29781
|
).all().map(readPendingEnvelope);
|
|
29782
|
+
pendingBatch = (limit) => {
|
|
29783
|
+
if (!Number.isSafeInteger(limit) || limit < 1) {
|
|
29784
|
+
throw new Error("Session event replay batch limit must be a positive integer");
|
|
29785
|
+
}
|
|
29786
|
+
return this.#database.prepare(
|
|
29787
|
+
`WITH ranked_events AS (
|
|
29788
|
+
SELECT ordinal,
|
|
29789
|
+
ROW_NUMBER() OVER (
|
|
29790
|
+
PARTITION BY source_key
|
|
29791
|
+
ORDER BY ordinal
|
|
29792
|
+
) AS source_position
|
|
29793
|
+
FROM relay_session_event_outbox
|
|
29794
|
+
)
|
|
29795
|
+
SELECT outbox.envelope_json
|
|
29796
|
+
FROM ranked_events AS ranked
|
|
29797
|
+
INNER JOIN relay_session_event_outbox AS outbox
|
|
29798
|
+
ON outbox.ordinal = ranked.ordinal
|
|
29799
|
+
ORDER BY ranked.source_position, outbox.ordinal
|
|
29800
|
+
LIMIT ?`
|
|
29801
|
+
).all(limit).map(readPendingEnvelope);
|
|
29802
|
+
};
|
|
29509
29803
|
};
|
|
29510
29804
|
function isDaemonExecutionState(value) {
|
|
29511
29805
|
return value === "cancelled" || value === "dispatching" || value === "failed" || value === "running" || value === "succeeded";
|
|
@@ -29522,7 +29816,7 @@ var systemDaemonTimer = new SystemDaemonTimer();
|
|
|
29522
29816
|
|
|
29523
29817
|
// src/run-daemon.ts
|
|
29524
29818
|
var RELAY_RECONNECT_DELAY_MILLISECONDS = 500;
|
|
29525
|
-
var
|
|
29819
|
+
var AGENT_ACTIVITY_COALESCING_MILLISECONDS = 100;
|
|
29526
29820
|
var ACTIVE_TURN_RECONCILIATION_TIMEOUT_MILLISECONDS = 2e4;
|
|
29527
29821
|
var ACTIVE_TURN_RECONCILIATION_CLOSE_CODE = 4009;
|
|
29528
29822
|
function botIpcSocketPath() {
|
|
@@ -29531,54 +29825,6 @@ function botIpcSocketPath() {
|
|
|
29531
29825
|
}
|
|
29532
29826
|
return join16("/tmp", `mobius-bot-${randomUUID6()}.sock`);
|
|
29533
29827
|
}
|
|
29534
|
-
var RelayConnectionRefreshState = class {
|
|
29535
|
-
};
|
|
29536
|
-
var ScheduledRelayConnectionRefreshState = class extends RelayConnectionRefreshState {
|
|
29537
|
-
};
|
|
29538
|
-
var DueRelayConnectionRefreshState = class extends RelayConnectionRefreshState {
|
|
29539
|
-
};
|
|
29540
|
-
var FinishedRelayConnectionRefreshState = class extends RelayConnectionRefreshState {
|
|
29541
|
-
};
|
|
29542
|
-
var RelayConnectionRefresh = class {
|
|
29543
|
-
#isSafe;
|
|
29544
|
-
#refresh;
|
|
29545
|
-
#scheduledTask;
|
|
29546
|
-
#state = new ScheduledRelayConnectionRefreshState();
|
|
29547
|
-
constructor(timer, isSafe, refresh) {
|
|
29548
|
-
this.#isSafe = isSafe;
|
|
29549
|
-
this.#refresh = refresh;
|
|
29550
|
-
this.#scheduledTask = timer.schedule(this.#request, RELAY_CONNECTION_REFRESH_MILLISECONDS);
|
|
29551
|
-
}
|
|
29552
|
-
afterTurnFinished = () => {
|
|
29553
|
-
if (this.#state instanceof DueRelayConnectionRefreshState) {
|
|
29554
|
-
this.#request();
|
|
29555
|
-
return;
|
|
29556
|
-
}
|
|
29557
|
-
if (this.#state instanceof ScheduledRelayConnectionRefreshState || this.#state instanceof FinishedRelayConnectionRefreshState) {
|
|
29558
|
-
return;
|
|
29559
|
-
}
|
|
29560
|
-
throw new Error("Unknown relay connection refresh state");
|
|
29561
|
-
};
|
|
29562
|
-
close = () => {
|
|
29563
|
-
this.#scheduledTask.cancel();
|
|
29564
|
-
this.#state = new FinishedRelayConnectionRefreshState();
|
|
29565
|
-
};
|
|
29566
|
-
#request = () => {
|
|
29567
|
-
if (this.#state instanceof FinishedRelayConnectionRefreshState) {
|
|
29568
|
-
return;
|
|
29569
|
-
}
|
|
29570
|
-
if (!(this.#state instanceof ScheduledRelayConnectionRefreshState) && !(this.#state instanceof DueRelayConnectionRefreshState)) {
|
|
29571
|
-
throw new Error("Unknown relay connection refresh state");
|
|
29572
|
-
}
|
|
29573
|
-
if (!this.#isSafe()) {
|
|
29574
|
-
this.#state = new DueRelayConnectionRefreshState();
|
|
29575
|
-
return;
|
|
29576
|
-
}
|
|
29577
|
-
this.#state = new FinishedRelayConnectionRefreshState();
|
|
29578
|
-
this.#scheduledTask.cancel();
|
|
29579
|
-
this.#refresh();
|
|
29580
|
-
};
|
|
29581
|
-
};
|
|
29582
29828
|
var DaemonAcpObserver = class {
|
|
29583
29829
|
#record;
|
|
29584
29830
|
constructor(record2) {
|
|
@@ -29775,10 +30021,17 @@ var ActiveTurnReconciliationError = class extends Error {
|
|
|
29775
30021
|
function activeTurnReconciliationEndpoint(config2, turn) {
|
|
29776
30022
|
const endpoint = new URL(config2.relayUrl);
|
|
29777
30023
|
endpoint.protocol = endpoint.protocol === "wss:" ? "https:" : "http:";
|
|
29778
|
-
|
|
29779
|
-
|
|
30024
|
+
let channelPath = "";
|
|
30025
|
+
if (endpoint.pathname.endsWith("/daemon")) {
|
|
30026
|
+
channelPath = endpoint.pathname.slice(0, -"/daemon".length);
|
|
30027
|
+
} else {
|
|
30028
|
+
const runtimePath = "/v1/runtimes/connect";
|
|
30029
|
+
if (!endpoint.pathname.endsWith(runtimePath)) {
|
|
30030
|
+
throw new ActiveTurnReconciliationError("The Relay URL is invalid");
|
|
30031
|
+
}
|
|
30032
|
+
channelPath = `${endpoint.pathname.slice(0, -runtimePath.length)}/channels/${encodeURIComponent(config2.channelId)}`;
|
|
29780
30033
|
}
|
|
29781
|
-
endpoint.pathname = `${
|
|
30034
|
+
endpoint.pathname = `${channelPath}/sessions/${encodeURIComponent(turn.command.sessionId)}/attempts/${encodeURIComponent(turn.attemptId)}/reconciliation`;
|
|
29782
30035
|
endpoint.searchParams.delete("liveness");
|
|
29783
30036
|
return endpoint;
|
|
29784
30037
|
}
|
|
@@ -29836,7 +30089,8 @@ var DaemonSessionEventConnectionState = class {
|
|
|
29836
30089
|
};
|
|
29837
30090
|
var DisconnectedDaemonSessionEventState = class extends DaemonSessionEventConnectionState {
|
|
29838
30091
|
disconnect = () => this;
|
|
29839
|
-
|
|
30092
|
+
matches = () => false;
|
|
30093
|
+
send = () => false;
|
|
29840
30094
|
};
|
|
29841
30095
|
var ConnectedDaemonSessionEventState = class extends DaemonSessionEventConnectionState {
|
|
29842
30096
|
#socket;
|
|
@@ -29845,38 +30099,155 @@ var ConnectedDaemonSessionEventState = class extends DaemonSessionEventConnectio
|
|
|
29845
30099
|
this.#socket = socket;
|
|
29846
30100
|
}
|
|
29847
30101
|
disconnect = (socket) => socket === this.#socket ? new DisconnectedDaemonSessionEventState() : this;
|
|
30102
|
+
matches = (socket) => socket === this.#socket;
|
|
29848
30103
|
send = (message) => {
|
|
29849
|
-
if (this.#socket.readyState
|
|
29850
|
-
|
|
29851
|
-
|
|
29852
|
-
|
|
29853
|
-
|
|
30104
|
+
if (this.#socket.readyState !== WebSocket2.OPEN) {
|
|
30105
|
+
return false;
|
|
30106
|
+
}
|
|
30107
|
+
try {
|
|
30108
|
+
this.#socket.send(message);
|
|
30109
|
+
return true;
|
|
30110
|
+
} catch {
|
|
30111
|
+
return false;
|
|
29854
30112
|
}
|
|
29855
30113
|
};
|
|
29856
30114
|
};
|
|
30115
|
+
var SESSION_EVENT_REPLAY_WINDOW = 4;
|
|
29857
30116
|
var DaemonSessionEventPublisher = class {
|
|
29858
30117
|
#outbox;
|
|
30118
|
+
#inFlightEventIds = /* @__PURE__ */ new Set();
|
|
29859
30119
|
#connection = new DisconnectedDaemonSessionEventState();
|
|
29860
30120
|
constructor(outbox) {
|
|
29861
30121
|
this.#outbox = outbox;
|
|
29862
30122
|
}
|
|
29863
30123
|
connect = (socket) => {
|
|
29864
|
-
|
|
29865
|
-
this.#
|
|
29866
|
-
|
|
29867
|
-
connection.send(pending);
|
|
29868
|
-
}
|
|
30124
|
+
this.#connection = new ConnectedDaemonSessionEventState(socket);
|
|
30125
|
+
this.#inFlightEventIds.clear();
|
|
30126
|
+
this.#publishNextBatch();
|
|
29869
30127
|
};
|
|
29870
30128
|
disconnect = (socket) => {
|
|
30129
|
+
if (!this.#connection.matches(socket)) {
|
|
30130
|
+
return;
|
|
30131
|
+
}
|
|
29871
30132
|
this.#connection = this.#connection.disconnect(socket);
|
|
30133
|
+
this.#inFlightEventIds.clear();
|
|
29872
30134
|
};
|
|
29873
30135
|
recordAttempt = (sessionId, payload, attemptId) => {
|
|
29874
|
-
this.#
|
|
30136
|
+
this.#outbox.enqueue(sessionId, payload, attemptId);
|
|
30137
|
+
this.#publishNextBatch();
|
|
29875
30138
|
};
|
|
29876
30139
|
recordRuntime = (sessionId, payload) => {
|
|
29877
|
-
this.#
|
|
30140
|
+
this.#outbox.enqueue(sessionId, payload);
|
|
30141
|
+
this.#publishNextBatch();
|
|
30142
|
+
};
|
|
30143
|
+
acknowledge = (acknowledgement) => {
|
|
30144
|
+
if (!this.#outbox.acknowledge(acknowledgement)) {
|
|
30145
|
+
return;
|
|
30146
|
+
}
|
|
30147
|
+
this.#inFlightEventIds.delete(acknowledgement.eventId);
|
|
30148
|
+
this.#publishNextBatch();
|
|
30149
|
+
};
|
|
30150
|
+
quarantine = (rejection) => {
|
|
30151
|
+
const quarantined = this.#outbox.quarantine(rejection);
|
|
30152
|
+
if (!quarantined) {
|
|
30153
|
+
return false;
|
|
30154
|
+
}
|
|
30155
|
+
this.#inFlightEventIds.delete(rejection.eventId);
|
|
30156
|
+
this.#publishNextBatch();
|
|
30157
|
+
return true;
|
|
30158
|
+
};
|
|
30159
|
+
#publishNextBatch = () => {
|
|
30160
|
+
if (this.#inFlightEventIds.size > 0) {
|
|
30161
|
+
return;
|
|
30162
|
+
}
|
|
30163
|
+
const batch = this.#outbox.pendingBatch(SESSION_EVENT_REPLAY_WINDOW);
|
|
30164
|
+
for (const encoded of batch) {
|
|
30165
|
+
const envelope2 = decodeSessionEventEnvelope(encoded);
|
|
30166
|
+
if (!this.#connection.send(encoded)) {
|
|
30167
|
+
this.#inFlightEventIds.clear();
|
|
30168
|
+
return;
|
|
30169
|
+
}
|
|
30170
|
+
this.#inFlightEventIds.add(envelope2.eventId);
|
|
30171
|
+
}
|
|
30172
|
+
};
|
|
30173
|
+
};
|
|
30174
|
+
var CoalescingDaemonActivityPublisher = class {
|
|
30175
|
+
#pending = /* @__PURE__ */ new Map();
|
|
30176
|
+
#publish;
|
|
30177
|
+
#publishedActivityIds = /* @__PURE__ */ new Set();
|
|
30178
|
+
#scheduled = /* @__PURE__ */ new Map();
|
|
30179
|
+
#timer;
|
|
30180
|
+
constructor(timer, publish) {
|
|
30181
|
+
this.#publish = publish;
|
|
30182
|
+
this.#timer = timer;
|
|
30183
|
+
}
|
|
30184
|
+
flush = () => {
|
|
30185
|
+
const activities = [...this.#pending.values()].sort((left, right) => left.sequence - right.sequence);
|
|
30186
|
+
for (const task of this.#scheduled.values()) {
|
|
30187
|
+
task.cancel();
|
|
30188
|
+
}
|
|
30189
|
+
this.#pending.clear();
|
|
30190
|
+
this.#scheduled.clear();
|
|
30191
|
+
for (const activity of activities) {
|
|
30192
|
+
this.#publish(activity);
|
|
30193
|
+
}
|
|
30194
|
+
};
|
|
30195
|
+
record = (activity) => {
|
|
30196
|
+
if (activity.status !== "pending" && activity.status !== "running") {
|
|
30197
|
+
this.#discardPending(activity.activityId);
|
|
30198
|
+
this.#publishedActivityIds.add(activity.activityId);
|
|
30199
|
+
this.#publish(activity);
|
|
30200
|
+
return Promise.resolve();
|
|
30201
|
+
}
|
|
30202
|
+
if (!this.#publishedActivityIds.has(activity.activityId)) {
|
|
30203
|
+
this.#publishedActivityIds.add(activity.activityId);
|
|
30204
|
+
this.#publish(activity);
|
|
30205
|
+
return Promise.resolve();
|
|
30206
|
+
}
|
|
30207
|
+
this.#pending.set(activity.activityId, activity);
|
|
30208
|
+
if (!this.#scheduled.has(activity.activityId)) {
|
|
30209
|
+
this.#scheduled.set(
|
|
30210
|
+
activity.activityId,
|
|
30211
|
+
this.#timer.schedule(
|
|
30212
|
+
() => this.#flushActivity(activity.activityId),
|
|
30213
|
+
AGENT_ACTIVITY_COALESCING_MILLISECONDS
|
|
30214
|
+
)
|
|
30215
|
+
);
|
|
30216
|
+
}
|
|
30217
|
+
return Promise.resolve();
|
|
30218
|
+
};
|
|
30219
|
+
#discardPending = (activityId) => {
|
|
30220
|
+
this.#scheduled.get(activityId)?.cancel();
|
|
30221
|
+
this.#scheduled.delete(activityId);
|
|
30222
|
+
this.#pending.delete(activityId);
|
|
30223
|
+
};
|
|
30224
|
+
#flushActivity = (activityId) => {
|
|
30225
|
+
const activity = this.#pending.get(activityId);
|
|
30226
|
+
this.#discardPending(activityId);
|
|
30227
|
+
if (activity !== void 0) {
|
|
30228
|
+
this.#publish(activity);
|
|
30229
|
+
}
|
|
29878
30230
|
};
|
|
29879
30231
|
};
|
|
30232
|
+
function encodeDaemonActivity(command, activity) {
|
|
30233
|
+
return encodeAgentActivityEvent({
|
|
30234
|
+
activityId: activity.activityId,
|
|
30235
|
+
activityType: activity.activityType,
|
|
30236
|
+
commandId: command.commandId,
|
|
30237
|
+
content: activity.content,
|
|
30238
|
+
detail: activity.detail,
|
|
30239
|
+
input: activity.input,
|
|
30240
|
+
kind: AGENT_ACTIVITY_KIND,
|
|
30241
|
+
locations: activity.locations,
|
|
30242
|
+
name: activity.name,
|
|
30243
|
+
output: activity.output,
|
|
30244
|
+
sequence: activity.sequence,
|
|
30245
|
+
sessionId: command.sessionId,
|
|
30246
|
+
status: activity.status,
|
|
30247
|
+
title: activity.title,
|
|
30248
|
+
toolKind: activity.toolKind
|
|
30249
|
+
});
|
|
30250
|
+
}
|
|
29880
30251
|
function reportFailure(publisher, command, code, message, attemptId) {
|
|
29881
30252
|
publisher.recordAttempt(
|
|
29882
30253
|
command.sessionId,
|
|
@@ -30053,7 +30424,10 @@ async function executeSessionConfigure(publisher, socket, command, config2, dire
|
|
|
30053
30424
|
reportOperationFailure(socket, command.requestId, command.sessionId, error61);
|
|
30054
30425
|
}
|
|
30055
30426
|
}
|
|
30056
|
-
async function executePrompt(outbox, publisher, command, config2, directories, audit, sessions, attemptId, signal) {
|
|
30427
|
+
async function executePrompt(outbox, publisher, command, config2, directories, audit, sessions, attemptId, timer, signal) {
|
|
30428
|
+
const activities = new CoalescingDaemonActivityPublisher(timer, (activity) => {
|
|
30429
|
+
publisher.recordAttempt(command.sessionId, encodeDaemonActivity(command, activity), attemptId);
|
|
30430
|
+
});
|
|
30057
30431
|
try {
|
|
30058
30432
|
const resolved = await resolveSessionDirectories(
|
|
30059
30433
|
directories,
|
|
@@ -30110,30 +30484,7 @@ async function executePrompt(outbox, publisher, command, config2, directories, a
|
|
|
30110
30484
|
cwd: resolved.cwd,
|
|
30111
30485
|
disposition: command.disposition,
|
|
30112
30486
|
images: attachments.images,
|
|
30113
|
-
onActivity:
|
|
30114
|
-
publisher.recordAttempt(
|
|
30115
|
-
command.sessionId,
|
|
30116
|
-
encodeAgentActivityEvent({
|
|
30117
|
-
activityId: activity.activityId,
|
|
30118
|
-
activityType: activity.activityType,
|
|
30119
|
-
commandId: command.commandId,
|
|
30120
|
-
content: activity.content,
|
|
30121
|
-
detail: activity.detail,
|
|
30122
|
-
input: activity.input,
|
|
30123
|
-
kind: AGENT_ACTIVITY_KIND,
|
|
30124
|
-
locations: activity.locations,
|
|
30125
|
-
name: activity.name,
|
|
30126
|
-
output: activity.output,
|
|
30127
|
-
sequence: activity.sequence,
|
|
30128
|
-
sessionId: command.sessionId,
|
|
30129
|
-
status: activity.status,
|
|
30130
|
-
title: activity.title,
|
|
30131
|
-
toolKind: activity.toolKind
|
|
30132
|
-
}),
|
|
30133
|
-
attemptId
|
|
30134
|
-
);
|
|
30135
|
-
return Promise.resolve();
|
|
30136
|
-
},
|
|
30487
|
+
onActivity: activities.record,
|
|
30137
30488
|
onText: (text, messageId) => {
|
|
30138
30489
|
publisher.recordAttempt(
|
|
30139
30490
|
command.sessionId,
|
|
@@ -30156,6 +30507,7 @@ async function executePrompt(outbox, publisher, command, config2, directories, a
|
|
|
30156
30507
|
});
|
|
30157
30508
|
stopReason = result.stopReason;
|
|
30158
30509
|
}
|
|
30510
|
+
activities.flush();
|
|
30159
30511
|
publisher.recordAttempt(
|
|
30160
30512
|
command.sessionId,
|
|
30161
30513
|
encodeSessionCompletedEvent({
|
|
@@ -30173,6 +30525,7 @@ async function executePrompt(outbox, publisher, command, config2, directories, a
|
|
|
30173
30525
|
sessionId: command.sessionId
|
|
30174
30526
|
});
|
|
30175
30527
|
} catch (error61) {
|
|
30528
|
+
activities.flush();
|
|
30176
30529
|
audit.record({
|
|
30177
30530
|
commandId: command.commandId,
|
|
30178
30531
|
event: "session_failed",
|
|
@@ -30211,7 +30564,10 @@ function botExecutionAgent(agent, contextHandle, socketPath) {
|
|
|
30211
30564
|
agent.capabilities
|
|
30212
30565
|
);
|
|
30213
30566
|
}
|
|
30214
|
-
async function executeBotPrompt(outbox, publisher, command, config2, directories, audit, sessions, grants, contexts, applicator, ipc, attemptId, signal) {
|
|
30567
|
+
async function executeBotPrompt(outbox, publisher, command, config2, directories, audit, sessions, grants, contexts, applicator, ipc, attemptId, timer, signal) {
|
|
30568
|
+
const activities = new CoalescingDaemonActivityPublisher(timer, (activity) => {
|
|
30569
|
+
publisher.recordAttempt(command.sessionId, encodeDaemonActivity(command, activity), attemptId);
|
|
30570
|
+
});
|
|
30215
30571
|
try {
|
|
30216
30572
|
const deadline = Date.parse(command.executionDeadlineAt);
|
|
30217
30573
|
const remaining = deadline - Date.now();
|
|
@@ -30295,30 +30651,7 @@ async function executeBotPrompt(outbox, publisher, command, config2, directories
|
|
|
30295
30651
|
commandId: command.commandId,
|
|
30296
30652
|
cwd: resolved.cwd,
|
|
30297
30653
|
images: attachments.images,
|
|
30298
|
-
onActivity:
|
|
30299
|
-
publisher.recordAttempt(
|
|
30300
|
-
command.sessionId,
|
|
30301
|
-
encodeAgentActivityEvent({
|
|
30302
|
-
activityId: activity.activityId,
|
|
30303
|
-
activityType: activity.activityType,
|
|
30304
|
-
commandId: command.commandId,
|
|
30305
|
-
content: activity.content,
|
|
30306
|
-
detail: activity.detail,
|
|
30307
|
-
input: activity.input,
|
|
30308
|
-
kind: AGENT_ACTIVITY_KIND,
|
|
30309
|
-
locations: activity.locations,
|
|
30310
|
-
name: activity.name,
|
|
30311
|
-
output: activity.output,
|
|
30312
|
-
sequence: activity.sequence,
|
|
30313
|
-
sessionId: command.sessionId,
|
|
30314
|
-
status: activity.status,
|
|
30315
|
-
title: activity.title,
|
|
30316
|
-
toolKind: activity.toolKind
|
|
30317
|
-
}),
|
|
30318
|
-
attemptId
|
|
30319
|
-
);
|
|
30320
|
-
return Promise.resolve();
|
|
30321
|
-
},
|
|
30654
|
+
onActivity: activities.record,
|
|
30322
30655
|
onText: (text, messageId) => {
|
|
30323
30656
|
publisher.recordAttempt(
|
|
30324
30657
|
command.sessionId,
|
|
@@ -30338,6 +30671,7 @@ async function executeBotPrompt(outbox, publisher, command, config2, directories
|
|
|
30338
30671
|
sessionId: command.sessionId,
|
|
30339
30672
|
signal: executionSignal
|
|
30340
30673
|
});
|
|
30674
|
+
activities.flush();
|
|
30341
30675
|
publisher.recordAttempt(
|
|
30342
30676
|
command.sessionId,
|
|
30343
30677
|
encodeSessionCompletedEvent({
|
|
@@ -30362,6 +30696,7 @@ async function executeBotPrompt(outbox, publisher, command, config2, directories
|
|
|
30362
30696
|
lease.release();
|
|
30363
30697
|
}
|
|
30364
30698
|
} catch (error61) {
|
|
30699
|
+
activities.flush();
|
|
30365
30700
|
const failure = Date.parse(command.executionDeadlineAt) <= Date.now() ? new LocalBotAuthorizationError("turn_expired", "The Bot execution deadline has expired", {
|
|
30366
30701
|
cause: error61
|
|
30367
30702
|
}) : error61;
|
|
@@ -30391,25 +30726,25 @@ function waitForRelayRetry(signal, timer) {
|
|
|
30391
30726
|
if (signal.aborted) {
|
|
30392
30727
|
return Promise.resolve();
|
|
30393
30728
|
}
|
|
30394
|
-
return new Promise((
|
|
30729
|
+
return new Promise((resolve6) => {
|
|
30395
30730
|
const retry = timer.schedule(finish, RELAY_RECONNECT_DELAY_MILLISECONDS);
|
|
30396
30731
|
function finish() {
|
|
30397
30732
|
retry.cancel();
|
|
30398
30733
|
signal.removeEventListener("abort", finish);
|
|
30399
|
-
|
|
30734
|
+
resolve6();
|
|
30400
30735
|
}
|
|
30401
30736
|
signal.addEventListener("abort", finish, { once: true });
|
|
30402
30737
|
});
|
|
30403
30738
|
}
|
|
30404
|
-
async function publishAgentCatalogUntilAvailable(config2, signal, timer) {
|
|
30739
|
+
async function publishAgentCatalogUntilAvailable(config2, diagnostics, signal, timer) {
|
|
30405
30740
|
try {
|
|
30406
30741
|
await publishAgentCatalog(config2, signal);
|
|
30407
30742
|
return;
|
|
30408
|
-
} catch {
|
|
30743
|
+
} catch (error61) {
|
|
30409
30744
|
if (signal.aborted) {
|
|
30410
30745
|
return;
|
|
30411
30746
|
}
|
|
30412
|
-
|
|
30747
|
+
diagnostics.catalogFailed(error61);
|
|
30413
30748
|
}
|
|
30414
30749
|
while (!signal.aborted) {
|
|
30415
30750
|
await waitForRelayRetry(signal, timer);
|
|
@@ -30423,20 +30758,20 @@ async function publishAgentCatalogUntilAvailable(config2, signal, timer) {
|
|
|
30423
30758
|
}
|
|
30424
30759
|
}
|
|
30425
30760
|
}
|
|
30426
|
-
async function runRelayConnection(config2, directories, audit, sessions, installations, installationObserver, nativeSessions, outbox, publisher, grants, contexts, applicator, ipc, activeTurns, activeAttemptIds, onConnected, signal, timer) {
|
|
30761
|
+
async function runRelayConnection(config2, directories, audit, sessions, installations, installationObserver, nativeSessions, outbox, publisher, grants, contexts, applicator, ipc, activeTurns, activeAttemptIds, connectionEpoch, diagnostics, onConnected, signal, timer) {
|
|
30427
30762
|
const relayUrl = new URL(config2.relayUrl);
|
|
30428
30763
|
relayUrl.searchParams.set("liveness", "1");
|
|
30429
30764
|
const socket = await connectRelay(relayUrl, signal);
|
|
30430
30765
|
const reconnectingTurns = [...activeTurns.values()];
|
|
30766
|
+
diagnostics.connectionOpened(connectionEpoch);
|
|
30431
30767
|
onConnected();
|
|
30432
30768
|
const connectionController = new AbortController();
|
|
30433
30769
|
const nativeRequests = /* @__PURE__ */ new Map();
|
|
30434
30770
|
installationObserver.connect(socket);
|
|
30435
30771
|
try {
|
|
30436
|
-
await new Promise((
|
|
30772
|
+
await new Promise((resolve6, reject) => {
|
|
30437
30773
|
let finished = false;
|
|
30438
30774
|
const cleanup = () => {
|
|
30439
|
-
connectionRefresh.close();
|
|
30440
30775
|
connectionLiveness.close();
|
|
30441
30776
|
signal.removeEventListener("abort", stop);
|
|
30442
30777
|
socket.removeEventListener("close", handleClose);
|
|
@@ -30452,63 +30787,72 @@ async function runRelayConnection(config2, directories, audit, sessions, install
|
|
|
30452
30787
|
}
|
|
30453
30788
|
finished = true;
|
|
30454
30789
|
cleanup();
|
|
30455
|
-
|
|
30790
|
+
resolve6();
|
|
30456
30791
|
};
|
|
30457
|
-
const rejectConnection = () => {
|
|
30792
|
+
const rejectConnection = (failure) => {
|
|
30458
30793
|
if (finished) {
|
|
30459
30794
|
return;
|
|
30460
30795
|
}
|
|
30461
30796
|
finished = true;
|
|
30462
30797
|
cleanup();
|
|
30463
|
-
reject(
|
|
30798
|
+
reject(failure);
|
|
30464
30799
|
};
|
|
30465
30800
|
const stop = () => {
|
|
30801
|
+
diagnostics.connectionClosed(connectionEpoch, 1e3, "Daemon stopped", "daemon_stop");
|
|
30466
30802
|
closeRelaySocket(socket, 1e3, "Daemon stopped");
|
|
30467
30803
|
resolveConnection();
|
|
30468
30804
|
};
|
|
30469
|
-
const
|
|
30470
|
-
|
|
30471
|
-
|
|
30805
|
+
const failAndClose = (failure, code, reason, source) => {
|
|
30806
|
+
diagnostics.connectionFailed(connectionEpoch, failure, source);
|
|
30807
|
+
diagnostics.connectionClosed(connectionEpoch, code, reason, source);
|
|
30808
|
+
closeRelaySocket(socket, code, reason);
|
|
30809
|
+
rejectConnection(failure);
|
|
30472
30810
|
};
|
|
30473
30811
|
const connectionLiveness = new RelayConnectionLiveness(timer, {
|
|
30474
30812
|
send: (message) => send(socket, message),
|
|
30475
|
-
unresponsive: () => {
|
|
30813
|
+
unresponsive: (heartbeatId, timeoutMilliseconds) => {
|
|
30814
|
+
diagnostics.heartbeatTimedOut(connectionEpoch, heartbeatId, timeoutMilliseconds);
|
|
30815
|
+
diagnostics.connectionClosed(
|
|
30816
|
+
connectionEpoch,
|
|
30817
|
+
4001,
|
|
30818
|
+
"Relay liveness check timed out",
|
|
30819
|
+
"heartbeat_timeout"
|
|
30820
|
+
);
|
|
30476
30821
|
closeRelaySocket(socket, 4001, "Relay liveness check timed out");
|
|
30477
30822
|
resolveConnection();
|
|
30478
30823
|
}
|
|
30479
30824
|
});
|
|
30480
|
-
const connectionRefresh = new RelayConnectionRefresh(
|
|
30481
|
-
timer,
|
|
30482
|
-
() => activeTurns.size === 0,
|
|
30483
|
-
refreshConnection
|
|
30484
|
-
);
|
|
30485
30825
|
signal.addEventListener("abort", stop, { once: true });
|
|
30486
|
-
const handleClose = () => {
|
|
30826
|
+
const handleClose = (event) => {
|
|
30827
|
+
diagnostics.connectionClosed(connectionEpoch, event.code, event.reason, "relay");
|
|
30487
30828
|
resolveConnection();
|
|
30488
30829
|
};
|
|
30489
|
-
const handleError = () => {
|
|
30830
|
+
const handleError = (event) => {
|
|
30490
30831
|
if (signal.aborted) {
|
|
30491
30832
|
resolveConnection();
|
|
30492
30833
|
return;
|
|
30493
30834
|
}
|
|
30494
|
-
|
|
30835
|
+
const cause = Reflect.get(event, "error");
|
|
30836
|
+
const failure = new Error("Relay WebSocket emitted an error", { cause: cause ?? event });
|
|
30837
|
+
diagnostics.connectionFailed(connectionEpoch, failure, "socket_error");
|
|
30838
|
+
diagnostics.connectionClosed(connectionEpoch, 1006, "WebSocket error", "socket_error");
|
|
30839
|
+
rejectConnection(failure);
|
|
30495
30840
|
};
|
|
30496
30841
|
const handleMessage = (event) => {
|
|
30497
30842
|
const encoded = event.data;
|
|
30498
30843
|
if (typeof encoded !== "string") {
|
|
30499
|
-
|
|
30500
|
-
rejectConnection();
|
|
30844
|
+
failAndClose(new Error("Relay sent a non-text message"), 4003, "Text message required", "protocol");
|
|
30501
30845
|
return;
|
|
30502
30846
|
}
|
|
30503
30847
|
try {
|
|
30504
30848
|
const kind = decodeMessageKind(encoded);
|
|
30505
30849
|
if (kind === SESSION_EVENT_ACK_KIND) {
|
|
30506
|
-
|
|
30850
|
+
publisher.acknowledge(decodeSessionEventAcknowledgement(encoded));
|
|
30507
30851
|
return;
|
|
30508
30852
|
}
|
|
30509
30853
|
if (kind === SESSION_EVENT_REJECTED_KIND) {
|
|
30510
30854
|
const rejection = decodeSessionEventRejection(encoded);
|
|
30511
|
-
if (
|
|
30855
|
+
if (publisher.quarantine(rejection)) {
|
|
30512
30856
|
audit.record({
|
|
30513
30857
|
commandId: rejection.eventId,
|
|
30514
30858
|
details: { code: rejection.code },
|
|
@@ -30632,7 +30976,7 @@ async function runRelayConnection(config2, directories, audit, sessions, install
|
|
|
30632
30976
|
try {
|
|
30633
30977
|
operationSignal.throwIfAborted();
|
|
30634
30978
|
if (previous.length > 0) {
|
|
30635
|
-
await new Promise((
|
|
30979
|
+
await new Promise((resolve7, reject2) => {
|
|
30636
30980
|
const cancel = () => reject2(operationSignal.reason);
|
|
30637
30981
|
operationSignal.addEventListener("abort", cancel, {
|
|
30638
30982
|
once: true
|
|
@@ -30640,7 +30984,7 @@ async function runRelayConnection(config2, directories, audit, sessions, install
|
|
|
30640
30984
|
void Promise.all(previous.map((request) => request.completion)).then(
|
|
30641
30985
|
() => {
|
|
30642
30986
|
operationSignal.removeEventListener("abort", cancel);
|
|
30643
|
-
|
|
30987
|
+
resolve7();
|
|
30644
30988
|
},
|
|
30645
30989
|
(error61) => {
|
|
30646
30990
|
operationSignal.removeEventListener("abort", cancel);
|
|
@@ -30714,13 +31058,13 @@ async function runRelayConnection(config2, directories, audit, sessions, install
|
|
|
30714
31058
|
try {
|
|
30715
31059
|
operationSignal.throwIfAborted();
|
|
30716
31060
|
if (previous.length > 0) {
|
|
30717
|
-
await new Promise((
|
|
31061
|
+
await new Promise((resolve7, reject2) => {
|
|
30718
31062
|
const cancel = () => reject2(operationSignal.reason);
|
|
30719
31063
|
operationSignal.addEventListener("abort", cancel, { once: true });
|
|
30720
31064
|
void Promise.all(previous.map((request) => request.completion)).then(
|
|
30721
31065
|
() => {
|
|
30722
31066
|
operationSignal.removeEventListener("abort", cancel);
|
|
30723
|
-
|
|
31067
|
+
resolve7();
|
|
30724
31068
|
},
|
|
30725
31069
|
(error61) => {
|
|
30726
31070
|
operationSignal.removeEventListener("abort", cancel);
|
|
@@ -30887,6 +31231,7 @@ async function runRelayConnection(config2, directories, audit, sessions, install
|
|
|
30887
31231
|
applicator,
|
|
30888
31232
|
ipc,
|
|
30889
31233
|
receipt2.attemptId,
|
|
31234
|
+
timer,
|
|
30890
31235
|
turn2.signal
|
|
30891
31236
|
).catch((error61) => {
|
|
30892
31237
|
console.error("Mobius daemon Bot turn failed", error61);
|
|
@@ -30896,7 +31241,6 @@ async function runRelayConnection(config2, directories, audit, sessions, install
|
|
|
30896
31241
|
activeAttemptIds.delete(command2.sessionId);
|
|
30897
31242
|
}
|
|
30898
31243
|
turn2.finish();
|
|
30899
|
-
connectionRefresh.afterTurnFinished();
|
|
30900
31244
|
});
|
|
30901
31245
|
return;
|
|
30902
31246
|
}
|
|
@@ -30925,6 +31269,7 @@ async function runRelayConnection(config2, directories, audit, sessions, install
|
|
|
30925
31269
|
audit,
|
|
30926
31270
|
sessions,
|
|
30927
31271
|
receipt.attemptId,
|
|
31272
|
+
timer,
|
|
30928
31273
|
turn.signal
|
|
30929
31274
|
).catch((error61) => {
|
|
30930
31275
|
console.error("Mobius daemon turn failed", error61);
|
|
@@ -30934,12 +31279,15 @@ async function runRelayConnection(config2, directories, audit, sessions, install
|
|
|
30934
31279
|
activeAttemptIds.delete(command.sessionId);
|
|
30935
31280
|
}
|
|
30936
31281
|
turn.finish();
|
|
30937
|
-
connectionRefresh.afterTurnFinished();
|
|
30938
31282
|
});
|
|
30939
31283
|
} catch (error61) {
|
|
30940
31284
|
console.error("Mobius daemon rejected a message", error61);
|
|
30941
|
-
|
|
30942
|
-
|
|
31285
|
+
failAndClose(
|
|
31286
|
+
new Error("Relay sent an invalid protocol message", { cause: error61 }),
|
|
31287
|
+
4008,
|
|
31288
|
+
"Invalid protocol message",
|
|
31289
|
+
"protocol"
|
|
31290
|
+
);
|
|
30943
31291
|
}
|
|
30944
31292
|
};
|
|
30945
31293
|
socket.addEventListener("close", handleClose);
|
|
@@ -30951,21 +31299,18 @@ async function runRelayConnection(config2, directories, audit, sessions, install
|
|
|
30951
31299
|
return;
|
|
30952
31300
|
}
|
|
30953
31301
|
publisher.connect(socket);
|
|
30954
|
-
void Promise.all(reconnectingTurns.map((turn) => turn.completion)).then(
|
|
30955
|
-
connectionRefresh.afterTurnFinished
|
|
30956
|
-
);
|
|
30957
31302
|
},
|
|
30958
31303
|
(error61) => {
|
|
30959
31304
|
if (finished) {
|
|
30960
31305
|
return;
|
|
30961
31306
|
}
|
|
30962
31307
|
console.error("Mobius daemon could not reconcile active Agent turns", error61);
|
|
30963
|
-
|
|
30964
|
-
|
|
31308
|
+
failAndClose(
|
|
31309
|
+
new Error("Active Agent turn reconciliation failed", { cause: error61 }),
|
|
30965
31310
|
ACTIVE_TURN_RECONCILIATION_CLOSE_CODE,
|
|
30966
|
-
"Active Agent turn reconciliation failed"
|
|
31311
|
+
"Active Agent turn reconciliation failed",
|
|
31312
|
+
"reconciliation"
|
|
30967
31313
|
);
|
|
30968
|
-
rejectConnection();
|
|
30969
31314
|
}
|
|
30970
31315
|
);
|
|
30971
31316
|
if (signal.aborted) {
|
|
@@ -31009,6 +31354,7 @@ async function runDaemon(config2, audit, signal, timer = systemDaemonTimer) {
|
|
|
31009
31354
|
const sessions = new AcpSessionManager(new DaemonAcpObserver(recordSessionEvent), sessionStore);
|
|
31010
31355
|
const directories = new WorkspaceDirectoryService(config2.bindingId, config2.defaultWorkspace);
|
|
31011
31356
|
const installationObserver = new DaemonInstallationObserver();
|
|
31357
|
+
const diagnostics = new RelayConnectionDiagnostics(audit, config2.channelId, config2.relayUrl);
|
|
31012
31358
|
const nativeSessions = new NativeSessionService(config2, directories, sessions, audit);
|
|
31013
31359
|
const installations = new AgentInstallationManager(
|
|
31014
31360
|
specifications,
|
|
@@ -31016,7 +31362,7 @@ async function runDaemon(config2, audit, signal, timer = systemDaemonTimer) {
|
|
|
31016
31362
|
installationObserver,
|
|
31017
31363
|
installationAudit
|
|
31018
31364
|
);
|
|
31019
|
-
let
|
|
31365
|
+
let connectionEpoch = 0;
|
|
31020
31366
|
let connectionAnnounced = false;
|
|
31021
31367
|
const announceConnection = () => {
|
|
31022
31368
|
if (connectionAnnounced) {
|
|
@@ -31032,10 +31378,11 @@ async function runDaemon(config2, audit, signal, timer = systemDaemonTimer) {
|
|
|
31032
31378
|
`
|
|
31033
31379
|
);
|
|
31034
31380
|
};
|
|
31035
|
-
const catalogPublication = publishAgentCatalogUntilAvailable(config2, signal, timer);
|
|
31381
|
+
const catalogPublication = publishAgentCatalogUntilAvailable(config2, diagnostics, signal, timer);
|
|
31036
31382
|
try {
|
|
31037
31383
|
await ipc.listen(signal);
|
|
31038
31384
|
while (!signal.aborted) {
|
|
31385
|
+
connectionEpoch += 1;
|
|
31039
31386
|
try {
|
|
31040
31387
|
await runRelayConnection(
|
|
31041
31388
|
config2,
|
|
@@ -31053,19 +31400,17 @@ async function runDaemon(config2, audit, signal, timer = systemDaemonTimer) {
|
|
|
31053
31400
|
ipc,
|
|
31054
31401
|
activeTurns,
|
|
31055
31402
|
activeAttemptIds,
|
|
31403
|
+
connectionEpoch,
|
|
31404
|
+
diagnostics,
|
|
31056
31405
|
announceConnection,
|
|
31057
31406
|
signal,
|
|
31058
31407
|
timer
|
|
31059
31408
|
);
|
|
31060
|
-
|
|
31061
|
-
} catch {
|
|
31409
|
+
} catch (error61) {
|
|
31062
31410
|
if (signal.aborted) {
|
|
31063
31411
|
return;
|
|
31064
31412
|
}
|
|
31065
|
-
|
|
31066
|
-
console.warn("Mobius daemon is waiting for the relay");
|
|
31067
|
-
retryAnnounced = true;
|
|
31068
|
-
}
|
|
31413
|
+
diagnostics.connectionFailed(connectionEpoch, error61, "connection");
|
|
31069
31414
|
}
|
|
31070
31415
|
await waitForRelayRetry(signal, timer);
|
|
31071
31416
|
}
|
|
@@ -31102,6 +31447,147 @@ async function runDaemon(config2, audit, signal, timer = systemDaemonTimer) {
|
|
|
31102
31447
|
}
|
|
31103
31448
|
}
|
|
31104
31449
|
}
|
|
31450
|
+
|
|
31451
|
+
// src/runtime.ts
|
|
31452
|
+
import { mkdir as mkdir5, realpath as realpath8, stat as stat8 } from "node:fs/promises";
|
|
31453
|
+
import { dirname as dirname8, join as join17, resolve as resolve5 } from "node:path";
|
|
31454
|
+
var APP_CREDENTIAL_PATTERN = /^mapp_[a-zA-Z0-9_-]{22}_[a-zA-Z0-9_-]{43}$/;
|
|
31455
|
+
var CONVERSATION_CREDENTIAL_PATTERN = /^mconv_[a-zA-Z0-9_-]{22}_[a-zA-Z0-9_-]{43}$/;
|
|
31456
|
+
var IDENTIFIER_PATTERN8 = /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/;
|
|
31457
|
+
var RUNTIME_CREDENTIAL_PATTERN = /^[a-zA-Z0-9_-]{32,256}$/;
|
|
31458
|
+
var MobiusRuntimeConfigurationError = class extends Error {
|
|
31459
|
+
code = "runtime_configuration_invalid";
|
|
31460
|
+
constructor(message, options = {}) {
|
|
31461
|
+
super(message, options);
|
|
31462
|
+
this.name = "MobiusRuntimeConfigurationError";
|
|
31463
|
+
}
|
|
31464
|
+
};
|
|
31465
|
+
var MobiusRuntimeState = class {
|
|
31466
|
+
};
|
|
31467
|
+
var IdleMobiusRuntimeState = class extends MobiusRuntimeState {
|
|
31468
|
+
};
|
|
31469
|
+
var RunningMobiusRuntimeState = class extends MobiusRuntimeState {
|
|
31470
|
+
};
|
|
31471
|
+
var FinishedMobiusRuntimeState = class extends MobiusRuntimeState {
|
|
31472
|
+
};
|
|
31473
|
+
function validateRuntimeRelay(relayUrl) {
|
|
31474
|
+
if (relayUrl.protocol !== "ws:" && relayUrl.protocol !== "wss:") {
|
|
31475
|
+
throw new MobiusRuntimeConfigurationError("The Runtime relay URL must use WebSocket transport");
|
|
31476
|
+
}
|
|
31477
|
+
const credential = relayUrl.searchParams.get("token") ?? "";
|
|
31478
|
+
if (credential.length === 0) {
|
|
31479
|
+
throw new MobiusRuntimeConfigurationError("The Runtime relay credential is required");
|
|
31480
|
+
}
|
|
31481
|
+
if (APP_CREDENTIAL_PATTERN.test(credential)) {
|
|
31482
|
+
throw new MobiusRuntimeConfigurationError("An AppCredential cannot be held by a local Runtime");
|
|
31483
|
+
}
|
|
31484
|
+
if (CONVERSATION_CREDENTIAL_PATTERN.test(credential)) {
|
|
31485
|
+
throw new MobiusRuntimeConfigurationError("A ConversationAccessToken cannot be held by a local Runtime");
|
|
31486
|
+
}
|
|
31487
|
+
if (!RUNTIME_CREDENTIAL_PATTERN.test(credential)) {
|
|
31488
|
+
throw new MobiusRuntimeConfigurationError("The Runtime relay credential is invalid");
|
|
31489
|
+
}
|
|
31490
|
+
}
|
|
31491
|
+
function validateRuntimeConfiguration(config2) {
|
|
31492
|
+
validateRuntimeRelay(config2.relayUrl);
|
|
31493
|
+
}
|
|
31494
|
+
function requiredEnvironmentValue(environment, name) {
|
|
31495
|
+
const value = environment[name]?.trim();
|
|
31496
|
+
if (value === void 0 || value.length === 0) {
|
|
31497
|
+
throw new MobiusRuntimeConfigurationError(`${name} is required`);
|
|
31498
|
+
}
|
|
31499
|
+
return value;
|
|
31500
|
+
}
|
|
31501
|
+
function relayUrlFromConnection(connection) {
|
|
31502
|
+
let relayUrl;
|
|
31503
|
+
try {
|
|
31504
|
+
relayUrl = new URL(connection.relayUrl);
|
|
31505
|
+
} catch (error61) {
|
|
31506
|
+
throw new MobiusRuntimeConfigurationError("The Runtime relay URL is invalid", { cause: error61 });
|
|
31507
|
+
}
|
|
31508
|
+
relayUrl.searchParams.set("token", connection.runtimeCredential);
|
|
31509
|
+
validateRuntimeRelay(relayUrl);
|
|
31510
|
+
return relayUrl;
|
|
31511
|
+
}
|
|
31512
|
+
function loadMobiusRuntimeConnection(environment = process.env) {
|
|
31513
|
+
const channelId = requiredEnvironmentValue(environment, "MOBIUS_CHANNEL_ID");
|
|
31514
|
+
if (!IDENTIFIER_PATTERN8.test(channelId)) {
|
|
31515
|
+
throw new MobiusRuntimeConfigurationError("MOBIUS_CHANNEL_ID is invalid");
|
|
31516
|
+
}
|
|
31517
|
+
return Object.freeze({
|
|
31518
|
+
auditDatabasePath: environment["MOBIUS_AUDIT_DATABASE"]?.trim() || join17(readStateDirectory(environment), "audit", `${channelId}.sqlite`),
|
|
31519
|
+
channelId,
|
|
31520
|
+
defaultWorkspace: loadDefaultWorkspace(environment),
|
|
31521
|
+
relayUrl: requiredEnvironmentValue(environment, "MOBIUS_RELAY_URL"),
|
|
31522
|
+
runtimeCredential: requiredEnvironmentValue(environment, "MOBIUS_RELAY_TOKEN")
|
|
31523
|
+
});
|
|
31524
|
+
}
|
|
31525
|
+
async function resolveWorkspace(path2) {
|
|
31526
|
+
const requested = resolve5(path2);
|
|
31527
|
+
try {
|
|
31528
|
+
await mkdir5(requested, { recursive: true, mode: 448 });
|
|
31529
|
+
const resolved = await realpath8(requested);
|
|
31530
|
+
const metadata = await stat8(resolved);
|
|
31531
|
+
if (!metadata.isDirectory()) {
|
|
31532
|
+
throw new MobiusRuntimeConfigurationError("The Runtime workspace is not a directory");
|
|
31533
|
+
}
|
|
31534
|
+
return resolved;
|
|
31535
|
+
} catch (error61) {
|
|
31536
|
+
if (error61 instanceof MobiusRuntimeConfigurationError) {
|
|
31537
|
+
throw error61;
|
|
31538
|
+
}
|
|
31539
|
+
throw new MobiusRuntimeConfigurationError("The Runtime workspace cannot be resolved", { cause: error61 });
|
|
31540
|
+
}
|
|
31541
|
+
}
|
|
31542
|
+
async function createMobiusRuntimeEngine(connection, signal, environment = process.env) {
|
|
31543
|
+
signal.throwIfAborted();
|
|
31544
|
+
const relayUrl = relayUrlFromConnection(connection);
|
|
31545
|
+
const defaultWorkspace = await resolveWorkspace(connection.defaultWorkspace);
|
|
31546
|
+
const auditDatabasePath = resolve5(connection.auditDatabasePath);
|
|
31547
|
+
await mkdir5(dirname8(auditDatabasePath), { recursive: true, mode: 448 });
|
|
31548
|
+
const inventory = await discoverLocalAgentInventory({
|
|
31549
|
+
defaultWorkspace,
|
|
31550
|
+
environment,
|
|
31551
|
+
signal
|
|
31552
|
+
});
|
|
31553
|
+
if (inventory.available.length + inventory.installable.length === 0) {
|
|
31554
|
+
throw new MobiusRuntimeConfigurationError("No supported Agent is available for the local Runtime");
|
|
31555
|
+
}
|
|
31556
|
+
return new MobiusRuntimeEngine(
|
|
31557
|
+
createDaemonConfig(
|
|
31558
|
+
{
|
|
31559
|
+
auditDatabasePath,
|
|
31560
|
+
channelId: connection.channelId,
|
|
31561
|
+
defaultWorkspace,
|
|
31562
|
+
relayUrl
|
|
31563
|
+
},
|
|
31564
|
+
inventory.readyAgents(),
|
|
31565
|
+
inventory.installable
|
|
31566
|
+
)
|
|
31567
|
+
);
|
|
31568
|
+
}
|
|
31569
|
+
var MobiusRuntimeEngine = class {
|
|
31570
|
+
#config;
|
|
31571
|
+
#state = new IdleMobiusRuntimeState();
|
|
31572
|
+
constructor(config2) {
|
|
31573
|
+
validateRuntimeConfiguration(config2);
|
|
31574
|
+
this.#config = config2;
|
|
31575
|
+
}
|
|
31576
|
+
run = async (signal) => {
|
|
31577
|
+
if (!(this.#state instanceof IdleMobiusRuntimeState)) {
|
|
31578
|
+
throw new MobiusRuntimeConfigurationError("A Mobius Runtime engine can only be started once");
|
|
31579
|
+
}
|
|
31580
|
+
signal.throwIfAborted();
|
|
31581
|
+
this.#state = new RunningMobiusRuntimeState();
|
|
31582
|
+
const audit = new AuditStore(this.#config.auditDatabasePath);
|
|
31583
|
+
try {
|
|
31584
|
+
await runDaemon(this.#config, audit, signal);
|
|
31585
|
+
} finally {
|
|
31586
|
+
audit.close();
|
|
31587
|
+
this.#state = new FinishedMobiusRuntimeState();
|
|
31588
|
+
}
|
|
31589
|
+
};
|
|
31590
|
+
};
|
|
31105
31591
|
export {
|
|
31106
31592
|
AcpExecutionError,
|
|
31107
31593
|
AuditStore,
|
|
@@ -31109,12 +31595,18 @@ export {
|
|
|
31109
31595
|
BotMessageCommandError,
|
|
31110
31596
|
BotOutboundIpcServer,
|
|
31111
31597
|
LocalAuthorizationError,
|
|
31598
|
+
MobiusRuntimeConfigurationError,
|
|
31599
|
+
MobiusRuntimeEngine,
|
|
31112
31600
|
PairingClientError,
|
|
31113
31601
|
createAcpClient,
|
|
31602
|
+
createMobiusRuntimeEngine,
|
|
31114
31603
|
executeBotMessageCommand,
|
|
31115
31604
|
loadDaemonConfig,
|
|
31605
|
+
loadMobiusRuntimeConnection,
|
|
31116
31606
|
pairLocalMachine,
|
|
31607
|
+
pairMobiusRuntime,
|
|
31117
31608
|
resumeLocalMachine,
|
|
31609
|
+
resumeMobiusRuntime,
|
|
31118
31610
|
runAcpPrompt,
|
|
31119
31611
|
runDaemon
|
|
31120
31612
|
};
|