@moxt-ai/mobius 0.0.27 → 0.0.29
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/acp-readiness-probe.d.ts.map +1 -1
- package/dist/agent-catalog/acp-readiness-probe.js +2 -2
- package/dist/agent-catalog/acp-readiness-probe.js.map +1 -1
- package/dist/agent-catalog/agent-specification.d.ts +3 -0
- package/dist/agent-catalog/agent-specification.d.ts.map +1 -1
- package/dist/agent-catalog/agent-specification.js +3 -0
- package/dist/agent-catalog/agent-specification.js.map +1 -1
- package/dist/agent-catalog/agents/copilot-cli-agent.d.ts +18 -0
- package/dist/agent-catalog/agents/copilot-cli-agent.d.ts.map +1 -0
- package/dist/agent-catalog/agents/copilot-cli-agent.js +29 -0
- package/dist/agent-catalog/agents/copilot-cli-agent.js.map +1 -0
- package/dist/agent-catalog/agents/gemini-cli-agent.d.ts +14 -0
- package/dist/agent-catalog/agents/gemini-cli-agent.d.ts.map +1 -0
- package/dist/agent-catalog/agents/gemini-cli-agent.js +30 -0
- package/dist/agent-catalog/agents/gemini-cli-agent.js.map +1 -0
- package/dist/agent-catalog/agents/hermes-agent.d.ts +18 -0
- package/dist/agent-catalog/agents/hermes-agent.d.ts.map +1 -0
- package/dist/agent-catalog/agents/hermes-agent.js +32 -0
- package/dist/agent-catalog/agents/hermes-agent.js.map +1 -0
- package/dist/agent-catalog/agents/resolve-user-local-executable.d.ts +4 -0
- package/dist/agent-catalog/agents/resolve-user-local-executable.d.ts.map +1 -0
- package/dist/agent-catalog/agents/resolve-user-local-executable.js +14 -0
- package/dist/agent-catalog/agents/resolve-user-local-executable.js.map +1 -0
- package/dist/agent-catalog/agents/supported-agent-specifications.d.ts.map +1 -1
- package/dist/agent-catalog/agents/supported-agent-specifications.js +6 -0
- package/dist/agent-catalog/agents/supported-agent-specifications.js.map +1 -1
- package/dist/agent-catalog/discover-agent.d.ts.map +1 -1
- package/dist/agent-catalog/discover-agent.js +2 -2
- package/dist/agent-catalog/discover-agent.js.map +1 -1
- package/dist/agent-catalog/discover-local-agents.d.ts +3 -0
- package/dist/agent-catalog/discover-local-agents.d.ts.map +1 -1
- package/dist/agent-catalog/discover-local-agents.js +3 -0
- package/dist/agent-catalog/discover-local-agents.js.map +1 -1
- package/dist/agent-catalog/executable-discovery.d.ts +1 -2
- package/dist/agent-catalog/executable-discovery.d.ts.map +1 -1
- package/dist/agent-catalog/executable-discovery.js +4 -6
- package/dist/agent-catalog/executable-discovery.js.map +1 -1
- package/dist/agent-catalog/version-output.d.ts +2 -0
- package/dist/agent-catalog/version-output.d.ts.map +1 -0
- package/dist/agent-catalog/version-output.js +4 -0
- package/dist/agent-catalog/version-output.js.map +1 -0
- 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 +1185 -333
- package/dist/cli.js.map +4 -4
- package/dist/index.js +1245 -396
- 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/run-daemon.d.ts.map +1 -1
- package/dist/run-daemon.js +30 -7
- package/dist/run-daemon.js.map +1 -1
- package/dist/runtime.js +1205 -354
- package/dist/runtime.js.map +4 -4
- package/package.json +2 -1
package/dist/runtime.js
CHANGED
|
@@ -5,8 +5,8 @@ var __export = (target, all) => {
|
|
|
5
5
|
};
|
|
6
6
|
|
|
7
7
|
// src/runtime.ts
|
|
8
|
-
import { mkdir as mkdir5, realpath as
|
|
9
|
-
import { dirname as dirname8, join as
|
|
8
|
+
import { mkdir as mkdir5, realpath as realpath9, stat as stat9 } from "node:fs/promises";
|
|
9
|
+
import { dirname as dirname8, join as join18, resolve as resolve5 } from "node:path";
|
|
10
10
|
|
|
11
11
|
// src/agent-catalog/local-agent.ts
|
|
12
12
|
import { realpathSync, statSync } from "node:fs";
|
|
@@ -1029,6 +1029,13 @@ var ManagedNpmPackageInstaller = class {
|
|
|
1029
1029
|
|
|
1030
1030
|
// src/agent-catalog/agent-specification.ts
|
|
1031
1031
|
import { join as join3 } from "node:path";
|
|
1032
|
+
|
|
1033
|
+
// src/agent-catalog/version-output.ts
|
|
1034
|
+
function normalizeVersionOutput(output2) {
|
|
1035
|
+
return output2.trim().split(/\r?\n/, 1)[0]?.trim().slice(0, 128) ?? "";
|
|
1036
|
+
}
|
|
1037
|
+
|
|
1038
|
+
// src/agent-catalog/agent-specification.ts
|
|
1032
1039
|
var VERSION_PROBE_TIMEOUT_MILLISECONDS = 3e3;
|
|
1033
1040
|
var ACP_PROBE_TIMEOUT_MILLISECONDS = 5e3;
|
|
1034
1041
|
var DEFAULT_PROMPT_TIMEOUT_MILLISECONDS = 30 * 60 * 1e3;
|
|
@@ -1037,6 +1044,8 @@ var LocalAgentSpecification = class {
|
|
|
1037
1044
|
authenticationCommand = () => "";
|
|
1038
1045
|
adapterVersionArguments = ["--version"];
|
|
1039
1046
|
agentVersionArguments = ["--version"];
|
|
1047
|
+
normalizeAdapterVersion = normalizeVersionOutput;
|
|
1048
|
+
normalizeAgentVersion = normalizeVersionOutput;
|
|
1040
1049
|
promptTimeoutMilliseconds = DEFAULT_PROMPT_TIMEOUT_MILLISECONDS;
|
|
1041
1050
|
versionProbeTimeoutMilliseconds = VERSION_PROBE_TIMEOUT_MILLISECONDS;
|
|
1042
1051
|
resolveManagedAgent = async (stateDirectory, platform, signal) => {
|
|
@@ -1148,6 +1157,20 @@ var AgentProbeError = class extends Error {
|
|
|
1148
1157
|
}
|
|
1149
1158
|
};
|
|
1150
1159
|
|
|
1160
|
+
// src/agent-catalog/agents/resolve-user-local-executable.ts
|
|
1161
|
+
import { isAbsolute as isAbsolute2, join as join4 } from "node:path";
|
|
1162
|
+
async function resolveUserLocalExecutable(executableName, context) {
|
|
1163
|
+
context.signal.throwIfAborted();
|
|
1164
|
+
const platform = context.platform ?? process.platform;
|
|
1165
|
+
const homeDirectory = context.environment["HOME"];
|
|
1166
|
+
if (platform === "win32" || homeDirectory === void 0 || !isAbsolute2(homeDirectory)) {
|
|
1167
|
+
return [];
|
|
1168
|
+
}
|
|
1169
|
+
const executable = await resolveExecutablePath(join4(homeDirectory, ".local", "bin", executableName), platform);
|
|
1170
|
+
context.signal.throwIfAborted();
|
|
1171
|
+
return executable === null ? [] : [executable];
|
|
1172
|
+
}
|
|
1173
|
+
|
|
1151
1174
|
// src/agent-catalog/agents/verify-session-creation.ts
|
|
1152
1175
|
import { methods } from "@agentclientprotocol/sdk";
|
|
1153
1176
|
async function verifySessionCreation(connection, capabilities, defaultWorkspace, signal, label) {
|
|
@@ -1172,6 +1195,37 @@ async function verifySessionCreation(connection, capabilities, defaultWorkspace,
|
|
|
1172
1195
|
}
|
|
1173
1196
|
}
|
|
1174
1197
|
|
|
1198
|
+
// src/agent-catalog/agents/copilot-cli-agent.ts
|
|
1199
|
+
var COPILOT_CLI_TESTED_VERSION = "1.0.83";
|
|
1200
|
+
var CopilotCliAgentSpecification = class extends DirectAcpAgentDefinition {
|
|
1201
|
+
acpProbeTimeoutMilliseconds = 2e4;
|
|
1202
|
+
adapterVersion = COPILOT_CLI_TESTED_VERSION;
|
|
1203
|
+
authenticationCommand = () => "copilot login";
|
|
1204
|
+
agentExecutable = "copilot";
|
|
1205
|
+
id = "github-copilot-cli";
|
|
1206
|
+
label = "GitHub Copilot CLI";
|
|
1207
|
+
versionProbeTimeoutMilliseconds = 1e4;
|
|
1208
|
+
constructor() {
|
|
1209
|
+
super(
|
|
1210
|
+
"MOBIUS_COPILOT_PATH",
|
|
1211
|
+
["--no-auto-update", "--acp", "--stdio"],
|
|
1212
|
+
["agents", "github-copilot-cli", COPILOT_CLI_TESTED_VERSION, "bin", "copilot"]
|
|
1213
|
+
);
|
|
1214
|
+
}
|
|
1215
|
+
createLaunchEnvironment = async (_agent, _context) => Object.freeze({ COPILOT_AUTO_UPDATE: "false" });
|
|
1216
|
+
resolveInstalledAgentExecutables = async (context) => await resolveUserLocalExecutable(this.agentExecutable, context);
|
|
1217
|
+
verifyAcp = async (connection, initialized, defaultWorkspace, signal) => {
|
|
1218
|
+
const capabilities = initialized.agentCapabilities ?? {};
|
|
1219
|
+
if (capabilities.loadSession !== true || capabilities.sessionCapabilities?.list == null || (initialized.authMethods ?? []).length === 0) {
|
|
1220
|
+
throw new AgentProbeError(
|
|
1221
|
+
"acp_incompatible",
|
|
1222
|
+
"GitHub Copilot CLI reported an unsupported ACP capability set"
|
|
1223
|
+
);
|
|
1224
|
+
}
|
|
1225
|
+
await verifySessionCreation(connection, capabilities, defaultWorkspace, signal, this.label);
|
|
1226
|
+
};
|
|
1227
|
+
};
|
|
1228
|
+
|
|
1175
1229
|
// src/agent-catalog/agents/cursor-cli-agent.ts
|
|
1176
1230
|
var CURSOR_CLI_TESTED_VERSION = "2026.09.02-c22c1a3";
|
|
1177
1231
|
var CursorCliAgentSpecification = class extends DirectAcpAgentDefinition {
|
|
@@ -1198,7 +1252,7 @@ var CursorCliAgentSpecification = class extends DirectAcpAgentDefinition {
|
|
|
1198
1252
|
|
|
1199
1253
|
// src/agent-catalog/agents/deepseek-harness-agent.ts
|
|
1200
1254
|
import { realpath as realpath3, stat as stat3 } from "node:fs/promises";
|
|
1201
|
-
import { isAbsolute as
|
|
1255
|
+
import { isAbsolute as isAbsolute3, join as join6, normalize } from "node:path";
|
|
1202
1256
|
|
|
1203
1257
|
// src/agent-installation/deepseek-managed-package.ts
|
|
1204
1258
|
var DeepSeekHarnessManagedPackage = class extends SriManagedNpmPackageDefinition {
|
|
@@ -1216,18 +1270,18 @@ var DEEPSEEK_HARNESS_PACKAGE = new DeepSeekHarnessManagedPackage(
|
|
|
1216
1270
|
|
|
1217
1271
|
// src/storage/state-directory.ts
|
|
1218
1272
|
import { homedir } from "node:os";
|
|
1219
|
-
import { join as
|
|
1273
|
+
import { join as join5, resolve as resolve2 } from "node:path";
|
|
1220
1274
|
function readStateDirectory(environment = process.env) {
|
|
1221
1275
|
const configured = environment["MOBIUS_STATE_DIRECTORY"]?.trim();
|
|
1222
1276
|
if (configured !== void 0 && configured.length > 0) {
|
|
1223
1277
|
return resolve2(configured);
|
|
1224
1278
|
}
|
|
1225
|
-
return
|
|
1279
|
+
return join5(homedir(), ".mobius");
|
|
1226
1280
|
}
|
|
1227
1281
|
|
|
1228
1282
|
// src/agent-catalog/agents/deepseek-harness-agent.ts
|
|
1229
1283
|
async function validateAgentHome(path2) {
|
|
1230
|
-
if (!
|
|
1284
|
+
if (!isAbsolute3(path2) || normalize(path2) !== path2) {
|
|
1231
1285
|
throw new AgentProbeError("agent_environment_invalid", "The configured Agent home is invalid");
|
|
1232
1286
|
}
|
|
1233
1287
|
try {
|
|
@@ -1277,7 +1331,7 @@ var DeepSeekHarnessAgentSpecification = class extends DirectAcpAgentDefinition {
|
|
|
1277
1331
|
context.signal
|
|
1278
1332
|
);
|
|
1279
1333
|
if (managed.path === agent.path) {
|
|
1280
|
-
selectedHome =
|
|
1334
|
+
selectedHome = join6(readStateDirectory(context.environment), "agents", this.id, "home");
|
|
1281
1335
|
}
|
|
1282
1336
|
} catch {
|
|
1283
1337
|
context.signal.throwIfAborted();
|
|
@@ -1293,7 +1347,7 @@ var DeepSeekHarnessAgentSpecification = class extends DirectAcpAgentDefinition {
|
|
|
1293
1347
|
resolveManagedAgent = async (stateDirectory, _platform, signal) => {
|
|
1294
1348
|
signal.throwIfAborted();
|
|
1295
1349
|
const executable = await validateManagedNpmPackage(
|
|
1296
|
-
|
|
1350
|
+
join6(stateDirectory, "agents", this.id, DEEPSEEK_HARNESS_PACKAGE.version),
|
|
1297
1351
|
DEEPSEEK_HARNESS_PACKAGE
|
|
1298
1352
|
);
|
|
1299
1353
|
signal.throwIfAborted();
|
|
@@ -1313,9 +1367,41 @@ var DeepSeekHarnessAgentSpecification = class extends DirectAcpAgentDefinition {
|
|
|
1313
1367
|
};
|
|
1314
1368
|
};
|
|
1315
1369
|
|
|
1370
|
+
// src/agent-catalog/agents/gemini-cli-agent.ts
|
|
1371
|
+
var GEMINI_CLI_TESTED_VERSION = "0.59.0";
|
|
1372
|
+
var GeminiCliAgentSpecification = class extends DirectAcpAgentDefinition {
|
|
1373
|
+
acpProbeTimeoutMilliseconds = 2e4;
|
|
1374
|
+
adapterVersion = GEMINI_CLI_TESTED_VERSION;
|
|
1375
|
+
authenticationCommand = () => "gemini";
|
|
1376
|
+
agentExecutable = "gemini";
|
|
1377
|
+
id = "gemini-cli";
|
|
1378
|
+
label = "Gemini CLI";
|
|
1379
|
+
versionProbeTimeoutMilliseconds = 1e4;
|
|
1380
|
+
constructor() {
|
|
1381
|
+
super(
|
|
1382
|
+
"MOBIUS_GEMINI_PATH",
|
|
1383
|
+
["--acp"],
|
|
1384
|
+
[
|
|
1385
|
+
"agents",
|
|
1386
|
+
"gemini-cli",
|
|
1387
|
+
GEMINI_CLI_TESTED_VERSION,
|
|
1388
|
+
"bin",
|
|
1389
|
+
process.platform === "win32" ? "gemini.cmd" : "gemini"
|
|
1390
|
+
]
|
|
1391
|
+
);
|
|
1392
|
+
}
|
|
1393
|
+
verifyAcp = async (connection, initialized, defaultWorkspace, signal) => {
|
|
1394
|
+
const capabilities = initialized.agentCapabilities ?? {};
|
|
1395
|
+
if (capabilities.loadSession !== true || (initialized.authMethods ?? []).length === 0) {
|
|
1396
|
+
throw new AgentProbeError("acp_incompatible", "Gemini CLI reported an unsupported ACP capability set");
|
|
1397
|
+
}
|
|
1398
|
+
await verifySessionCreation(connection, capabilities, defaultWorkspace, signal, this.label);
|
|
1399
|
+
};
|
|
1400
|
+
};
|
|
1401
|
+
|
|
1316
1402
|
// src/agent-catalog/agents/grok-build-agent.ts
|
|
1317
1403
|
import { realpath as realpath4 } from "node:fs/promises";
|
|
1318
|
-
import { isAbsolute as
|
|
1404
|
+
import { isAbsolute as isAbsolute4, join as join7, relative as relative2, sep as sep2 } from "node:path";
|
|
1319
1405
|
|
|
1320
1406
|
// src/agent-installation/grok-managed-package.ts
|
|
1321
1407
|
var GROK_BUILD_MANAGED_VERSION = "1.0.21";
|
|
@@ -1378,7 +1464,7 @@ function grokBuildManagedPackage(platform, architecture) {
|
|
|
1378
1464
|
// src/agent-catalog/agents/grok-build-agent.ts
|
|
1379
1465
|
function isContainedPath2(root, candidate) {
|
|
1380
1466
|
const difference = relative2(root, candidate);
|
|
1381
|
-
return difference.length > 0 && difference !== ".." && !difference.startsWith(`..${sep2}`) && !
|
|
1467
|
+
return difference.length > 0 && difference !== ".." && !difference.startsWith(`..${sep2}`) && !isAbsolute4(difference);
|
|
1382
1468
|
}
|
|
1383
1469
|
var GrokBuildAgentSpecification = class extends DirectAcpAgentDefinition {
|
|
1384
1470
|
adapterVersion = GROK_BUILD_MANAGED_VERSION;
|
|
@@ -1406,7 +1492,7 @@ var GrokBuildAgentSpecification = class extends DirectAcpAgentDefinition {
|
|
|
1406
1492
|
if (managed.path === agent.path) {
|
|
1407
1493
|
return Object.freeze({
|
|
1408
1494
|
GROK_HOME: await realpath4(
|
|
1409
|
-
|
|
1495
|
+
join7(stateDirectory, "agents", this.id, GROK_BUILD_MANAGED_VERSION, "home")
|
|
1410
1496
|
)
|
|
1411
1497
|
});
|
|
1412
1498
|
}
|
|
@@ -1417,9 +1503,9 @@ var GrokBuildAgentSpecification = class extends DirectAcpAgentDefinition {
|
|
|
1417
1503
|
};
|
|
1418
1504
|
resolveManagedAgent = async (stateDirectory, platform, signal) => {
|
|
1419
1505
|
signal.throwIfAborted();
|
|
1420
|
-
const versionRoot = await realpath4(
|
|
1421
|
-
await validateManagedNpmPackage(
|
|
1422
|
-
const executable = await resolveExecutablePath(
|
|
1506
|
+
const versionRoot = await realpath4(join7(stateDirectory, "agents", this.id, GROK_BUILD_MANAGED_VERSION));
|
|
1507
|
+
await validateManagedNpmPackage(join7(versionRoot, "package"), grokBuildManagedPackage(platform, process.arch));
|
|
1508
|
+
const executable = await resolveExecutablePath(join7(versionRoot, "home", "bin", "grok"), platform);
|
|
1423
1509
|
signal.throwIfAborted();
|
|
1424
1510
|
if (executable === null || !isContainedPath2(versionRoot, executable.path)) {
|
|
1425
1511
|
throw new AgentProbeError("managed_agent_invalid", "The managed Grok Build executable is invalid");
|
|
@@ -1436,14 +1522,39 @@ var GrokBuildAgentSpecification = class extends DirectAcpAgentDefinition {
|
|
|
1436
1522
|
};
|
|
1437
1523
|
};
|
|
1438
1524
|
|
|
1525
|
+
// src/agent-catalog/agents/hermes-agent.ts
|
|
1526
|
+
var HERMES_TESTED_VERSION = "0.21.1";
|
|
1527
|
+
var HermesAgentSpecification = class extends DirectAcpAgentDefinition {
|
|
1528
|
+
acpProbeTimeoutMilliseconds = 2e4;
|
|
1529
|
+
adapterVersion = HERMES_TESTED_VERSION;
|
|
1530
|
+
adapterVersionArguments = ["acp", "--version"];
|
|
1531
|
+
authenticationCommand = () => "hermes acp --setup";
|
|
1532
|
+
agentExecutable = "hermes";
|
|
1533
|
+
agentVersionArguments = ["acp", "--version"];
|
|
1534
|
+
id = "hermes";
|
|
1535
|
+
label = "Hermes Agent";
|
|
1536
|
+
constructor() {
|
|
1537
|
+
super("MOBIUS_HERMES_PATH", ["acp"], ["agents", "hermes", HERMES_TESTED_VERSION, "bin", "hermes"]);
|
|
1538
|
+
}
|
|
1539
|
+
resolveInstalledAgentExecutables = async (context) => await resolveUserLocalExecutable(this.agentExecutable, context);
|
|
1540
|
+
verifyAcp = async (connection, initialized, defaultWorkspace, signal) => {
|
|
1541
|
+
const capabilities = initialized.agentCapabilities ?? {};
|
|
1542
|
+
const session = capabilities.sessionCapabilities;
|
|
1543
|
+
if (capabilities.loadSession !== true || session?.fork == null || session.list == null || session.resume == null || (initialized.authMethods ?? []).length === 0) {
|
|
1544
|
+
throw new AgentProbeError("acp_incompatible", "Hermes Agent reported an unsupported ACP capability set");
|
|
1545
|
+
}
|
|
1546
|
+
await verifySessionCreation(connection, capabilities, defaultWorkspace, signal, this.label);
|
|
1547
|
+
};
|
|
1548
|
+
};
|
|
1549
|
+
|
|
1439
1550
|
// src/agent-catalog/agents/opencode-agent.ts
|
|
1440
|
-
import { join as
|
|
1551
|
+
import { join as join9 } from "node:path";
|
|
1441
1552
|
|
|
1442
1553
|
// src/agent-installation/managed-agent-archive.ts
|
|
1443
1554
|
import { createHash } from "node:crypto";
|
|
1444
1555
|
import { createReadStream } from "node:fs";
|
|
1445
1556
|
import { chmod, copyFile, mkdir as mkdir2, mkdtemp as mkdtemp2, open as open2, realpath as realpath5, rename as rename2, rm as rm2, stat as stat4, writeFile } from "node:fs/promises";
|
|
1446
|
-
import { dirname as dirname2, isAbsolute as
|
|
1557
|
+
import { dirname as dirname2, isAbsolute as isAbsolute5, join as join8, relative as relative3, sep as sep3 } from "node:path";
|
|
1447
1558
|
|
|
1448
1559
|
// src/agent-installation/verified-download.ts
|
|
1449
1560
|
import { fetch } from "undici";
|
|
@@ -1549,7 +1660,7 @@ function isRecord3(value) {
|
|
|
1549
1660
|
}
|
|
1550
1661
|
function isContainedPath3(root, candidate) {
|
|
1551
1662
|
const difference = relative3(root, candidate);
|
|
1552
|
-
return difference.length > 0 && difference !== ".." && !difference.startsWith(`..${sep3}`) && !
|
|
1663
|
+
return difference.length > 0 && difference !== ".." && !difference.startsWith(`..${sep3}`) && !isAbsolute5(difference);
|
|
1553
1664
|
}
|
|
1554
1665
|
async function hashFile(path2, signal) {
|
|
1555
1666
|
signal.throwIfAborted();
|
|
@@ -1628,11 +1739,11 @@ async function validateManagedAgentArchive(root, definition, signal) {
|
|
|
1628
1739
|
if (!rootMetadata.isDirectory() || typeof process.getuid === "function" && rootMetadata.uid !== process.getuid()) {
|
|
1629
1740
|
throw new Error("Managed Agent root is not user-owned");
|
|
1630
1741
|
}
|
|
1631
|
-
const manifest = await readManifest(
|
|
1742
|
+
const manifest = await readManifest(join8(rootPath, "archive.json"));
|
|
1632
1743
|
if (manifest["archiveSha256"] !== definition.archiveSha256 || manifest["archiveUrl"] !== definition.archiveUrl.toString() || manifest["version"] !== definition.version || typeof manifest["executableSha256"] !== "string") {
|
|
1633
1744
|
throw new Error("Managed Agent archive identity is invalid");
|
|
1634
1745
|
}
|
|
1635
|
-
const executable = await resolveExecutablePath(
|
|
1746
|
+
const executable = await resolveExecutablePath(join8(rootPath, "bin", definition.executableName));
|
|
1636
1747
|
if (executable === null || !isContainedPath3(rootPath, executable.path) || await hashFile(executable.path, signal) !== manifest["executableSha256"]) {
|
|
1637
1748
|
throw new Error("Managed Agent executable is invalid");
|
|
1638
1749
|
}
|
|
@@ -1724,7 +1835,7 @@ var OpenCodeAgentSpecification = class extends DirectAcpAgentDefinition {
|
|
|
1724
1835
|
}
|
|
1725
1836
|
createLaunchEnvironment = async (_agent, _context) => Object.freeze({ OPENCODE_DISABLE_AUTOUPDATE: "1" });
|
|
1726
1837
|
resolveManagedAgent = async (stateDirectory, platform, signal) => await validateManagedAgentArchive(
|
|
1727
|
-
|
|
1838
|
+
join9(stateDirectory, "agents", this.id, OPENCODE_MANAGED_VERSION),
|
|
1728
1839
|
openCodeManagedArchive(platform, process.arch),
|
|
1729
1840
|
signal
|
|
1730
1841
|
);
|
|
@@ -1742,7 +1853,7 @@ var OpenCodeAgentSpecification = class extends DirectAcpAgentDefinition {
|
|
|
1742
1853
|
};
|
|
1743
1854
|
|
|
1744
1855
|
// src/agent-catalog/agents/pi-agent.ts
|
|
1745
|
-
import { join as
|
|
1856
|
+
import { join as join10 } from "node:path";
|
|
1746
1857
|
import {
|
|
1747
1858
|
methods as methods2
|
|
1748
1859
|
} from "@agentclientprotocol/sdk";
|
|
@@ -1801,7 +1912,7 @@ var PiAgentSpecification = class extends BridgedAcpAgentDefinition {
|
|
|
1801
1912
|
resolveManagedAgent = async (stateDirectory, _platform, signal) => {
|
|
1802
1913
|
signal.throwIfAborted();
|
|
1803
1914
|
const executable = await validateManagedNpmPackage(
|
|
1804
|
-
|
|
1915
|
+
join10(stateDirectory, "agents", this.id, PI_AGENT_PACKAGE.version),
|
|
1805
1916
|
PI_AGENT_PACKAGE
|
|
1806
1917
|
);
|
|
1807
1918
|
signal.throwIfAborted();
|
|
@@ -1839,7 +1950,7 @@ var PiAgentSpecification = class extends BridgedAcpAgentDefinition {
|
|
|
1839
1950
|
};
|
|
1840
1951
|
|
|
1841
1952
|
// src/agent-catalog/agents/workbuddy-agent.ts
|
|
1842
|
-
import { isAbsolute as
|
|
1953
|
+
import { isAbsolute as isAbsolute6, join as join11 } from "node:path";
|
|
1843
1954
|
|
|
1844
1955
|
// src/agent-installation/workbuddy-managed-package.ts
|
|
1845
1956
|
var WORKBUDDY_MANAGED_VERSION = "2.146.0";
|
|
@@ -1892,7 +2003,7 @@ var WorkBuddyAgentSpecification = class extends DirectAcpAgentDefinition {
|
|
|
1892
2003
|
resolveManagedAgent = async (stateDirectory, _platform, signal) => {
|
|
1893
2004
|
signal.throwIfAborted();
|
|
1894
2005
|
const executable = await validateManagedNpmPackage(
|
|
1895
|
-
|
|
2006
|
+
join11(stateDirectory, "agents", this.id, WORKBUDDY_MANAGED_VERSION),
|
|
1896
2007
|
WORKBUDDY_MANAGED_PACKAGE
|
|
1897
2008
|
);
|
|
1898
2009
|
signal.throwIfAborted();
|
|
@@ -1903,10 +2014,10 @@ var WorkBuddyAgentSpecification = class extends DirectAcpAgentDefinition {
|
|
|
1903
2014
|
if ((context.platform ?? process.platform) !== "darwin") {
|
|
1904
2015
|
return [];
|
|
1905
2016
|
}
|
|
1906
|
-
const requestedPaths = [
|
|
2017
|
+
const requestedPaths = [join11("/Applications", ...WORKBUDDY_MACOS_EXECUTABLE_PATH)];
|
|
1907
2018
|
const homeDirectory = context.environment["HOME"];
|
|
1908
|
-
if (homeDirectory !== void 0 &&
|
|
1909
|
-
requestedPaths.unshift(
|
|
2019
|
+
if (homeDirectory !== void 0 && isAbsolute6(homeDirectory)) {
|
|
2020
|
+
requestedPaths.unshift(join11(homeDirectory, "Applications", ...WORKBUDDY_MACOS_EXECUTABLE_PATH));
|
|
1910
2021
|
}
|
|
1911
2022
|
const executables = [];
|
|
1912
2023
|
for (const requestedPath of requestedPaths) {
|
|
@@ -1932,12 +2043,15 @@ function supportedLocalAgentSpecifications() {
|
|
|
1932
2043
|
return Object.freeze([
|
|
1933
2044
|
new CodexAgentSpecification(),
|
|
1934
2045
|
new ClaudeCodeAgentSpecification(),
|
|
2046
|
+
new CopilotCliAgentSpecification(),
|
|
1935
2047
|
new PiAgentSpecification(),
|
|
1936
2048
|
new DeepSeekHarnessAgentSpecification(),
|
|
2049
|
+
new HermesAgentSpecification(),
|
|
1937
2050
|
new OpenCodeAgentSpecification(),
|
|
1938
2051
|
new CursorCliAgentSpecification(),
|
|
1939
2052
|
new GrokBuildAgentSpecification(),
|
|
1940
|
-
new WorkBuddyAgentSpecification()
|
|
2053
|
+
new WorkBuddyAgentSpecification(),
|
|
2054
|
+
new GeminiCliAgentSpecification()
|
|
1941
2055
|
]);
|
|
1942
2056
|
}
|
|
1943
2057
|
|
|
@@ -1977,11 +2091,173 @@ var createAcpClient = (handler) => client({ name: "mobius" }).onRequest(
|
|
|
1977
2091
|
outcome: { outcome: "cancelled" }
|
|
1978
2092
|
})).onNotification("cursor/update_todos", discardExtensionParams, async () => Promise.resolve()).onNotification("cursor/task", discardExtensionParams, async () => Promise.resolve()).onNotification("cursor/generate_image", discardExtensionParams, async () => Promise.resolve());
|
|
1979
2093
|
|
|
2094
|
+
// src/agent-catalog/acp-readiness-probe.ts
|
|
2095
|
+
var ACP_OUTPUT_LIMIT_BYTES = 1024 * 1024;
|
|
2096
|
+
var VerifiedAcpReadiness = class {
|
|
2097
|
+
adapterVersion;
|
|
2098
|
+
capabilities;
|
|
2099
|
+
constructor(adapterVersion, capabilities) {
|
|
2100
|
+
this.adapterVersion = adapterVersion;
|
|
2101
|
+
this.capabilities = capabilities;
|
|
2102
|
+
}
|
|
2103
|
+
};
|
|
2104
|
+
var DiscoveryAcpHandler = class {
|
|
2105
|
+
onElicitation = (_request, _signal) => Promise.reject(new Error("ACP probe does not accept elicitations"));
|
|
2106
|
+
onElicitationComplete = (_notification) => Promise.resolve();
|
|
2107
|
+
onPermission = (_request, _signal) => Promise.reject(new Error("ACP probe does not grant permissions"));
|
|
2108
|
+
onUpdate = (_notification) => Promise.resolve();
|
|
2109
|
+
};
|
|
2110
|
+
function readableAcpStream(input2) {
|
|
2111
|
+
let byteLength = 0;
|
|
2112
|
+
let open5 = true;
|
|
2113
|
+
return new ReadableStream({
|
|
2114
|
+
start(controller) {
|
|
2115
|
+
input2.on("data", (chunk) => {
|
|
2116
|
+
if (!open5) {
|
|
2117
|
+
return;
|
|
2118
|
+
}
|
|
2119
|
+
if (!(chunk instanceof Uint8Array)) {
|
|
2120
|
+
open5 = false;
|
|
2121
|
+
controller.error(new Error("ACP adapter produced invalid output"));
|
|
2122
|
+
return;
|
|
2123
|
+
}
|
|
2124
|
+
byteLength += chunk.byteLength;
|
|
2125
|
+
if (byteLength > ACP_OUTPUT_LIMIT_BYTES) {
|
|
2126
|
+
open5 = false;
|
|
2127
|
+
controller.error(new Error("ACP adapter output limit exceeded"));
|
|
2128
|
+
return;
|
|
2129
|
+
}
|
|
2130
|
+
controller.enqueue(new Uint8Array(chunk));
|
|
2131
|
+
});
|
|
2132
|
+
input2.once("end", () => {
|
|
2133
|
+
if (open5) {
|
|
2134
|
+
open5 = false;
|
|
2135
|
+
controller.close();
|
|
2136
|
+
}
|
|
2137
|
+
});
|
|
2138
|
+
input2.once("error", (error61) => {
|
|
2139
|
+
if (open5) {
|
|
2140
|
+
open5 = false;
|
|
2141
|
+
controller.error(error61);
|
|
2142
|
+
}
|
|
2143
|
+
});
|
|
2144
|
+
},
|
|
2145
|
+
cancel() {
|
|
2146
|
+
open5 = false;
|
|
2147
|
+
}
|
|
2148
|
+
});
|
|
2149
|
+
}
|
|
2150
|
+
function writableAcpStream(output2) {
|
|
2151
|
+
return new WritableStream({
|
|
2152
|
+
write(chunk) {
|
|
2153
|
+
return new Promise((resolveWrite, rejectWrite) => {
|
|
2154
|
+
output2.write(chunk, (error61) => {
|
|
2155
|
+
if (error61) {
|
|
2156
|
+
rejectWrite(error61);
|
|
2157
|
+
return;
|
|
2158
|
+
}
|
|
2159
|
+
resolveWrite();
|
|
2160
|
+
});
|
|
2161
|
+
});
|
|
2162
|
+
}
|
|
2163
|
+
});
|
|
2164
|
+
}
|
|
2165
|
+
async function probeAcpReadiness(specification, agent, environment, defaultWorkspace, signal) {
|
|
2166
|
+
signal.throwIfAborted();
|
|
2167
|
+
const controller = new AbortController();
|
|
2168
|
+
let timedOut = false;
|
|
2169
|
+
const timeout = setTimeout(() => {
|
|
2170
|
+
timedOut = true;
|
|
2171
|
+
controller.abort(new Error("ACP probe timed out"));
|
|
2172
|
+
}, specification.acpProbeTimeoutMilliseconds);
|
|
2173
|
+
const abort = () => controller.abort(signal.reason);
|
|
2174
|
+
signal.addEventListener("abort", abort, { once: true });
|
|
2175
|
+
if (signal.aborted) {
|
|
2176
|
+
abort();
|
|
2177
|
+
}
|
|
2178
|
+
const child = spawn2(agent.adapterPath, [...agent.arguments], {
|
|
2179
|
+
cwd: defaultWorkspace,
|
|
2180
|
+
detached: process.platform !== "win32",
|
|
2181
|
+
env: { ...environment, ...agent.environment },
|
|
2182
|
+
shell: false,
|
|
2183
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
2184
|
+
});
|
|
2185
|
+
const processExit = new Promise((_resolve, reject) => {
|
|
2186
|
+
const rejectExit = () => reject(new Error("ACP adapter exited during initialization"));
|
|
2187
|
+
child.once("error", reject);
|
|
2188
|
+
child.once("exit", rejectExit);
|
|
2189
|
+
if (child.exitCode !== null || child.signalCode !== null) {
|
|
2190
|
+
rejectExit();
|
|
2191
|
+
}
|
|
2192
|
+
});
|
|
2193
|
+
const stdin = child.stdin;
|
|
2194
|
+
const stdout = child.stdout;
|
|
2195
|
+
const stderr = child.stderr;
|
|
2196
|
+
if (stdin === null || stdout === null || stderr === null) {
|
|
2197
|
+
await stopProcessTree(child);
|
|
2198
|
+
throw new AgentProbeError("acp_incompatible", "ACP adapter streams are unavailable");
|
|
2199
|
+
}
|
|
2200
|
+
let stderrBytes = 0;
|
|
2201
|
+
const consumeStderr = (chunk) => {
|
|
2202
|
+
stderrBytes += chunk.byteLength;
|
|
2203
|
+
if (stderrBytes > ACP_OUTPUT_LIMIT_BYTES) {
|
|
2204
|
+
controller.abort(new Error("ACP adapter output limit exceeded"));
|
|
2205
|
+
}
|
|
2206
|
+
};
|
|
2207
|
+
stderr.on("data", consumeStderr);
|
|
2208
|
+
const connection = createAcpClient(new DiscoveryAcpHandler()).connect(
|
|
2209
|
+
ndJsonStream(writableAcpStream(stdin), readableAcpStream(stdout))
|
|
2210
|
+
);
|
|
2211
|
+
try {
|
|
2212
|
+
const initialized = await Promise.race([
|
|
2213
|
+
connection.agent.request(
|
|
2214
|
+
methods4.agent.initialize,
|
|
2215
|
+
{
|
|
2216
|
+
clientCapabilities: {},
|
|
2217
|
+
clientInfo: { name: "mobius", version: "0.0.3" },
|
|
2218
|
+
protocolVersion: PROTOCOL_VERSION
|
|
2219
|
+
},
|
|
2220
|
+
{ cancellationSignal: controller.signal }
|
|
2221
|
+
),
|
|
2222
|
+
processExit
|
|
2223
|
+
]);
|
|
2224
|
+
if (initialized.protocolVersion !== PROTOCOL_VERSION) {
|
|
2225
|
+
throw new AgentProbeError("acp_incompatible", "ACP adapter selected an unsupported protocol version");
|
|
2226
|
+
}
|
|
2227
|
+
await specification.verifyAcp(connection, initialized, defaultWorkspace, controller.signal);
|
|
2228
|
+
return new VerifiedAcpReadiness(
|
|
2229
|
+
normalizeVersionOutput(initialized.agentInfo?.version ?? ""),
|
|
2230
|
+
normalizeAcpCapabilities(initialized)
|
|
2231
|
+
);
|
|
2232
|
+
} catch (error61) {
|
|
2233
|
+
if (signal.aborted) {
|
|
2234
|
+
signal.throwIfAborted();
|
|
2235
|
+
}
|
|
2236
|
+
if (timedOut) {
|
|
2237
|
+
throw new AgentProbeError("adapter_probe_timeout", "ACP adapter probe timed out", { cause: error61 });
|
|
2238
|
+
}
|
|
2239
|
+
if (error61 instanceof AgentProbeError) {
|
|
2240
|
+
throw error61;
|
|
2241
|
+
}
|
|
2242
|
+
if (error61 instanceof RequestError && error61.code === -32e3 && specification.authenticationCommand().length > 0) {
|
|
2243
|
+
throw new AgentProbeError("authentication_required", "Agent authentication is required", { cause: error61 });
|
|
2244
|
+
}
|
|
2245
|
+
throw new AgentProbeError("acp_incompatible", "ACP adapter initialization failed", { cause: error61 });
|
|
2246
|
+
} finally {
|
|
2247
|
+
clearTimeout(timeout);
|
|
2248
|
+
signal.removeEventListener("abort", abort);
|
|
2249
|
+
connection.close();
|
|
2250
|
+
stdin.end();
|
|
2251
|
+
stderr.removeListener("data", consumeStderr);
|
|
2252
|
+
await stopProcessTree(child);
|
|
2253
|
+
}
|
|
2254
|
+
}
|
|
2255
|
+
|
|
1980
2256
|
// src/agent-catalog/executable-discovery.ts
|
|
1981
|
-
import { isAbsolute as
|
|
2257
|
+
import { isAbsolute as isAbsolute7, join as join13 } from "node:path";
|
|
1982
2258
|
|
|
1983
2259
|
// src/agent-installation/managed-adapter-installer.ts
|
|
1984
|
-
import { join as
|
|
2260
|
+
import { join as join12 } from "node:path";
|
|
1985
2261
|
var ManagedAdapterInstallError = class extends Error {
|
|
1986
2262
|
code;
|
|
1987
2263
|
constructor(code, message, options = {}) {
|
|
@@ -2038,7 +2314,7 @@ var ManagedAdapterInstaller = class {
|
|
|
2038
2314
|
this.#stateDirectory = options.stateDirectory;
|
|
2039
2315
|
}
|
|
2040
2316
|
install = async (specification, signal) => {
|
|
2041
|
-
const root =
|
|
2317
|
+
const root = join12(this.#stateDirectory, "adapters", specification.id, specification.adapterVersion);
|
|
2042
2318
|
try {
|
|
2043
2319
|
return await this.#npmInstaller.install(
|
|
2044
2320
|
root,
|
|
@@ -2072,7 +2348,7 @@ async function resolveManagedAdapterExecutable(specification, context) {
|
|
|
2072
2348
|
let managed;
|
|
2073
2349
|
try {
|
|
2074
2350
|
managed = await validateManagedAdapter(
|
|
2075
|
-
|
|
2351
|
+
join13(readStateDirectory(context.environment), "adapters", specification.id, specification.adapterVersion),
|
|
2076
2352
|
specification
|
|
2077
2353
|
);
|
|
2078
2354
|
} catch {
|
|
@@ -2083,7 +2359,7 @@ async function resolveManagedAdapterExecutable(specification, context) {
|
|
|
2083
2359
|
async function resolveSpecificationExecutables(executableName, overrideVariable, resolveInstalled, resolveManaged, context) {
|
|
2084
2360
|
const override = context.environment[overrideVariable];
|
|
2085
2361
|
if (override !== void 0) {
|
|
2086
|
-
if (override.length === 0 || !
|
|
2362
|
+
if (override.length === 0 || !isAbsolute7(override)) {
|
|
2087
2363
|
return [];
|
|
2088
2364
|
}
|
|
2089
2365
|
const executable = await resolveExecutablePath(override, context.platform);
|
|
@@ -2137,10 +2413,7 @@ async function resolveAdapterExecutable(specification, context) {
|
|
|
2137
2413
|
const executables = await resolveAdapterExecutables(specification, context);
|
|
2138
2414
|
return executables[0] ?? null;
|
|
2139
2415
|
}
|
|
2140
|
-
function
|
|
2141
|
-
return output2.trim().split(/\r?\n/, 1)[0]?.trim().slice(0, 128) ?? "";
|
|
2142
|
-
}
|
|
2143
|
-
async function probeVersion(executable, arguments_, environment, defaultWorkspace, signal, timeoutMilliseconds) {
|
|
2416
|
+
async function probeVersion(executable, arguments_, environment, defaultWorkspace, signal, timeoutMilliseconds, normalize4 = normalizeVersionOutput) {
|
|
2144
2417
|
const result = await runBoundedProcess({
|
|
2145
2418
|
arguments: arguments_,
|
|
2146
2419
|
command: executable.path,
|
|
@@ -2149,7 +2422,7 @@ async function probeVersion(executable, arguments_, environment, defaultWorkspac
|
|
|
2149
2422
|
signal,
|
|
2150
2423
|
timeoutMilliseconds
|
|
2151
2424
|
});
|
|
2152
|
-
const version2 =
|
|
2425
|
+
const version2 = normalize4(result.stdout || result.stderr);
|
|
2153
2426
|
if (version2.length === 0) {
|
|
2154
2427
|
throw new ProcessExecutionError("process_exit_failed", "The executable did not report a version");
|
|
2155
2428
|
}
|
|
@@ -2173,7 +2446,8 @@ async function findVerifiedAgentExecutable(specification, context) {
|
|
|
2173
2446
|
context.environment,
|
|
2174
2447
|
context.defaultWorkspace,
|
|
2175
2448
|
context.signal,
|
|
2176
|
-
specification.versionProbeTimeoutMilliseconds
|
|
2449
|
+
specification.versionProbeTimeoutMilliseconds,
|
|
2450
|
+
specification.normalizeAgentVersion
|
|
2177
2451
|
);
|
|
2178
2452
|
return new VerifiedAgentExecutable(executable, version2);
|
|
2179
2453
|
} catch {
|
|
@@ -2185,168 +2459,6 @@ async function findVerifiedAgentExecutable(specification, context) {
|
|
|
2185
2459
|
return null;
|
|
2186
2460
|
}
|
|
2187
2461
|
|
|
2188
|
-
// src/agent-catalog/acp-readiness-probe.ts
|
|
2189
|
-
var ACP_OUTPUT_LIMIT_BYTES = 1024 * 1024;
|
|
2190
|
-
var VerifiedAcpReadiness = class {
|
|
2191
|
-
adapterVersion;
|
|
2192
|
-
capabilities;
|
|
2193
|
-
constructor(adapterVersion, capabilities) {
|
|
2194
|
-
this.adapterVersion = adapterVersion;
|
|
2195
|
-
this.capabilities = capabilities;
|
|
2196
|
-
}
|
|
2197
|
-
};
|
|
2198
|
-
var DiscoveryAcpHandler = class {
|
|
2199
|
-
onElicitation = (_request, _signal) => Promise.reject(new Error("ACP probe does not accept elicitations"));
|
|
2200
|
-
onElicitationComplete = (_notification) => Promise.resolve();
|
|
2201
|
-
onPermission = (_request, _signal) => Promise.reject(new Error("ACP probe does not grant permissions"));
|
|
2202
|
-
onUpdate = (_notification) => Promise.resolve();
|
|
2203
|
-
};
|
|
2204
|
-
function readableAcpStream(input2) {
|
|
2205
|
-
let byteLength = 0;
|
|
2206
|
-
let open5 = true;
|
|
2207
|
-
return new ReadableStream({
|
|
2208
|
-
start(controller) {
|
|
2209
|
-
input2.on("data", (chunk) => {
|
|
2210
|
-
if (!open5) {
|
|
2211
|
-
return;
|
|
2212
|
-
}
|
|
2213
|
-
if (!(chunk instanceof Uint8Array)) {
|
|
2214
|
-
open5 = false;
|
|
2215
|
-
controller.error(new Error("ACP adapter produced invalid output"));
|
|
2216
|
-
return;
|
|
2217
|
-
}
|
|
2218
|
-
byteLength += chunk.byteLength;
|
|
2219
|
-
if (byteLength > ACP_OUTPUT_LIMIT_BYTES) {
|
|
2220
|
-
open5 = false;
|
|
2221
|
-
controller.error(new Error("ACP adapter output limit exceeded"));
|
|
2222
|
-
return;
|
|
2223
|
-
}
|
|
2224
|
-
controller.enqueue(new Uint8Array(chunk));
|
|
2225
|
-
});
|
|
2226
|
-
input2.once("end", () => {
|
|
2227
|
-
if (open5) {
|
|
2228
|
-
open5 = false;
|
|
2229
|
-
controller.close();
|
|
2230
|
-
}
|
|
2231
|
-
});
|
|
2232
|
-
input2.once("error", (error61) => {
|
|
2233
|
-
if (open5) {
|
|
2234
|
-
open5 = false;
|
|
2235
|
-
controller.error(error61);
|
|
2236
|
-
}
|
|
2237
|
-
});
|
|
2238
|
-
},
|
|
2239
|
-
cancel() {
|
|
2240
|
-
open5 = false;
|
|
2241
|
-
}
|
|
2242
|
-
});
|
|
2243
|
-
}
|
|
2244
|
-
function writableAcpStream(output2) {
|
|
2245
|
-
return new WritableStream({
|
|
2246
|
-
write(chunk) {
|
|
2247
|
-
return new Promise((resolveWrite, rejectWrite) => {
|
|
2248
|
-
output2.write(chunk, (error61) => {
|
|
2249
|
-
if (error61) {
|
|
2250
|
-
rejectWrite(error61);
|
|
2251
|
-
return;
|
|
2252
|
-
}
|
|
2253
|
-
resolveWrite();
|
|
2254
|
-
});
|
|
2255
|
-
});
|
|
2256
|
-
}
|
|
2257
|
-
});
|
|
2258
|
-
}
|
|
2259
|
-
async function probeAcpReadiness(specification, agent, environment, defaultWorkspace, signal) {
|
|
2260
|
-
signal.throwIfAborted();
|
|
2261
|
-
const controller = new AbortController();
|
|
2262
|
-
let timedOut = false;
|
|
2263
|
-
const timeout = setTimeout(() => {
|
|
2264
|
-
timedOut = true;
|
|
2265
|
-
controller.abort(new Error("ACP probe timed out"));
|
|
2266
|
-
}, specification.acpProbeTimeoutMilliseconds);
|
|
2267
|
-
const abort = () => controller.abort(signal.reason);
|
|
2268
|
-
signal.addEventListener("abort", abort, { once: true });
|
|
2269
|
-
if (signal.aborted) {
|
|
2270
|
-
abort();
|
|
2271
|
-
}
|
|
2272
|
-
const child = spawn2(agent.adapterPath, [...agent.arguments], {
|
|
2273
|
-
cwd: defaultWorkspace,
|
|
2274
|
-
detached: process.platform !== "win32",
|
|
2275
|
-
env: { ...environment, ...agent.environment },
|
|
2276
|
-
shell: false,
|
|
2277
|
-
stdio: ["pipe", "pipe", "pipe"]
|
|
2278
|
-
});
|
|
2279
|
-
const processExit = new Promise((_resolve, reject) => {
|
|
2280
|
-
const rejectExit = () => reject(new Error("ACP adapter exited during initialization"));
|
|
2281
|
-
child.once("error", reject);
|
|
2282
|
-
child.once("exit", rejectExit);
|
|
2283
|
-
if (child.exitCode !== null || child.signalCode !== null) {
|
|
2284
|
-
rejectExit();
|
|
2285
|
-
}
|
|
2286
|
-
});
|
|
2287
|
-
const stdin = child.stdin;
|
|
2288
|
-
const stdout = child.stdout;
|
|
2289
|
-
const stderr = child.stderr;
|
|
2290
|
-
if (stdin === null || stdout === null || stderr === null) {
|
|
2291
|
-
await stopProcessTree(child);
|
|
2292
|
-
throw new AgentProbeError("acp_incompatible", "ACP adapter streams are unavailable");
|
|
2293
|
-
}
|
|
2294
|
-
let stderrBytes = 0;
|
|
2295
|
-
const consumeStderr = (chunk) => {
|
|
2296
|
-
stderrBytes += chunk.byteLength;
|
|
2297
|
-
if (stderrBytes > ACP_OUTPUT_LIMIT_BYTES) {
|
|
2298
|
-
controller.abort(new Error("ACP adapter output limit exceeded"));
|
|
2299
|
-
}
|
|
2300
|
-
};
|
|
2301
|
-
stderr.on("data", consumeStderr);
|
|
2302
|
-
const connection = createAcpClient(new DiscoveryAcpHandler()).connect(
|
|
2303
|
-
ndJsonStream(writableAcpStream(stdin), readableAcpStream(stdout))
|
|
2304
|
-
);
|
|
2305
|
-
try {
|
|
2306
|
-
const initialized = await Promise.race([
|
|
2307
|
-
connection.agent.request(
|
|
2308
|
-
methods4.agent.initialize,
|
|
2309
|
-
{
|
|
2310
|
-
clientCapabilities: {},
|
|
2311
|
-
clientInfo: { name: "mobius", version: "0.0.3" },
|
|
2312
|
-
protocolVersion: PROTOCOL_VERSION
|
|
2313
|
-
},
|
|
2314
|
-
{ cancellationSignal: controller.signal }
|
|
2315
|
-
),
|
|
2316
|
-
processExit
|
|
2317
|
-
]);
|
|
2318
|
-
if (initialized.protocolVersion !== PROTOCOL_VERSION) {
|
|
2319
|
-
throw new AgentProbeError("acp_incompatible", "ACP adapter selected an unsupported protocol version");
|
|
2320
|
-
}
|
|
2321
|
-
await specification.verifyAcp(connection, initialized, defaultWorkspace, controller.signal);
|
|
2322
|
-
return new VerifiedAcpReadiness(
|
|
2323
|
-
normalizedVersion(initialized.agentInfo?.version ?? ""),
|
|
2324
|
-
normalizeAcpCapabilities(initialized)
|
|
2325
|
-
);
|
|
2326
|
-
} catch (error61) {
|
|
2327
|
-
if (signal.aborted) {
|
|
2328
|
-
signal.throwIfAborted();
|
|
2329
|
-
}
|
|
2330
|
-
if (timedOut) {
|
|
2331
|
-
throw new AgentProbeError("adapter_probe_timeout", "ACP adapter probe timed out", { cause: error61 });
|
|
2332
|
-
}
|
|
2333
|
-
if (error61 instanceof AgentProbeError) {
|
|
2334
|
-
throw error61;
|
|
2335
|
-
}
|
|
2336
|
-
if (error61 instanceof RequestError && error61.code === -32e3 && specification.authenticationCommand().length > 0) {
|
|
2337
|
-
throw new AgentProbeError("authentication_required", "Agent authentication is required", { cause: error61 });
|
|
2338
|
-
}
|
|
2339
|
-
throw new AgentProbeError("acp_incompatible", "ACP adapter initialization failed", { cause: error61 });
|
|
2340
|
-
} finally {
|
|
2341
|
-
clearTimeout(timeout);
|
|
2342
|
-
signal.removeEventListener("abort", abort);
|
|
2343
|
-
connection.close();
|
|
2344
|
-
stdin.end();
|
|
2345
|
-
stderr.removeListener("data", consumeStderr);
|
|
2346
|
-
await stopProcessTree(child);
|
|
2347
|
-
}
|
|
2348
|
-
}
|
|
2349
|
-
|
|
2350
2462
|
// src/agent-catalog/discover-agent.ts
|
|
2351
2463
|
function agentProbeFailure(specification, error61) {
|
|
2352
2464
|
if (error61 instanceof AgentProbeError) {
|
|
@@ -2390,7 +2502,8 @@ async function discoverAgent(specification, context) {
|
|
|
2390
2502
|
context.environment,
|
|
2391
2503
|
context.defaultWorkspace,
|
|
2392
2504
|
context.signal,
|
|
2393
|
-
specification.versionProbeTimeoutMilliseconds
|
|
2505
|
+
specification.versionProbeTimeoutMilliseconds,
|
|
2506
|
+
specification.normalizeAgentVersion
|
|
2394
2507
|
);
|
|
2395
2508
|
} catch (error61) {
|
|
2396
2509
|
if (context.signal.aborted) {
|
|
@@ -2426,7 +2539,8 @@ async function discoverAgent(specification, context) {
|
|
|
2426
2539
|
},
|
|
2427
2540
|
context.defaultWorkspace,
|
|
2428
2541
|
context.signal,
|
|
2429
|
-
specification.versionProbeTimeoutMilliseconds
|
|
2542
|
+
specification.versionProbeTimeoutMilliseconds,
|
|
2543
|
+
specification.normalizeAdapterVersion
|
|
2430
2544
|
);
|
|
2431
2545
|
}
|
|
2432
2546
|
} catch (error61) {
|
|
@@ -2524,7 +2638,7 @@ var AuditStore = class {
|
|
|
2524
2638
|
this.database.exec("ALTER TABLE audit_events ADD COLUMN details_json TEXT NOT NULL DEFAULT '{}'");
|
|
2525
2639
|
}
|
|
2526
2640
|
}
|
|
2527
|
-
record(
|
|
2641
|
+
record(record3) {
|
|
2528
2642
|
this.database.prepare(
|
|
2529
2643
|
`
|
|
2530
2644
|
INSERT INTO audit_events (
|
|
@@ -2537,10 +2651,10 @@ var AuditStore = class {
|
|
|
2537
2651
|
`
|
|
2538
2652
|
).run(
|
|
2539
2653
|
(/* @__PURE__ */ new Date()).toISOString(),
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
|
|
2543
|
-
JSON.stringify(
|
|
2654
|
+
record3.event,
|
|
2655
|
+
record3.commandId,
|
|
2656
|
+
record3.sessionId,
|
|
2657
|
+
JSON.stringify(record3.details ?? {})
|
|
2544
2658
|
);
|
|
2545
2659
|
}
|
|
2546
2660
|
close() {
|
|
@@ -2549,7 +2663,7 @@ var AuditStore = class {
|
|
|
2549
2663
|
};
|
|
2550
2664
|
|
|
2551
2665
|
// src/config.ts
|
|
2552
|
-
import { join as
|
|
2666
|
+
import { join as join14 } from "node:path";
|
|
2553
2667
|
|
|
2554
2668
|
// ../../node_modules/.pnpm/zod@4.5.4/node_modules/zod/v4/classic/external.js
|
|
2555
2669
|
var external_exports = {};
|
|
@@ -18603,8 +18717,8 @@ function rewriteKeyNames(ctx) {
|
|
|
18603
18717
|
bySchema.set(entry.schema, entry);
|
|
18604
18718
|
}
|
|
18605
18719
|
const rewrites = /* @__PURE__ */ new Map();
|
|
18606
|
-
for (const
|
|
18607
|
-
const seen = ctx.seen.get(
|
|
18720
|
+
for (const record3 of pendingRecords.get(ctx) ?? []) {
|
|
18721
|
+
const seen = ctx.seen.get(record3);
|
|
18608
18722
|
const names = (seen?.def ?? seen?.schema)?.propertyNames;
|
|
18609
18723
|
if (!names || names === true || rewrites.has(names))
|
|
18610
18724
|
continue;
|
|
@@ -21419,6 +21533,28 @@ function date4(params) {
|
|
|
21419
21533
|
|
|
21420
21534
|
// ../protocol/src/prompt-usage.ts
|
|
21421
21535
|
var TOKEN_COUNT = external_exports.number().int().nonnegative();
|
|
21536
|
+
function normalizeQuotaTokenCount(value) {
|
|
21537
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
21538
|
+
return value;
|
|
21539
|
+
}
|
|
21540
|
+
if (Reflect.has(value, "inputTokens") || Reflect.has(value, "outputTokens") || Reflect.has(value, "totalTokens")) {
|
|
21541
|
+
return value;
|
|
21542
|
+
}
|
|
21543
|
+
if (!Reflect.has(value, "input_tokens") && !Reflect.has(value, "output_tokens")) {
|
|
21544
|
+
return value;
|
|
21545
|
+
}
|
|
21546
|
+
const inputTokens = Reflect.get(value, "input_tokens");
|
|
21547
|
+
const outputTokens = Reflect.get(value, "output_tokens");
|
|
21548
|
+
const reportedTotal = Reflect.get(value, "total_tokens");
|
|
21549
|
+
return {
|
|
21550
|
+
cachedInputTokens: Reflect.get(value, "cached_input_tokens"),
|
|
21551
|
+
cachedWriteTokens: Reflect.get(value, "cached_write_tokens"),
|
|
21552
|
+
inputTokens,
|
|
21553
|
+
outputTokens,
|
|
21554
|
+
reasoningOutputTokens: Reflect.get(value, "reasoning_output_tokens"),
|
|
21555
|
+
totalTokens: reportedTotal === void 0 && typeof inputTokens === "number" && typeof outputTokens === "number" ? inputTokens + outputTokens : reportedTotal
|
|
21556
|
+
};
|
|
21557
|
+
}
|
|
21422
21558
|
var promptUsageSchema = external_exports.object({
|
|
21423
21559
|
cachedReadTokens: TOKEN_COUNT.nullish(),
|
|
21424
21560
|
cachedWriteTokens: TOKEN_COUNT.nullish(),
|
|
@@ -21427,14 +21563,17 @@ var promptUsageSchema = external_exports.object({
|
|
|
21427
21563
|
thoughtTokens: TOKEN_COUNT.nullish(),
|
|
21428
21564
|
totalTokens: TOKEN_COUNT
|
|
21429
21565
|
}).readonly();
|
|
21430
|
-
var quotaTokenCountSchema = external_exports.
|
|
21431
|
-
|
|
21432
|
-
|
|
21433
|
-
|
|
21434
|
-
|
|
21435
|
-
|
|
21436
|
-
|
|
21437
|
-
|
|
21566
|
+
var quotaTokenCountSchema = external_exports.preprocess(
|
|
21567
|
+
normalizeQuotaTokenCount,
|
|
21568
|
+
external_exports.object({
|
|
21569
|
+
cachedInputTokens: TOKEN_COUNT.optional(),
|
|
21570
|
+
cachedWriteTokens: TOKEN_COUNT.optional(),
|
|
21571
|
+
inputTokens: TOKEN_COUNT,
|
|
21572
|
+
outputTokens: TOKEN_COUNT,
|
|
21573
|
+
reasoningOutputTokens: TOKEN_COUNT.optional(),
|
|
21574
|
+
totalTokens: TOKEN_COUNT
|
|
21575
|
+
}).readonly()
|
|
21576
|
+
);
|
|
21438
21577
|
var promptMetadataSchema = external_exports.object({
|
|
21439
21578
|
quota: external_exports.object({
|
|
21440
21579
|
model_usage: external_exports.array(
|
|
@@ -21561,6 +21700,7 @@ var elicitationFieldSchema = external_exports.strictObject({
|
|
|
21561
21700
|
type: external_exports.enum(["boolean", "integer", "multiselect", "number", "select", "string"])
|
|
21562
21701
|
}).readonly();
|
|
21563
21702
|
var displayContentSchema = external_exports.strictObject({
|
|
21703
|
+
artifactId: external_exports.string().max(128).default(""),
|
|
21564
21704
|
data: external_exports.string().max(4e6),
|
|
21565
21705
|
mimeType: external_exports.string().max(255),
|
|
21566
21706
|
name: external_exports.string().max(500),
|
|
@@ -21573,6 +21713,7 @@ var displayContentSchema = external_exports.strictObject({
|
|
|
21573
21713
|
uri: external_exports.string().max(4096)
|
|
21574
21714
|
}).readonly();
|
|
21575
21715
|
var recordedDisplayContentSchema = external_exports.strictObject({
|
|
21716
|
+
artifactId: external_exports.string().max(128).default(""),
|
|
21576
21717
|
data: external_exports.string().max(4e6),
|
|
21577
21718
|
mimeType: external_exports.string().max(255),
|
|
21578
21719
|
name: external_exports.string().max(500),
|
|
@@ -23060,7 +23201,7 @@ var decodeSessionEventRejection = (encoded) => decode5(encoded, eventRejectionSc
|
|
|
23060
23201
|
// src/config.ts
|
|
23061
23202
|
function loadDefaultWorkspace(environment = process.env) {
|
|
23062
23203
|
const { MOBIUS_DEFAULT_WORKSPACE: configuredWorkspace } = environment;
|
|
23063
|
-
return configuredWorkspace ??
|
|
23204
|
+
return configuredWorkspace ?? join14(readStateDirectory(environment), "workspace");
|
|
23064
23205
|
}
|
|
23065
23206
|
function createDaemonConfig(connection, agents = [], installableAgents = []) {
|
|
23066
23207
|
return {
|
|
@@ -23077,9 +23218,9 @@ function createDaemonConfig(connection, agents = [], installableAgents = []) {
|
|
|
23077
23218
|
|
|
23078
23219
|
// src/run-daemon.ts
|
|
23079
23220
|
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
23080
|
-
import { basename as
|
|
23221
|
+
import { basename as basename4, join as join16 } from "node:path";
|
|
23081
23222
|
import { styleText } from "node:util";
|
|
23082
|
-
import { fetch as
|
|
23223
|
+
import { fetch as fetch6, WebSocket as WebSocket2 } from "undici";
|
|
23083
23224
|
|
|
23084
23225
|
// src/acp/session-manager.ts
|
|
23085
23226
|
import { spawn as spawn3 } from "node:child_process";
|
|
@@ -23090,6 +23231,212 @@ import {
|
|
|
23090
23231
|
RequestError as RequestError2
|
|
23091
23232
|
} from "@agentclientprotocol/sdk";
|
|
23092
23233
|
|
|
23234
|
+
// src/authorization/local-raster.ts
|
|
23235
|
+
import { readFile, realpath as realpath6, stat as stat5 } from "node:fs/promises";
|
|
23236
|
+
import { basename, isAbsolute as isAbsolute8, normalize as normalize2, relative as relative4, sep as sep4 } from "node:path";
|
|
23237
|
+
import { fileURLToPath } from "node:url";
|
|
23238
|
+
var MAX_LOCAL_RASTER_BYTES = 3e6;
|
|
23239
|
+
var PNG_SIGNATURE = Uint8Array.of(137, 80, 78, 71);
|
|
23240
|
+
var JPEG_SIGNATURE = Uint8Array.of(255, 216, 255);
|
|
23241
|
+
var GIF87_SIGNATURE = new TextEncoder().encode("GIF87a");
|
|
23242
|
+
var GIF89_SIGNATURE = new TextEncoder().encode("GIF89a");
|
|
23243
|
+
var RIFF_SIGNATURE = new TextEncoder().encode("RIFF");
|
|
23244
|
+
var WEBP_SIGNATURE = new TextEncoder().encode("WEBP");
|
|
23245
|
+
var LocalRasterImage = class {
|
|
23246
|
+
bytes;
|
|
23247
|
+
mimeType;
|
|
23248
|
+
name;
|
|
23249
|
+
constructor(name, mimeType, bytes) {
|
|
23250
|
+
this.bytes = bytes;
|
|
23251
|
+
this.mimeType = mimeType;
|
|
23252
|
+
this.name = name;
|
|
23253
|
+
}
|
|
23254
|
+
base64 = () => Buffer.from(this.bytes).toString("base64");
|
|
23255
|
+
};
|
|
23256
|
+
function startsWith(bytes, signature, offset = 0) {
|
|
23257
|
+
if (bytes.byteLength < offset + signature.byteLength) {
|
|
23258
|
+
return false;
|
|
23259
|
+
}
|
|
23260
|
+
return signature.every((value, index) => bytes[offset + index] === value);
|
|
23261
|
+
}
|
|
23262
|
+
function sniffRasterMime(bytes) {
|
|
23263
|
+
if (startsWith(bytes, PNG_SIGNATURE)) {
|
|
23264
|
+
return "image/png";
|
|
23265
|
+
}
|
|
23266
|
+
if (startsWith(bytes, JPEG_SIGNATURE)) {
|
|
23267
|
+
return "image/jpeg";
|
|
23268
|
+
}
|
|
23269
|
+
if (startsWith(bytes, GIF87_SIGNATURE) || startsWith(bytes, GIF89_SIGNATURE)) {
|
|
23270
|
+
return "image/gif";
|
|
23271
|
+
}
|
|
23272
|
+
if (startsWith(bytes, RIFF_SIGNATURE) && startsWith(bytes, WEBP_SIGNATURE, 8)) {
|
|
23273
|
+
return "image/webp";
|
|
23274
|
+
}
|
|
23275
|
+
return null;
|
|
23276
|
+
}
|
|
23277
|
+
function isInsideRoot(root, target) {
|
|
23278
|
+
const relation = relative4(root, target);
|
|
23279
|
+
return relation !== ".." && !relation.startsWith(`..${sep4}`) && !isAbsolute8(relation);
|
|
23280
|
+
}
|
|
23281
|
+
async function resolveCanonicalPath(requested, signal) {
|
|
23282
|
+
signal.throwIfAborted();
|
|
23283
|
+
if (!isAbsolute8(requested) || requested.includes("\0") || normalize2(requested) !== requested) {
|
|
23284
|
+
return null;
|
|
23285
|
+
}
|
|
23286
|
+
try {
|
|
23287
|
+
const target = await realpath6(requested);
|
|
23288
|
+
signal.throwIfAborted();
|
|
23289
|
+
if (!isAbsolute8(target) || normalize2(target) !== target) {
|
|
23290
|
+
return null;
|
|
23291
|
+
}
|
|
23292
|
+
return target;
|
|
23293
|
+
} catch (cause) {
|
|
23294
|
+
signal.throwIfAborted();
|
|
23295
|
+
if (cause instanceof Error && cause.name === "AbortError") {
|
|
23296
|
+
throw cause;
|
|
23297
|
+
}
|
|
23298
|
+
return null;
|
|
23299
|
+
}
|
|
23300
|
+
}
|
|
23301
|
+
function parseLocalImageUri(uri) {
|
|
23302
|
+
const trimmed = uri.trim();
|
|
23303
|
+
if (trimmed.length === 0 || trimmed.length > 2048 || trimmed.includes("\0")) {
|
|
23304
|
+
return null;
|
|
23305
|
+
}
|
|
23306
|
+
if (trimmed.startsWith("data:")) {
|
|
23307
|
+
return null;
|
|
23308
|
+
}
|
|
23309
|
+
if (trimmed.startsWith("file:")) {
|
|
23310
|
+
try {
|
|
23311
|
+
const url2 = new URL(trimmed);
|
|
23312
|
+
if (url2.protocol !== "file:" || url2.host.length > 0) {
|
|
23313
|
+
return null;
|
|
23314
|
+
}
|
|
23315
|
+
return fileURLToPath(url2);
|
|
23316
|
+
} catch {
|
|
23317
|
+
return null;
|
|
23318
|
+
}
|
|
23319
|
+
}
|
|
23320
|
+
if (/^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(trimmed)) {
|
|
23321
|
+
return null;
|
|
23322
|
+
}
|
|
23323
|
+
return trimmed;
|
|
23324
|
+
}
|
|
23325
|
+
async function readAuthorizedRaster(uri, roots, signal) {
|
|
23326
|
+
signal.throwIfAborted();
|
|
23327
|
+
const requested = parseLocalImageUri(uri);
|
|
23328
|
+
if (requested === null) {
|
|
23329
|
+
return null;
|
|
23330
|
+
}
|
|
23331
|
+
const target = await resolveCanonicalPath(requested, signal);
|
|
23332
|
+
if (target === null) {
|
|
23333
|
+
return null;
|
|
23334
|
+
}
|
|
23335
|
+
const targetMetadata = await stat5(target);
|
|
23336
|
+
signal.throwIfAborted();
|
|
23337
|
+
if (!targetMetadata.isFile() || targetMetadata.size < 1 || targetMetadata.size > MAX_LOCAL_RASTER_BYTES) {
|
|
23338
|
+
return null;
|
|
23339
|
+
}
|
|
23340
|
+
const authorizedRoots = [];
|
|
23341
|
+
for (const root of roots) {
|
|
23342
|
+
const directory = await resolveCanonicalPath(root, signal);
|
|
23343
|
+
if (directory === null) {
|
|
23344
|
+
continue;
|
|
23345
|
+
}
|
|
23346
|
+
const metadata = await stat5(directory);
|
|
23347
|
+
signal.throwIfAborted();
|
|
23348
|
+
if (metadata.isDirectory()) {
|
|
23349
|
+
authorizedRoots.push(directory);
|
|
23350
|
+
}
|
|
23351
|
+
}
|
|
23352
|
+
if (!authorizedRoots.some((root) => isInsideRoot(root, target))) {
|
|
23353
|
+
return null;
|
|
23354
|
+
}
|
|
23355
|
+
const bytes = new Uint8Array(await readFile(target));
|
|
23356
|
+
signal.throwIfAborted();
|
|
23357
|
+
if (bytes.byteLength < 1 || bytes.byteLength > MAX_LOCAL_RASTER_BYTES) {
|
|
23358
|
+
return null;
|
|
23359
|
+
}
|
|
23360
|
+
const mimeType = sniffRasterMime(bytes);
|
|
23361
|
+
if (mimeType === null) {
|
|
23362
|
+
return null;
|
|
23363
|
+
}
|
|
23364
|
+
return new LocalRasterImage(basename(target) || "Image", mimeType, bytes);
|
|
23365
|
+
}
|
|
23366
|
+
|
|
23367
|
+
// src/native-sessions/history-images.ts
|
|
23368
|
+
var IMAGE_MARKER = /\[@image\]\(([^)\r\n]*)(?:\)|$)/g;
|
|
23369
|
+
async function embedLocalHistoryImages(history, roots, signal) {
|
|
23370
|
+
if (history.status !== "available") {
|
|
23371
|
+
return history;
|
|
23372
|
+
}
|
|
23373
|
+
const messages = [];
|
|
23374
|
+
let imageCharacters = 0;
|
|
23375
|
+
for (const message of history.messages) {
|
|
23376
|
+
signal.throwIfAborted();
|
|
23377
|
+
const resolved = await resolveMessageImages(message, roots, imageCharacters, signal);
|
|
23378
|
+
imageCharacters += (resolved.images ?? []).reduce((size, image) => size + image.data.length, 0);
|
|
23379
|
+
messages.push(resolved);
|
|
23380
|
+
}
|
|
23381
|
+
return {
|
|
23382
|
+
...history,
|
|
23383
|
+
messages
|
|
23384
|
+
};
|
|
23385
|
+
}
|
|
23386
|
+
async function resolveMessageImages(message, roots, usedCharacters, signal) {
|
|
23387
|
+
const images = [...message.images ?? []];
|
|
23388
|
+
let imageCharacters = images.reduce((size, image) => size + image.data.length, 0);
|
|
23389
|
+
const text = await replaceImageMarkers(message.text, async (uri) => {
|
|
23390
|
+
if (images.length >= 8 || usedCharacters + imageCharacters >= SESSION_HISTORY_IMAGE_CHARACTER_LIMIT) {
|
|
23391
|
+
return "[Image unavailable]";
|
|
23392
|
+
}
|
|
23393
|
+
const embedded = parseNativeHistoryText(`[@image](${uri})`).images[0];
|
|
23394
|
+
if (embedded !== void 0) {
|
|
23395
|
+
if (usedCharacters + imageCharacters + embedded.data.length > SESSION_HISTORY_IMAGE_CHARACTER_LIMIT) {
|
|
23396
|
+
return "[Image unavailable]";
|
|
23397
|
+
}
|
|
23398
|
+
images.push(embedded);
|
|
23399
|
+
imageCharacters += embedded.data.length;
|
|
23400
|
+
return "";
|
|
23401
|
+
}
|
|
23402
|
+
const local = await readAuthorizedRaster(uri, roots, signal);
|
|
23403
|
+
if (local === null) {
|
|
23404
|
+
return "[Image unavailable]";
|
|
23405
|
+
}
|
|
23406
|
+
const data = local.base64();
|
|
23407
|
+
if (usedCharacters + imageCharacters + data.length > SESSION_HISTORY_IMAGE_CHARACTER_LIMIT) {
|
|
23408
|
+
return "[Image unavailable]";
|
|
23409
|
+
}
|
|
23410
|
+
images.push({
|
|
23411
|
+
data,
|
|
23412
|
+
mimeType: local.mimeType,
|
|
23413
|
+
name: local.name
|
|
23414
|
+
});
|
|
23415
|
+
imageCharacters += data.length;
|
|
23416
|
+
return "";
|
|
23417
|
+
});
|
|
23418
|
+
return {
|
|
23419
|
+
...message,
|
|
23420
|
+
text,
|
|
23421
|
+
...images.length > 0 ? { images } : {}
|
|
23422
|
+
};
|
|
23423
|
+
}
|
|
23424
|
+
async function replaceImageMarkers(text, replace) {
|
|
23425
|
+
const matches = [...text.matchAll(IMAGE_MARKER)];
|
|
23426
|
+
if (matches.length === 0) {
|
|
23427
|
+
return text;
|
|
23428
|
+
}
|
|
23429
|
+
let cursor = 0;
|
|
23430
|
+
let rewritten = "";
|
|
23431
|
+
for (const match of matches) {
|
|
23432
|
+
const index = match.index ?? 0;
|
|
23433
|
+
rewritten += text.slice(cursor, index);
|
|
23434
|
+
rewritten += await replace(match[1] ?? "");
|
|
23435
|
+
cursor = index + match[0].length;
|
|
23436
|
+
}
|
|
23437
|
+
return `${rewritten}${text.slice(cursor)}`;
|
|
23438
|
+
}
|
|
23439
|
+
|
|
23093
23440
|
// src/acp/activity.ts
|
|
23094
23441
|
var TRUNCATION_MARKER = "\n\u2026 output truncated by Mobius";
|
|
23095
23442
|
function isRecord6(value) {
|
|
@@ -23187,6 +23534,7 @@ function readContentOutputDetail(content) {
|
|
|
23187
23534
|
function summarizeDisplayContent(content) {
|
|
23188
23535
|
return {
|
|
23189
23536
|
...content,
|
|
23537
|
+
artifactId: truncate(content.artifactId, 128),
|
|
23190
23538
|
data: truncate(content.data, AGENT_ACTIVITY_DETAIL_LIMIT),
|
|
23191
23539
|
mimeType: truncate(content.mimeType, 255),
|
|
23192
23540
|
name: truncate(content.name, 500),
|
|
@@ -23199,7 +23547,7 @@ function summarizeDisplayContent(content) {
|
|
|
23199
23547
|
};
|
|
23200
23548
|
}
|
|
23201
23549
|
function contentFitsRecordingEnvelope(content) {
|
|
23202
|
-
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;
|
|
23550
|
+
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;
|
|
23203
23551
|
}
|
|
23204
23552
|
function encodedByteLength(value) {
|
|
23205
23553
|
return new TextEncoder().encode(JSON.stringify(value)).byteLength;
|
|
@@ -23225,6 +23573,7 @@ function recordedDetail(activity) {
|
|
|
23225
23573
|
}
|
|
23226
23574
|
function emptyDisplayContent(type) {
|
|
23227
23575
|
return {
|
|
23576
|
+
artifactId: "",
|
|
23228
23577
|
data: "",
|
|
23229
23578
|
mimeType: "",
|
|
23230
23579
|
name: "",
|
|
@@ -23237,6 +23586,16 @@ function emptyDisplayContent(type) {
|
|
|
23237
23586
|
uri: ""
|
|
23238
23587
|
};
|
|
23239
23588
|
}
|
|
23589
|
+
function imageDisplayContent(mimeType, name, data, artifactId = "", uri = "") {
|
|
23590
|
+
return {
|
|
23591
|
+
...emptyDisplayContent("image"),
|
|
23592
|
+
artifactId,
|
|
23593
|
+
data,
|
|
23594
|
+
mimeType,
|
|
23595
|
+
name,
|
|
23596
|
+
uri
|
|
23597
|
+
};
|
|
23598
|
+
}
|
|
23240
23599
|
function normalizeContentBlock(content) {
|
|
23241
23600
|
if (content.type === "text") {
|
|
23242
23601
|
return { ...emptyDisplayContent("text"), text: content.text };
|
|
@@ -24028,7 +24387,6 @@ var AcpHistoryReplay = class {
|
|
|
24028
24387
|
#messages = [];
|
|
24029
24388
|
#lastMessageId = null;
|
|
24030
24389
|
#characters = 0;
|
|
24031
|
-
#imageCharacters = 0;
|
|
24032
24390
|
#truncated = false;
|
|
24033
24391
|
record = (update) => {
|
|
24034
24392
|
if (update.sessionUpdate !== "user_message_chunk" && update.sessionUpdate !== "agent_message_chunk") {
|
|
@@ -24039,40 +24397,30 @@ var AcpHistoryReplay = class {
|
|
|
24039
24397
|
}
|
|
24040
24398
|
const role = update.sessionUpdate === "user_message_chunk" ? "user" : "assistant";
|
|
24041
24399
|
const content = update.content;
|
|
24042
|
-
const
|
|
24043
|
-
|
|
24044
|
-
);
|
|
24045
|
-
const text = parsed.text;
|
|
24046
|
-
if (text.length === 0 && parsed.images.length === 0) {
|
|
24400
|
+
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]`;
|
|
24401
|
+
if (text.length === 0) {
|
|
24047
24402
|
return;
|
|
24048
24403
|
}
|
|
24049
24404
|
const previous = this.#messages.at(-1);
|
|
24050
24405
|
const id = update.messageId ?? null;
|
|
24051
24406
|
const continuation = previous?.role === role && id === this.#lastMessageId;
|
|
24052
24407
|
const combined = continuation ? `${previous.text}${text}` : text;
|
|
24053
|
-
const allImages = continuation ? [...previous.images ?? [], ...parsed.images] : parsed.images;
|
|
24054
|
-
const images = allImages.slice(0, 8);
|
|
24055
|
-
this.#truncated ||= images.length < allImages.length;
|
|
24056
24408
|
if (continuation) {
|
|
24057
24409
|
this.#messages.pop();
|
|
24058
24410
|
this.#characters -= previous.text.length;
|
|
24059
|
-
this.#imageCharacters -= (previous.images ?? []).reduce((size, image) => size + image.data.length, 0);
|
|
24060
24411
|
}
|
|
24061
24412
|
const bounded = combined.slice(-SESSION_HISTORY_CHARACTER_LIMIT);
|
|
24062
24413
|
this.#truncated ||= bounded.length < combined.length;
|
|
24063
24414
|
this.#messages.push({
|
|
24064
24415
|
role,
|
|
24065
|
-
text: bounded
|
|
24066
|
-
...images.length > 0 ? { images } : {}
|
|
24416
|
+
text: bounded
|
|
24067
24417
|
});
|
|
24068
24418
|
this.#characters += bounded.length;
|
|
24069
|
-
this.#imageCharacters += images.reduce((size, image) => size + image.data.length, 0);
|
|
24070
24419
|
this.#lastMessageId = id;
|
|
24071
|
-
while (this.#messages.length > SESSION_HISTORY_PREVIEW_MESSAGE_LIMIT || this.#characters > SESSION_HISTORY_CHARACTER_LIMIT
|
|
24420
|
+
while (this.#messages.length > SESSION_HISTORY_PREVIEW_MESSAGE_LIMIT || this.#characters > SESSION_HISTORY_CHARACTER_LIMIT) {
|
|
24072
24421
|
const removed = this.#messages.shift();
|
|
24073
24422
|
if (removed !== void 0) {
|
|
24074
24423
|
this.#characters -= removed.text.length;
|
|
24075
|
-
this.#imageCharacters -= (removed.images ?? []).reduce((size, image) => size + image.data.length, 0);
|
|
24076
24424
|
}
|
|
24077
24425
|
this.#truncated = true;
|
|
24078
24426
|
}
|
|
@@ -24295,6 +24643,10 @@ var MAX_PRE_SESSION_UPDATES = 100;
|
|
|
24295
24643
|
var MAX_PRE_SESSION_UPDATE_BYTES = 1024 * 1024;
|
|
24296
24644
|
var SESSION_CONTROL_COMMAND_ID = "session-control";
|
|
24297
24645
|
var NullAcpSessionObserver = class {
|
|
24646
|
+
importLocalImage = (_sessionId, _image, signal) => {
|
|
24647
|
+
signal.throwIfAborted();
|
|
24648
|
+
return Promise.resolve("");
|
|
24649
|
+
};
|
|
24298
24650
|
onCommands = () => Promise.resolve();
|
|
24299
24651
|
onConfig = () => Promise.resolve();
|
|
24300
24652
|
onContent = () => Promise.resolve();
|
|
@@ -24917,11 +25269,75 @@ var AcpProcessSession = class _AcpProcessSession {
|
|
|
24917
25269
|
);
|
|
24918
25270
|
await this.#updateTail;
|
|
24919
25271
|
signal.throwIfAborted();
|
|
24920
|
-
return
|
|
25272
|
+
return await embedLocalHistoryImages(
|
|
25273
|
+
history.snapshot(),
|
|
25274
|
+
[this.#cwd, ...this.#additionalDirectories],
|
|
25275
|
+
signal
|
|
25276
|
+
);
|
|
24921
25277
|
} finally {
|
|
24922
25278
|
this.#replay = { kind: "idle" };
|
|
24923
25279
|
}
|
|
24924
25280
|
};
|
|
25281
|
+
imageRoots = () => [this.#cwd, ...this.#additionalDirectories];
|
|
25282
|
+
emitAgentText = async (text, messageId) => {
|
|
25283
|
+
const signal = AbortSignal.timeout(2e4);
|
|
25284
|
+
const parts = text.split(/(\[@image\]\([^)\r\n]*(?:\)|$))/);
|
|
25285
|
+
let leftover = "";
|
|
25286
|
+
for (const part of parts) {
|
|
25287
|
+
const marker = /^\[@image\]\(([^)\r\n]*)(?:\)|$)/.exec(part);
|
|
25288
|
+
if (marker === null) {
|
|
25289
|
+
leftover += part;
|
|
25290
|
+
continue;
|
|
25291
|
+
}
|
|
25292
|
+
if (leftover.length > 0) {
|
|
25293
|
+
await this.#turn.onText(leftover, messageId);
|
|
25294
|
+
leftover = "";
|
|
25295
|
+
}
|
|
25296
|
+
const raster = await readAuthorizedRaster(marker[1] ?? "", this.imageRoots(), signal);
|
|
25297
|
+
if (raster === null) {
|
|
25298
|
+
leftover += "[Image unavailable]";
|
|
25299
|
+
continue;
|
|
25300
|
+
}
|
|
25301
|
+
await this.emitRaster(raster, messageId, signal);
|
|
25302
|
+
}
|
|
25303
|
+
if (leftover.length > 0) {
|
|
25304
|
+
await this.#turn.onText(leftover, messageId);
|
|
25305
|
+
}
|
|
25306
|
+
};
|
|
25307
|
+
emitAgentContent = async (content, messageId) => {
|
|
25308
|
+
if (content.type === "image" && content.data.length === 0 && content.uri.length > 0) {
|
|
25309
|
+
const signal = AbortSignal.timeout(2e4);
|
|
25310
|
+
const raster = await readAuthorizedRaster(content.uri, this.imageRoots(), signal);
|
|
25311
|
+
if (raster !== null) {
|
|
25312
|
+
await this.emitRaster(raster, messageId, signal);
|
|
25313
|
+
return;
|
|
25314
|
+
}
|
|
25315
|
+
}
|
|
25316
|
+
await this.#getObserver().onContent({
|
|
25317
|
+
commandId: this.#turn.commandId,
|
|
25318
|
+
content,
|
|
25319
|
+
contentId: `content-${crypto.randomUUID()}`,
|
|
25320
|
+
kind: AGENT_CONTENT_KIND,
|
|
25321
|
+
messageId,
|
|
25322
|
+
sessionId: this.#mobiusSessionId
|
|
25323
|
+
});
|
|
25324
|
+
};
|
|
25325
|
+
emitRaster = async (raster, messageId, signal) => {
|
|
25326
|
+
const artifactId = await this.#getObserver().importLocalImage(this.#mobiusSessionId, raster, signal);
|
|
25327
|
+
await this.#getObserver().onContent({
|
|
25328
|
+
commandId: this.#turn.commandId,
|
|
25329
|
+
content: imageDisplayContent(
|
|
25330
|
+
raster.mimeType,
|
|
25331
|
+
raster.name,
|
|
25332
|
+
artifactId.length > 0 ? "" : raster.base64(),
|
|
25333
|
+
artifactId
|
|
25334
|
+
),
|
|
25335
|
+
contentId: `content-${crypto.randomUUID()}`,
|
|
25336
|
+
kind: AGENT_CONTENT_KIND,
|
|
25337
|
+
messageId,
|
|
25338
|
+
sessionId: this.#mobiusSessionId
|
|
25339
|
+
});
|
|
25340
|
+
};
|
|
24925
25341
|
async #initializeAgent(signal) {
|
|
24926
25342
|
const initialized = await this.race(
|
|
24927
25343
|
this.#connection.agent.request(
|
|
@@ -25624,18 +26040,14 @@ var AcpProcessSession = class _AcpProcessSession {
|
|
|
25624
26040
|
);
|
|
25625
26041
|
} else {
|
|
25626
26042
|
await this.#turn.activities.finishNarrative();
|
|
25627
|
-
await this
|
|
26043
|
+
await this.emitAgentText(update.content.text, truncate3(update.messageId ?? "", 255));
|
|
25628
26044
|
}
|
|
25629
26045
|
} else {
|
|
25630
26046
|
await this.#turn.activities.finishNarrative();
|
|
25631
|
-
await this
|
|
25632
|
-
|
|
25633
|
-
|
|
25634
|
-
|
|
25635
|
-
kind: AGENT_CONTENT_KIND,
|
|
25636
|
-
messageId: truncate3(update.messageId ?? "", 255),
|
|
25637
|
-
sessionId: this.#mobiusSessionId
|
|
25638
|
-
});
|
|
26047
|
+
await this.emitAgentContent(
|
|
26048
|
+
normalizeContentBlock(update.content),
|
|
26049
|
+
truncate3(update.messageId ?? "", 255)
|
|
26050
|
+
);
|
|
25639
26051
|
}
|
|
25640
26052
|
return;
|
|
25641
26053
|
}
|
|
@@ -26996,6 +27408,402 @@ var FixedInstallationExecutor = class {
|
|
|
26996
27408
|
};
|
|
26997
27409
|
};
|
|
26998
27410
|
|
|
27411
|
+
// src/artifacts/runtime-artifact-uploader.ts
|
|
27412
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
27413
|
+
|
|
27414
|
+
// ../mobius-sdk/src/errors.ts
|
|
27415
|
+
var MobiusError = class extends Error {
|
|
27416
|
+
code;
|
|
27417
|
+
constructor(code, message, options = {}) {
|
|
27418
|
+
super(message, options);
|
|
27419
|
+
this.code = code;
|
|
27420
|
+
this.name = "MobiusError";
|
|
27421
|
+
}
|
|
27422
|
+
};
|
|
27423
|
+
var MobiusProtocolError = class extends MobiusError {
|
|
27424
|
+
constructor(message, options = {}) {
|
|
27425
|
+
super("invalid_service_response", message, options);
|
|
27426
|
+
this.name = "MobiusProtocolError";
|
|
27427
|
+
}
|
|
27428
|
+
};
|
|
27429
|
+
var MobiusValidationError = class extends MobiusError {
|
|
27430
|
+
constructor(message, options = {}) {
|
|
27431
|
+
super("invalid_request", message, options);
|
|
27432
|
+
this.name = "MobiusValidationError";
|
|
27433
|
+
}
|
|
27434
|
+
};
|
|
27435
|
+
|
|
27436
|
+
// ../mobius-sdk/src/resources.ts
|
|
27437
|
+
var IDENTIFIER_PATTERN5 = /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/;
|
|
27438
|
+
function invalidResponse(message) {
|
|
27439
|
+
return new MobiusProtocolError(message);
|
|
27440
|
+
}
|
|
27441
|
+
function isRecord9(value) {
|
|
27442
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
27443
|
+
}
|
|
27444
|
+
function record2(value, name) {
|
|
27445
|
+
if (!isRecord9(value)) {
|
|
27446
|
+
throw invalidResponse(`The service returned an invalid ${name}`);
|
|
27447
|
+
}
|
|
27448
|
+
return value;
|
|
27449
|
+
}
|
|
27450
|
+
function stringField(value, field, maximumLength = 85e5) {
|
|
27451
|
+
const candidate = value[field];
|
|
27452
|
+
if (typeof candidate !== "string" || candidate.length > maximumLength) {
|
|
27453
|
+
throw invalidResponse(`The service returned an invalid ${field}`);
|
|
27454
|
+
}
|
|
27455
|
+
return candidate;
|
|
27456
|
+
}
|
|
27457
|
+
function identifierField(value, field) {
|
|
27458
|
+
const candidate = stringField(value, field, 128);
|
|
27459
|
+
if (!IDENTIFIER_PATTERN5.test(candidate)) {
|
|
27460
|
+
throw invalidResponse(`The service returned an invalid ${field}`);
|
|
27461
|
+
}
|
|
27462
|
+
return candidate;
|
|
27463
|
+
}
|
|
27464
|
+
function integerField(value, field) {
|
|
27465
|
+
const candidate = value[field];
|
|
27466
|
+
if (typeof candidate !== "number" || !Number.isSafeInteger(candidate) || candidate < 0) {
|
|
27467
|
+
throw invalidResponse(`The service returned an invalid ${field}`);
|
|
27468
|
+
}
|
|
27469
|
+
return candidate;
|
|
27470
|
+
}
|
|
27471
|
+
function validateTimestamp(value, field) {
|
|
27472
|
+
if (Number.isNaN(Date.parse(value))) {
|
|
27473
|
+
throw invalidResponse(`The service returned an invalid ${field}`);
|
|
27474
|
+
}
|
|
27475
|
+
return value;
|
|
27476
|
+
}
|
|
27477
|
+
var MobiusArtifactUploadRequest = class {
|
|
27478
|
+
byteLength;
|
|
27479
|
+
mediaType;
|
|
27480
|
+
name;
|
|
27481
|
+
sha256;
|
|
27482
|
+
constructor(name, mediaType, byteLength, sha256) {
|
|
27483
|
+
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)) {
|
|
27484
|
+
throw new MobiusValidationError("The artifact upload request is invalid");
|
|
27485
|
+
}
|
|
27486
|
+
this.byteLength = byteLength;
|
|
27487
|
+
this.mediaType = mediaType;
|
|
27488
|
+
this.name = name;
|
|
27489
|
+
this.sha256 = sha256;
|
|
27490
|
+
}
|
|
27491
|
+
};
|
|
27492
|
+
var MobiusArtifact = class {
|
|
27493
|
+
artifactId;
|
|
27494
|
+
byteLength;
|
|
27495
|
+
createdAt;
|
|
27496
|
+
mediaType;
|
|
27497
|
+
name;
|
|
27498
|
+
sessionId;
|
|
27499
|
+
sha256;
|
|
27500
|
+
constructor(sessionId, artifactId, name, mediaType, byteLength, sha256, createdAt) {
|
|
27501
|
+
this.artifactId = artifactId;
|
|
27502
|
+
this.byteLength = byteLength;
|
|
27503
|
+
this.createdAt = createdAt;
|
|
27504
|
+
this.mediaType = mediaType;
|
|
27505
|
+
this.name = name;
|
|
27506
|
+
this.sessionId = sessionId;
|
|
27507
|
+
this.sha256 = sha256;
|
|
27508
|
+
}
|
|
27509
|
+
};
|
|
27510
|
+
var MobiusUploadingArtifact = class extends MobiusArtifact {
|
|
27511
|
+
expiresAt;
|
|
27512
|
+
state = "uploading";
|
|
27513
|
+
constructor(sessionId, artifactId, name, mediaType, byteLength, sha256, createdAt, expiresAt) {
|
|
27514
|
+
super(sessionId, artifactId, name, mediaType, byteLength, sha256, createdAt);
|
|
27515
|
+
this.expiresAt = expiresAt;
|
|
27516
|
+
}
|
|
27517
|
+
};
|
|
27518
|
+
var MobiusArtifactUpload = class extends MobiusUploadingArtifact {
|
|
27519
|
+
uploadToken;
|
|
27520
|
+
constructor(artifact, uploadToken) {
|
|
27521
|
+
super(
|
|
27522
|
+
artifact.sessionId,
|
|
27523
|
+
artifact.artifactId,
|
|
27524
|
+
artifact.name,
|
|
27525
|
+
artifact.mediaType,
|
|
27526
|
+
artifact.byteLength,
|
|
27527
|
+
artifact.sha256,
|
|
27528
|
+
artifact.createdAt,
|
|
27529
|
+
artifact.expiresAt
|
|
27530
|
+
);
|
|
27531
|
+
this.uploadToken = uploadToken;
|
|
27532
|
+
}
|
|
27533
|
+
};
|
|
27534
|
+
var MobiusAvailableArtifact = class extends MobiusArtifact {
|
|
27535
|
+
availableAt;
|
|
27536
|
+
state = "available";
|
|
27537
|
+
constructor(sessionId, artifactId, name, mediaType, byteLength, sha256, createdAt, availableAt) {
|
|
27538
|
+
super(sessionId, artifactId, name, mediaType, byteLength, sha256, createdAt);
|
|
27539
|
+
this.availableAt = availableAt;
|
|
27540
|
+
}
|
|
27541
|
+
};
|
|
27542
|
+
var MobiusExpiredArtifact = class extends MobiusArtifact {
|
|
27543
|
+
expiredAt;
|
|
27544
|
+
state = "expired";
|
|
27545
|
+
constructor(sessionId, artifactId, name, mediaType, byteLength, sha256, createdAt, expiredAt) {
|
|
27546
|
+
super(sessionId, artifactId, name, mediaType, byteLength, sha256, createdAt);
|
|
27547
|
+
this.expiredAt = expiredAt;
|
|
27548
|
+
}
|
|
27549
|
+
};
|
|
27550
|
+
function artifactFields(value) {
|
|
27551
|
+
const sha256 = stringField(value, "sha256", 64);
|
|
27552
|
+
if (!/^[a-f0-9]{64}$/.test(sha256)) {
|
|
27553
|
+
throw invalidResponse("The service returned an invalid artifact digest");
|
|
27554
|
+
}
|
|
27555
|
+
return {
|
|
27556
|
+
artifactId: identifierField(value, "artifactId"),
|
|
27557
|
+
byteLength: integerField(value, "byteLength"),
|
|
27558
|
+
createdAt: validateTimestamp(stringField(value, "createdAt", 128), "createdAt"),
|
|
27559
|
+
mediaType: stringField(value, "mediaType", 255),
|
|
27560
|
+
name: stringField(value, "name", 500),
|
|
27561
|
+
sessionId: identifierField(value, "sessionId"),
|
|
27562
|
+
sha256
|
|
27563
|
+
};
|
|
27564
|
+
}
|
|
27565
|
+
function uploadingArtifact(value) {
|
|
27566
|
+
const fields = artifactFields(value);
|
|
27567
|
+
return new MobiusUploadingArtifact(
|
|
27568
|
+
fields.sessionId,
|
|
27569
|
+
fields.artifactId,
|
|
27570
|
+
fields.name,
|
|
27571
|
+
fields.mediaType,
|
|
27572
|
+
fields.byteLength,
|
|
27573
|
+
fields.sha256,
|
|
27574
|
+
fields.createdAt,
|
|
27575
|
+
validateTimestamp(stringField(value, "expiresAt", 128), "expiresAt")
|
|
27576
|
+
);
|
|
27577
|
+
}
|
|
27578
|
+
function decodeMobiusArtifactUpload(value) {
|
|
27579
|
+
const artifact = record2(value, "artifact upload authorization");
|
|
27580
|
+
return new MobiusArtifactUpload(uploadingArtifact(artifact), stringField(artifact, "uploadToken", 256));
|
|
27581
|
+
}
|
|
27582
|
+
function decodeMobiusArtifact(value) {
|
|
27583
|
+
const artifact = record2(value, "artifact");
|
|
27584
|
+
const state = stringField(artifact, "state", 32);
|
|
27585
|
+
if (state === "uploading") {
|
|
27586
|
+
return uploadingArtifact(artifact);
|
|
27587
|
+
}
|
|
27588
|
+
const fields = artifactFields(artifact);
|
|
27589
|
+
if (state === "available") {
|
|
27590
|
+
return new MobiusAvailableArtifact(
|
|
27591
|
+
fields.sessionId,
|
|
27592
|
+
fields.artifactId,
|
|
27593
|
+
fields.name,
|
|
27594
|
+
fields.mediaType,
|
|
27595
|
+
fields.byteLength,
|
|
27596
|
+
fields.sha256,
|
|
27597
|
+
fields.createdAt,
|
|
27598
|
+
validateTimestamp(stringField(artifact, "availableAt", 128), "availableAt")
|
|
27599
|
+
);
|
|
27600
|
+
}
|
|
27601
|
+
if (state === "expired") {
|
|
27602
|
+
return new MobiusExpiredArtifact(
|
|
27603
|
+
fields.sessionId,
|
|
27604
|
+
fields.artifactId,
|
|
27605
|
+
fields.name,
|
|
27606
|
+
fields.mediaType,
|
|
27607
|
+
fields.byteLength,
|
|
27608
|
+
fields.sha256,
|
|
27609
|
+
fields.createdAt,
|
|
27610
|
+
validateTimestamp(stringField(artifact, "expiredAt", 128), "expiredAt")
|
|
27611
|
+
);
|
|
27612
|
+
}
|
|
27613
|
+
throw invalidResponse("The service returned an invalid artifact state");
|
|
27614
|
+
}
|
|
27615
|
+
function decodeMobiusAvailableArtifact(value) {
|
|
27616
|
+
const artifact = decodeMobiusArtifact(value);
|
|
27617
|
+
if (!(artifact instanceof MobiusAvailableArtifact)) {
|
|
27618
|
+
throw invalidResponse("The service did not make the artifact available");
|
|
27619
|
+
}
|
|
27620
|
+
return artifact;
|
|
27621
|
+
}
|
|
27622
|
+
var MobiusRuntimePairingLifecycle = Object.freeze({
|
|
27623
|
+
Expired: "expired",
|
|
27624
|
+
Paired: "paired",
|
|
27625
|
+
Pending: "pending",
|
|
27626
|
+
Revoked: "revoked"
|
|
27627
|
+
});
|
|
27628
|
+
|
|
27629
|
+
// src/artifacts/runtime-artifact-uploader.ts
|
|
27630
|
+
import { fetch as fetch3 } from "undici";
|
|
27631
|
+
var UPLOAD_TIMEOUT_MILLISECONDS = 2e4;
|
|
27632
|
+
var RuntimeArtifactUploadError = class extends Error {
|
|
27633
|
+
code;
|
|
27634
|
+
constructor(code, message, options = {}) {
|
|
27635
|
+
super(message, options);
|
|
27636
|
+
this.code = code;
|
|
27637
|
+
this.name = "RuntimeArtifactUploadError";
|
|
27638
|
+
}
|
|
27639
|
+
};
|
|
27640
|
+
var UploadedRuntimeArtifact = class {
|
|
27641
|
+
artifactId;
|
|
27642
|
+
byteLength;
|
|
27643
|
+
mimeType;
|
|
27644
|
+
name;
|
|
27645
|
+
sha256;
|
|
27646
|
+
constructor(artifactId, name, mimeType, byteLength, sha256) {
|
|
27647
|
+
this.artifactId = artifactId;
|
|
27648
|
+
this.byteLength = byteLength;
|
|
27649
|
+
this.mimeType = mimeType;
|
|
27650
|
+
this.name = name;
|
|
27651
|
+
this.sha256 = sha256;
|
|
27652
|
+
}
|
|
27653
|
+
};
|
|
27654
|
+
function daemonToken(config2) {
|
|
27655
|
+
const token = config2.relayUrl.searchParams.get("token");
|
|
27656
|
+
if (token === null || token.length < 32) {
|
|
27657
|
+
throw new RuntimeArtifactUploadError("artifact_endpoint_invalid", "The Relay daemon token is missing");
|
|
27658
|
+
}
|
|
27659
|
+
return token;
|
|
27660
|
+
}
|
|
27661
|
+
function channelOrigin(config2) {
|
|
27662
|
+
const url2 = new URL(config2.relayUrl);
|
|
27663
|
+
url2.protocol = url2.protocol === "wss:" ? "https:" : "http:";
|
|
27664
|
+
let channelPath = "";
|
|
27665
|
+
if (url2.pathname.endsWith("/daemon")) {
|
|
27666
|
+
channelPath = url2.pathname.slice(0, -"/daemon".length);
|
|
27667
|
+
} else {
|
|
27668
|
+
const runtimePath = `${MOBIUS_API_PREFIX}/v1/runtimes/connect`;
|
|
27669
|
+
if (!url2.pathname.endsWith("/v1/runtimes/connect") && !url2.pathname.endsWith(runtimePath)) {
|
|
27670
|
+
throw new RuntimeArtifactUploadError("artifact_endpoint_invalid", "The Relay artifact endpoint is invalid");
|
|
27671
|
+
}
|
|
27672
|
+
channelPath = `${url2.pathname.replace(/\/v1\/runtimes\/connect$/, "")}/channels/${encodeURIComponent(config2.channelId)}`;
|
|
27673
|
+
}
|
|
27674
|
+
url2.pathname = channelPath;
|
|
27675
|
+
url2.search = "";
|
|
27676
|
+
url2.hash = "";
|
|
27677
|
+
return url2;
|
|
27678
|
+
}
|
|
27679
|
+
function uploadError(code, message, cause) {
|
|
27680
|
+
return new RuntimeArtifactUploadError(code, message, cause === void 0 ? {} : { cause });
|
|
27681
|
+
}
|
|
27682
|
+
function translateSdkError(cause) {
|
|
27683
|
+
if (cause instanceof MobiusValidationError) {
|
|
27684
|
+
throw uploadError("artifact_upload_failed", cause.message, cause);
|
|
27685
|
+
}
|
|
27686
|
+
if (cause instanceof MobiusProtocolError) {
|
|
27687
|
+
throw uploadError("artifact_upload_failed", "The Relay returned an invalid upload response", cause);
|
|
27688
|
+
}
|
|
27689
|
+
throw cause;
|
|
27690
|
+
}
|
|
27691
|
+
async function readJson(response) {
|
|
27692
|
+
try {
|
|
27693
|
+
return await response.json();
|
|
27694
|
+
} catch (cause) {
|
|
27695
|
+
throw uploadError("artifact_upload_failed", "The Relay returned an invalid upload response", cause);
|
|
27696
|
+
}
|
|
27697
|
+
}
|
|
27698
|
+
async function readAuthorization(response) {
|
|
27699
|
+
try {
|
|
27700
|
+
return decodeMobiusArtifactUpload(await readJson(response));
|
|
27701
|
+
} catch (cause) {
|
|
27702
|
+
translateSdkError(cause);
|
|
27703
|
+
}
|
|
27704
|
+
}
|
|
27705
|
+
function sessionArtifactUrl(origin, sessionId, resourcePath, token) {
|
|
27706
|
+
const url2 = new URL(`${origin.pathname}/sessions/${encodeURIComponent(sessionId)}/${resourcePath}`, origin);
|
|
27707
|
+
url2.searchParams.set("token", token);
|
|
27708
|
+
return url2;
|
|
27709
|
+
}
|
|
27710
|
+
async function postLease(url2, request, signal) {
|
|
27711
|
+
return await fetch3(url2, {
|
|
27712
|
+
dispatcher: environmentProxyDispatcher,
|
|
27713
|
+
headers: { "content-type": "application/json" },
|
|
27714
|
+
method: "POST",
|
|
27715
|
+
body: JSON.stringify(request),
|
|
27716
|
+
signal
|
|
27717
|
+
});
|
|
27718
|
+
}
|
|
27719
|
+
async function putContent(url2, authorization, bytes, signal) {
|
|
27720
|
+
return await fetch3(url2, {
|
|
27721
|
+
dispatcher: environmentProxyDispatcher,
|
|
27722
|
+
headers: {
|
|
27723
|
+
"content-type": authorization.mediaType,
|
|
27724
|
+
"x-mobius-upload-token": authorization.uploadToken
|
|
27725
|
+
},
|
|
27726
|
+
method: "PUT",
|
|
27727
|
+
body: bytes,
|
|
27728
|
+
signal
|
|
27729
|
+
});
|
|
27730
|
+
}
|
|
27731
|
+
async function uploadRuntimeArtifact(config2, sessionId, image, signal) {
|
|
27732
|
+
signal.throwIfAborted();
|
|
27733
|
+
let request;
|
|
27734
|
+
try {
|
|
27735
|
+
request = new MobiusArtifactUploadRequest(
|
|
27736
|
+
image.name,
|
|
27737
|
+
image.mimeType,
|
|
27738
|
+
image.bytes.byteLength,
|
|
27739
|
+
createHash2("sha256").update(image.bytes).digest("hex")
|
|
27740
|
+
);
|
|
27741
|
+
} catch (cause) {
|
|
27742
|
+
translateSdkError(cause);
|
|
27743
|
+
}
|
|
27744
|
+
const timeoutSignal = AbortSignal.timeout(UPLOAD_TIMEOUT_MILLISECONDS);
|
|
27745
|
+
const requestSignal = AbortSignal.any([signal, timeoutSignal]);
|
|
27746
|
+
const origin = channelOrigin(config2);
|
|
27747
|
+
const token = daemonToken(config2);
|
|
27748
|
+
let created;
|
|
27749
|
+
try {
|
|
27750
|
+
created = await postLease(
|
|
27751
|
+
sessionArtifactUrl(origin, sessionId, "artifacts/uploads", token),
|
|
27752
|
+
request,
|
|
27753
|
+
requestSignal
|
|
27754
|
+
);
|
|
27755
|
+
} catch (cause) {
|
|
27756
|
+
signal.throwIfAborted();
|
|
27757
|
+
throw uploadError(
|
|
27758
|
+
timeoutSignal.aborted ? "artifact_upload_timeout" : "artifact_upload_failed",
|
|
27759
|
+
timeoutSignal.aborted ? "The artifact upload authorization timed out" : "The artifact upload could not start",
|
|
27760
|
+
cause
|
|
27761
|
+
);
|
|
27762
|
+
}
|
|
27763
|
+
if (!created.ok) {
|
|
27764
|
+
await created.body?.cancel();
|
|
27765
|
+
throw uploadError("artifact_upload_rejected", "The Relay rejected the artifact upload");
|
|
27766
|
+
}
|
|
27767
|
+
const authorization = await readAuthorization(created);
|
|
27768
|
+
let uploaded;
|
|
27769
|
+
try {
|
|
27770
|
+
uploaded = await putContent(
|
|
27771
|
+
sessionArtifactUrl(
|
|
27772
|
+
origin,
|
|
27773
|
+
sessionId,
|
|
27774
|
+
`artifacts/${encodeURIComponent(authorization.artifactId)}/content`,
|
|
27775
|
+
token
|
|
27776
|
+
),
|
|
27777
|
+
authorization,
|
|
27778
|
+
image.bytes,
|
|
27779
|
+
requestSignal
|
|
27780
|
+
);
|
|
27781
|
+
} catch (cause) {
|
|
27782
|
+
signal.throwIfAborted();
|
|
27783
|
+
throw uploadError(
|
|
27784
|
+
timeoutSignal.aborted ? "artifact_upload_timeout" : "artifact_upload_failed",
|
|
27785
|
+
timeoutSignal.aborted ? "The artifact upload timed out" : "The artifact content could not be uploaded",
|
|
27786
|
+
cause
|
|
27787
|
+
);
|
|
27788
|
+
}
|
|
27789
|
+
if (!uploaded.ok) {
|
|
27790
|
+
await uploaded.body?.cancel();
|
|
27791
|
+
throw uploadError("artifact_upload_rejected", "The Relay rejected the artifact content");
|
|
27792
|
+
}
|
|
27793
|
+
try {
|
|
27794
|
+
const available = decodeMobiusAvailableArtifact(await readJson(uploaded));
|
|
27795
|
+
return new UploadedRuntimeArtifact(
|
|
27796
|
+
available.artifactId,
|
|
27797
|
+
available.name,
|
|
27798
|
+
available.mediaType,
|
|
27799
|
+
available.byteLength,
|
|
27800
|
+
available.sha256
|
|
27801
|
+
);
|
|
27802
|
+
} catch (cause) {
|
|
27803
|
+
translateSdkError(cause);
|
|
27804
|
+
}
|
|
27805
|
+
}
|
|
27806
|
+
|
|
26999
27807
|
// src/authorization/local-authorization-error.ts
|
|
27000
27808
|
var LocalAuthorizationError = class extends Error {
|
|
27001
27809
|
code = "local_authorization_failed";
|
|
@@ -27006,9 +27814,9 @@ var LocalAuthorizationError = class extends Error {
|
|
|
27006
27814
|
};
|
|
27007
27815
|
|
|
27008
27816
|
// src/authorization/workspace-directory.ts
|
|
27009
|
-
import { readdir, realpath as
|
|
27817
|
+
import { readdir, realpath as realpath7, stat as stat6 } from "node:fs/promises";
|
|
27010
27818
|
import { homedir as homedir2 } from "node:os";
|
|
27011
|
-
import { basename, dirname as dirname5, isAbsolute as
|
|
27819
|
+
import { basename as basename2, dirname as dirname5, isAbsolute as isAbsolute9, join as join15, normalize as normalize3, relative as relative5 } from "node:path";
|
|
27012
27820
|
var WorkspaceDirectoryListing = class {
|
|
27013
27821
|
directoryId;
|
|
27014
27822
|
directoryLabel;
|
|
@@ -27034,7 +27842,7 @@ function decodePath(value, prefix) {
|
|
|
27034
27842
|
throw new LocalAuthorizationError("The directory identifier is invalid");
|
|
27035
27843
|
}
|
|
27036
27844
|
const decoded = Buffer.from(encoded, "base64url").toString("utf8");
|
|
27037
|
-
if (Buffer.from(decoded, "utf8").toString("base64url") !== encoded || decoded.includes("\0") ||
|
|
27845
|
+
if (Buffer.from(decoded, "utf8").toString("base64url") !== encoded || decoded.includes("\0") || normalize3(decoded) !== decoded) {
|
|
27038
27846
|
throw new LocalAuthorizationError("The directory identifier is invalid");
|
|
27039
27847
|
}
|
|
27040
27848
|
return decoded;
|
|
@@ -27060,7 +27868,7 @@ var WorkspaceDirectoryService = class {
|
|
|
27060
27868
|
}
|
|
27061
27869
|
if (id.startsWith("path-")) {
|
|
27062
27870
|
const path2 = decodePath(id, "path-");
|
|
27063
|
-
if (
|
|
27871
|
+
if (isAbsolute9(path2)) {
|
|
27064
27872
|
return path2;
|
|
27065
27873
|
}
|
|
27066
27874
|
}
|
|
@@ -27068,15 +27876,15 @@ var WorkspaceDirectoryService = class {
|
|
|
27068
27876
|
};
|
|
27069
27877
|
resolvePath = async (requested, signal) => {
|
|
27070
27878
|
signal.throwIfAborted();
|
|
27071
|
-
if (!
|
|
27879
|
+
if (!isAbsolute9(requested) || requested.includes("\0") || normalize3(requested) !== requested) {
|
|
27072
27880
|
throw new LocalAuthorizationError("The local directory path is invalid");
|
|
27073
27881
|
}
|
|
27074
27882
|
try {
|
|
27075
|
-
const target = await
|
|
27883
|
+
const target = await realpath7(requested);
|
|
27076
27884
|
signal.throwIfAborted();
|
|
27077
|
-
const metadata = await
|
|
27885
|
+
const metadata = await stat6(target);
|
|
27078
27886
|
signal.throwIfAborted();
|
|
27079
|
-
if (!
|
|
27887
|
+
if (!isAbsolute9(target) || normalize3(target) !== target || !metadata.isDirectory()) {
|
|
27080
27888
|
throw new LocalAuthorizationError("The selected location is not a directory");
|
|
27081
27889
|
}
|
|
27082
27890
|
return target;
|
|
@@ -27091,8 +27899,8 @@ var WorkspaceDirectoryService = class {
|
|
|
27091
27899
|
}
|
|
27092
27900
|
};
|
|
27093
27901
|
label = (path2) => {
|
|
27094
|
-
const suffix =
|
|
27095
|
-
return suffix === "" ? "~" : !
|
|
27902
|
+
const suffix = relative5(homedir2(), path2);
|
|
27903
|
+
return suffix === "" ? "~" : !isAbsolute9(suffix) && suffix !== ".." && !suffix.startsWith(`..${process.platform === "win32" ? "\\" : "/"}`) ? `~/${suffix.replaceAll("\\", "/")}` : path2;
|
|
27096
27904
|
};
|
|
27097
27905
|
identify = async (bindingId, requestedPath, signal) => {
|
|
27098
27906
|
this.authorizeMachine(bindingId);
|
|
@@ -27100,7 +27908,7 @@ var WorkspaceDirectoryService = class {
|
|
|
27100
27908
|
return {
|
|
27101
27909
|
path: path2,
|
|
27102
27910
|
directoryId: encodePath(path2),
|
|
27103
|
-
name:
|
|
27911
|
+
name: basename2(path2) || path2,
|
|
27104
27912
|
label: this.label(path2)
|
|
27105
27913
|
};
|
|
27106
27914
|
};
|
|
@@ -27122,7 +27930,7 @@ var WorkspaceDirectoryService = class {
|
|
|
27122
27930
|
continue;
|
|
27123
27931
|
}
|
|
27124
27932
|
try {
|
|
27125
|
-
const path2 = await this.resolvePath(
|
|
27933
|
+
const path2 = await this.resolvePath(join15(target, child.name), signal);
|
|
27126
27934
|
entries.push({ directoryId: encodePath(path2), name: child.name });
|
|
27127
27935
|
} catch (cause) {
|
|
27128
27936
|
signal.throwIfAborted();
|
|
@@ -27157,8 +27965,8 @@ var WorkspaceDirectoryService = class {
|
|
|
27157
27965
|
};
|
|
27158
27966
|
|
|
27159
27967
|
// src/bots/local-bot-grant-store.ts
|
|
27160
|
-
import { createHash as
|
|
27161
|
-
import { stat as
|
|
27968
|
+
import { createHash as createHash3, randomUUID } from "node:crypto";
|
|
27969
|
+
import { stat as stat7 } from "node:fs/promises";
|
|
27162
27970
|
import { DatabaseSync as DatabaseSync3 } from "node:sqlite";
|
|
27163
27971
|
var LOCAL_BOT_GRANT_LIFETIME_MILLISECONDS = 90 * 24 * 60 * 60 * 1e3;
|
|
27164
27972
|
var LocalBotAuthorizationError = class extends Error {
|
|
@@ -27202,7 +28010,7 @@ var LocalBotGrant = class {
|
|
|
27202
28010
|
}
|
|
27203
28011
|
};
|
|
27204
28012
|
function digest(value) {
|
|
27205
|
-
return
|
|
28013
|
+
return createHash3("sha256").update(value, "utf8").digest("hex");
|
|
27206
28014
|
}
|
|
27207
28015
|
function agentDigest(agent) {
|
|
27208
28016
|
return digest(
|
|
@@ -27216,7 +28024,7 @@ function agentDigest(agent) {
|
|
|
27216
28024
|
);
|
|
27217
28025
|
}
|
|
27218
28026
|
async function workspaceDigest(path2) {
|
|
27219
|
-
const metadata = await
|
|
28027
|
+
const metadata = await stat7(path2);
|
|
27220
28028
|
if (!metadata.isDirectory()) {
|
|
27221
28029
|
throw new LocalBotAuthorizationError("binding_incompatible", "The Bot workspace is not a directory");
|
|
27222
28030
|
}
|
|
@@ -27633,12 +28441,12 @@ var BotExecutionContextRegistry = class {
|
|
|
27633
28441
|
// src/bots/bot-outbound-ipc.ts
|
|
27634
28442
|
import { chmod as chmod2, mkdir as mkdir3, unlink } from "node:fs/promises";
|
|
27635
28443
|
import { createServer } from "node:net";
|
|
27636
|
-
import { dirname as dirname6, isAbsolute as
|
|
27637
|
-
import { fetch as
|
|
28444
|
+
import { dirname as dirname6, isAbsolute as isAbsolute10 } from "node:path";
|
|
28445
|
+
import { fetch as fetch4 } from "undici";
|
|
27638
28446
|
var BOT_IPC_REQUEST_LIMIT = 32 * 1024;
|
|
27639
28447
|
var BOT_IPC_TIMEOUT_MILLISECONDS = 2e4;
|
|
27640
28448
|
var BOT_RELAY_TIMEOUT_MILLISECONDS = 2e4;
|
|
27641
|
-
var
|
|
28449
|
+
var IDENTIFIER_PATTERN6 = /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/;
|
|
27642
28450
|
var WINDOWS_NAMED_PIPE_PREFIX = "\\\\.\\pipe\\";
|
|
27643
28451
|
var BotOutboundIpcRequest = class {
|
|
27644
28452
|
contextHandle;
|
|
@@ -27652,7 +28460,7 @@ var BotOutboundIpcRequest = class {
|
|
|
27652
28460
|
this.text = text;
|
|
27653
28461
|
}
|
|
27654
28462
|
};
|
|
27655
|
-
function
|
|
28463
|
+
function isRecord10(value) {
|
|
27656
28464
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
27657
28465
|
}
|
|
27658
28466
|
function decodeRequest(encoded) {
|
|
@@ -27662,7 +28470,7 @@ function decodeRequest(encoded) {
|
|
|
27662
28470
|
} catch (cause) {
|
|
27663
28471
|
throw new LocalBotAuthorizationError("invalid_request", "The local Bot request is invalid", { cause });
|
|
27664
28472
|
}
|
|
27665
|
-
if (!
|
|
28473
|
+
if (!isRecord10(value)) {
|
|
27666
28474
|
throw new LocalBotAuthorizationError("invalid_request", "The local Bot request is invalid");
|
|
27667
28475
|
}
|
|
27668
28476
|
const keys = Object.keys(value);
|
|
@@ -27673,7 +28481,7 @@ function decodeRequest(encoded) {
|
|
|
27673
28481
|
const idempotencyKey = value["idempotencyKey"];
|
|
27674
28482
|
const target = value["target"];
|
|
27675
28483
|
const text = value["text"];
|
|
27676
|
-
if (typeof contextHandle !== "string" || !/^ctx_[a-zA-Z0-9_-]{43}$/.test(contextHandle) || typeof idempotencyKey !== "string" || !
|
|
28484
|
+
if (typeof contextHandle !== "string" || !/^ctx_[a-zA-Z0-9_-]{43}$/.test(contextHandle) || typeof idempotencyKey !== "string" || !IDENTIFIER_PATTERN6.test(idempotencyKey) || typeof target !== "string" || !IDENTIFIER_PATTERN6.test(target) || typeof text !== "string" || text.trim().length === 0 || text.length > 1e4) {
|
|
27677
28485
|
throw new LocalBotAuthorizationError("invalid_request", "The local Bot request is invalid");
|
|
27678
28486
|
}
|
|
27679
28487
|
return new BotOutboundIpcRequest(contextHandle, idempotencyKey, target, text);
|
|
@@ -27695,7 +28503,7 @@ function relayEndpoint(relayUrl, context, target) {
|
|
|
27695
28503
|
endpoint.pathname = `${MOBIUS_API_PREFIX}/v1/bot-executions/${execution}/delivery-targets/${encodeURIComponent(deliveryTargetId)}/messages`;
|
|
27696
28504
|
return endpoint;
|
|
27697
28505
|
}
|
|
27698
|
-
function
|
|
28506
|
+
function daemonToken2(relayUrl) {
|
|
27699
28507
|
const token = relayUrl.searchParams.get("token") ?? "";
|
|
27700
28508
|
if (!/^[a-zA-Z0-9_-]{32,256}$/.test(token)) {
|
|
27701
28509
|
throw new LocalBotAuthorizationError("bot_service_unavailable", "The Runtime credential is unavailable");
|
|
@@ -27712,10 +28520,10 @@ async function decodeRelayResponse(response) {
|
|
|
27712
28520
|
cause
|
|
27713
28521
|
});
|
|
27714
28522
|
}
|
|
27715
|
-
if (response.status === 202 &&
|
|
28523
|
+
if (response.status === 202 && isRecord10(value) && typeof value["outboundMessageId"] === "string") {
|
|
27716
28524
|
return value["outboundMessageId"];
|
|
27717
28525
|
}
|
|
27718
|
-
if (
|
|
28526
|
+
if (isRecord10(value) && isRecord10(value["error"])) {
|
|
27719
28527
|
const error61 = value["error"];
|
|
27720
28528
|
if (typeof error61["code"] === "string" && typeof error61["message"] === "string") {
|
|
27721
28529
|
throw new LocalBotAuthorizationError(error61["code"], error61["message"]);
|
|
@@ -27731,7 +28539,7 @@ var BotOutboundIpcServer = class {
|
|
|
27731
28539
|
#usesFilesystemSocket;
|
|
27732
28540
|
constructor(socketPath, relayUrl, registry2) {
|
|
27733
28541
|
const usesFilesystemSocket = !socketPath.startsWith(WINDOWS_NAMED_PIPE_PREFIX);
|
|
27734
|
-
if (usesFilesystemSocket && !
|
|
28542
|
+
if (usesFilesystemSocket && !isAbsolute10(socketPath)) {
|
|
27735
28543
|
throw new Error("The Bot IPC path must be absolute");
|
|
27736
28544
|
}
|
|
27737
28545
|
this.#registry = registry2;
|
|
@@ -27748,7 +28556,7 @@ var BotOutboundIpcServer = class {
|
|
|
27748
28556
|
if (this.#usesFilesystemSocket) {
|
|
27749
28557
|
await mkdir3(dirname6(this.#socketPath), { mode: 448, recursive: true });
|
|
27750
28558
|
await unlink(this.#socketPath).catch((error61) => {
|
|
27751
|
-
if (!
|
|
28559
|
+
if (!isRecord10(error61) || error61["code"] !== "ENOENT") {
|
|
27752
28560
|
throw error61;
|
|
27753
28561
|
}
|
|
27754
28562
|
});
|
|
@@ -27783,7 +28591,7 @@ var BotOutboundIpcServer = class {
|
|
|
27783
28591
|
}
|
|
27784
28592
|
if (this.#usesFilesystemSocket) {
|
|
27785
28593
|
await unlink(this.#socketPath).catch((error61) => {
|
|
27786
|
-
if (!
|
|
28594
|
+
if (!isRecord10(error61) || error61["code"] !== "ENOENT") {
|
|
27787
28595
|
throw error61;
|
|
27788
28596
|
}
|
|
27789
28597
|
});
|
|
@@ -27847,10 +28655,10 @@ var BotOutboundIpcServer = class {
|
|
|
27847
28655
|
const requestSignal = AbortSignal.any([signal, timeout]);
|
|
27848
28656
|
let response;
|
|
27849
28657
|
try {
|
|
27850
|
-
response = await
|
|
28658
|
+
response = await fetch4(relayEndpoint(this.#relayUrl, context, request.target), {
|
|
27851
28659
|
body: JSON.stringify({ idempotencyKey: request.idempotencyKey, text: request.text }),
|
|
27852
28660
|
headers: {
|
|
27853
|
-
authorization: `Bearer ${
|
|
28661
|
+
authorization: `Bearer ${daemonToken2(this.#relayUrl)}`,
|
|
27854
28662
|
"content-type": "application/json",
|
|
27855
28663
|
"x-mobius-bot-execution-capability": context.command.executionCapabilitySecret
|
|
27856
28664
|
},
|
|
@@ -27871,7 +28679,7 @@ var BotOutboundIpcServer = class {
|
|
|
27871
28679
|
|
|
27872
28680
|
// src/native-sessions/service.ts
|
|
27873
28681
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
27874
|
-
import { basename as
|
|
28682
|
+
import { basename as basename3 } from "node:path";
|
|
27875
28683
|
|
|
27876
28684
|
// src/native-sessions/codex-history.ts
|
|
27877
28685
|
import { spawn as spawn4 } from "node:child_process";
|
|
@@ -27904,7 +28712,6 @@ function decodeHistory(thread, value) {
|
|
|
27904
28712
|
const page = turnsSchema.parse(value);
|
|
27905
28713
|
const messages = [];
|
|
27906
28714
|
let characters = 0;
|
|
27907
|
-
let imageCharacters = 0;
|
|
27908
28715
|
let truncated = page.nextCursor != null;
|
|
27909
28716
|
for (const turn of page.data.toReversed()) {
|
|
27910
28717
|
for (const item of turn.items) {
|
|
@@ -27912,22 +28719,19 @@ function decodeHistory(thread, value) {
|
|
|
27912
28719
|
let message;
|
|
27913
28720
|
if (type === "userMessage") {
|
|
27914
28721
|
const { content } = userMessageSchema.parse(item);
|
|
27915
|
-
const
|
|
27916
|
-
|
|
27917
|
-
|
|
27918
|
-
|
|
27919
|
-
|
|
27920
|
-
|
|
27921
|
-
|
|
27922
|
-
|
|
27923
|
-
|
|
27924
|
-
|
|
27925
|
-
}).join("")
|
|
27926
|
-
);
|
|
28722
|
+
const text2 = content.map((block) => {
|
|
28723
|
+
const { type: type2 } = itemTypeSchema.parse(block);
|
|
28724
|
+
if (type2 === "text") {
|
|
28725
|
+
return textSchema.parse(block).text;
|
|
28726
|
+
}
|
|
28727
|
+
if (type2 === "image") {
|
|
28728
|
+
return `[@image](${imageSchema.parse(block).url})`;
|
|
28729
|
+
}
|
|
28730
|
+
return "[Attachment]";
|
|
28731
|
+
}).join("");
|
|
27927
28732
|
message = {
|
|
27928
28733
|
role: "user",
|
|
27929
|
-
text:
|
|
27930
|
-
...parsed.images.length > 0 ? { images: parsed.images } : {}
|
|
28734
|
+
text: text2
|
|
27931
28735
|
};
|
|
27932
28736
|
} else if (type === "agentMessage") {
|
|
27933
28737
|
const agent = agentMessageSchema.parse(item);
|
|
@@ -27945,12 +28749,10 @@ function decodeHistory(thread, value) {
|
|
|
27945
28749
|
truncated ||= text.length < message.text.length;
|
|
27946
28750
|
messages.push({ ...message, text });
|
|
27947
28751
|
characters += text.length;
|
|
27948
|
-
|
|
27949
|
-
while (messages.length > SESSION_HISTORY_PREVIEW_MESSAGE_LIMIT || characters > SESSION_HISTORY_CHARACTER_LIMIT || imageCharacters > SESSION_HISTORY_IMAGE_CHARACTER_LIMIT) {
|
|
28752
|
+
while (messages.length > SESSION_HISTORY_PREVIEW_MESSAGE_LIMIT || characters > SESSION_HISTORY_CHARACTER_LIMIT) {
|
|
27950
28753
|
const removed = messages.shift();
|
|
27951
28754
|
if (removed !== void 0) {
|
|
27952
28755
|
characters -= removed.text.length;
|
|
27953
|
-
imageCharacters -= (removed.images ?? []).reduce((size, image) => size + image.data.length, 0);
|
|
27954
28756
|
}
|
|
27955
28757
|
truncated = true;
|
|
27956
28758
|
}
|
|
@@ -28108,7 +28910,11 @@ async function readCodexHistory(agent, cwd, nativeSessionId, signal) {
|
|
|
28108
28910
|
params: { clientInfo: { name: "mobius_history", version: "1.0.0" } }
|
|
28109
28911
|
});
|
|
28110
28912
|
}
|
|
28111
|
-
|
|
28913
|
+
const snapshot = await response.promise;
|
|
28914
|
+
return {
|
|
28915
|
+
...snapshot,
|
|
28916
|
+
history: await embedLocalHistoryImages(snapshot.history, [cwd, snapshot.cwd], signal)
|
|
28917
|
+
};
|
|
28112
28918
|
} finally {
|
|
28113
28919
|
clearTimeout(timeout);
|
|
28114
28920
|
signal.removeEventListener("abort", abort);
|
|
@@ -28362,7 +29168,7 @@ var NativeSessionService = class {
|
|
|
28362
29168
|
}
|
|
28363
29169
|
resolvedPaths.add(path2);
|
|
28364
29170
|
additionalDirectories.push(path2);
|
|
28365
|
-
additionalEntries.push({ directoryId: directoryId2, name:
|
|
29171
|
+
additionalEntries.push({ directoryId: directoryId2, name: basename3(path2) });
|
|
28366
29172
|
}
|
|
28367
29173
|
const listing = await this.#directories.list(this.#config.bindingId, command.directoryId, signal);
|
|
28368
29174
|
const opened = await this.#sessions.forkSessionAtTurn(
|
|
@@ -28501,13 +29307,13 @@ var NativeSessionService = class {
|
|
|
28501
29307
|
};
|
|
28502
29308
|
|
|
28503
29309
|
// src/prompt-artifact-resolver.ts
|
|
28504
|
-
import { createHash as
|
|
28505
|
-
import { fetch as
|
|
29310
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
29311
|
+
import { fetch as fetch5 } from "undici";
|
|
28506
29312
|
var ARTIFACT_SCHEME = "mobius-artifact:";
|
|
28507
29313
|
var ARTIFACT_DOWNLOAD_TIMEOUT_MILLISECONDS = 2e4;
|
|
28508
29314
|
var MAX_AGENT_IMAGE_BASE64_LENGTH = 4e6;
|
|
28509
29315
|
var MAX_AGENT_RESOURCE_BYTE_LENGTH = 1e6;
|
|
28510
|
-
var
|
|
29316
|
+
var IDENTIFIER_PATTERN7 = /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/;
|
|
28511
29317
|
var PromptArtifactError = class extends Error {
|
|
28512
29318
|
code;
|
|
28513
29319
|
constructor(code, message, options = {}) {
|
|
@@ -28550,7 +29356,7 @@ function parseReference(resource) {
|
|
|
28550
29356
|
const encodedByteLength2 = url2.searchParams.get("byteLength") ?? "";
|
|
28551
29357
|
const sha256 = url2.searchParams.get("sha256") ?? "";
|
|
28552
29358
|
const byteLength = Number(encodedByteLength2);
|
|
28553
|
-
if (url2.protocol !== ARTIFACT_SCHEME || url2.hash.length > 0 || resource.type !== "link" || resource.text.length > 0 || !
|
|
29359
|
+
if (url2.protocol !== ARTIFACT_SCHEME || url2.hash.length > 0 || resource.type !== "link" || resource.text.length > 0 || !IDENTIFIER_PATTERN7.test(artifactId) || keys.length !== 2 || keys[0] !== "byteLength" || keys[1] !== "sha256" || !/^[1-9][0-9]*$/.test(encodedByteLength2) || !Number.isSafeInteger(byteLength) || !/^[a-f0-9]{64}$/.test(sha256)) {
|
|
28554
29360
|
throw new PromptArtifactError("artifact_reference_invalid", "The prompt artifact reference is invalid");
|
|
28555
29361
|
}
|
|
28556
29362
|
return new PromptArtifactReference(artifactId, byteLength, sha256, resource);
|
|
@@ -28616,7 +29422,7 @@ async function download(config2, command, reference, signal) {
|
|
|
28616
29422
|
const requestSignal = AbortSignal.any([signal, timeoutSignal]);
|
|
28617
29423
|
let response;
|
|
28618
29424
|
try {
|
|
28619
|
-
response = await
|
|
29425
|
+
response = await fetch5(downloadUrl(config2, command, reference), {
|
|
28620
29426
|
dispatcher: environmentProxyDispatcher,
|
|
28621
29427
|
headers: {
|
|
28622
29428
|
accept: reference.resource.mimeType,
|
|
@@ -28640,7 +29446,7 @@ async function download(config2, command, reference, signal) {
|
|
|
28640
29446
|
);
|
|
28641
29447
|
}
|
|
28642
29448
|
const bytes = await responseBytes(response, reference.byteLength, requestSignal);
|
|
28643
|
-
if (
|
|
29449
|
+
if (createHash4("sha256").update(bytes).digest("hex") !== reference.sha256) {
|
|
28644
29450
|
throw new PromptArtifactError(
|
|
28645
29451
|
"artifact_integrity_failed",
|
|
28646
29452
|
"The prompt artifact failed integrity validation"
|
|
@@ -29673,13 +30479,26 @@ function botIpcSocketPath() {
|
|
|
29673
30479
|
if (process.platform === "win32") {
|
|
29674
30480
|
return `\\\\.\\pipe\\mobius-bot-${randomUUID4()}`;
|
|
29675
30481
|
}
|
|
29676
|
-
return
|
|
30482
|
+
return join16("/tmp", `mobius-bot-${randomUUID4()}.sock`);
|
|
29677
30483
|
}
|
|
29678
30484
|
var DaemonAcpObserver = class {
|
|
30485
|
+
#config;
|
|
29679
30486
|
#record;
|
|
29680
|
-
constructor(
|
|
29681
|
-
this.#
|
|
30487
|
+
constructor(config2, record3) {
|
|
30488
|
+
this.#config = config2;
|
|
30489
|
+
this.#record = record3;
|
|
29682
30490
|
}
|
|
30491
|
+
importLocalImage = async (sessionId, image, signal) => {
|
|
30492
|
+
try {
|
|
30493
|
+
return (await uploadRuntimeArtifact(this.#config, sessionId, image, signal)).artifactId;
|
|
30494
|
+
} catch (cause) {
|
|
30495
|
+
signal.throwIfAborted();
|
|
30496
|
+
if (cause instanceof Error && cause.name === "AbortError") {
|
|
30497
|
+
throw cause;
|
|
30498
|
+
}
|
|
30499
|
+
return "";
|
|
30500
|
+
}
|
|
30501
|
+
};
|
|
29683
30502
|
onCommands = (event) => {
|
|
29684
30503
|
this.#record(event.sessionId, encodeSessionCommandsUpdatedEvent(event));
|
|
29685
30504
|
return Promise.resolve();
|
|
@@ -29889,7 +30708,7 @@ async function reconcileActiveTurn(config2, turn, signal) {
|
|
|
29889
30708
|
const requestSignal = AbortSignal.any([signal, timeoutSignal]);
|
|
29890
30709
|
let response;
|
|
29891
30710
|
try {
|
|
29892
|
-
response = await
|
|
30711
|
+
response = await fetch6(activeTurnReconciliationEndpoint(config2, turn), {
|
|
29893
30712
|
body: JSON.stringify({ outcome: { kind: "running" } }),
|
|
29894
30713
|
dispatcher: environmentProxyDispatcher,
|
|
29895
30714
|
headers: { ...runtimeAuthorization(config2.relayUrl), "content-type": "application/json" },
|
|
@@ -30205,7 +31024,7 @@ async function resolveSessionDirectories(directories, bindingId, directoryId2, a
|
|
|
30205
31024
|
additionalDirectories.push(directory);
|
|
30206
31025
|
additionalDirectoryEntries.push({
|
|
30207
31026
|
directoryId: additionalDirectoryId,
|
|
30208
|
-
name:
|
|
31027
|
+
name: basename4(directory)
|
|
30209
31028
|
});
|
|
30210
31029
|
}
|
|
30211
31030
|
return new ResolvedSessionDirectories(cwd, additionalDirectories, additionalDirectoryEntries);
|
|
@@ -30716,8 +31535,7 @@ async function runRelayConnection(config2, directories, audit, sessions, install
|
|
|
30716
31535
|
rejectConnection(failure);
|
|
30717
31536
|
};
|
|
30718
31537
|
const processingDeliveryIds = /* @__PURE__ */ new Set();
|
|
30719
|
-
const processDeliveredPrompt = async (delivery) => {
|
|
30720
|
-
const command = decodeSessionPromptCommand(delivery.payload);
|
|
31538
|
+
const processDeliveredPrompt = async (delivery, command, trackActiveAttempt, execute) => {
|
|
30721
31539
|
if (command.sessionId !== delivery.sessionId) {
|
|
30722
31540
|
throw new Error("Runtime delivery Session identity does not match its payload");
|
|
30723
31541
|
}
|
|
@@ -30745,22 +31563,11 @@ async function runRelayConnection(config2, directories, audit, sessions, install
|
|
|
30745
31563
|
}
|
|
30746
31564
|
const turn = new ActiveDaemonTurn(command, receipt.attemptId);
|
|
30747
31565
|
activeTurns.set(command.commandId, turn);
|
|
30748
|
-
if (
|
|
31566
|
+
if (trackActiveAttempt) {
|
|
30749
31567
|
activeAttemptIds.set(command.sessionId, receipt.attemptId);
|
|
30750
31568
|
}
|
|
30751
31569
|
try {
|
|
30752
|
-
await
|
|
30753
|
-
outbox,
|
|
30754
|
-
publisher,
|
|
30755
|
-
command,
|
|
30756
|
-
config2,
|
|
30757
|
-
directories,
|
|
30758
|
-
audit,
|
|
30759
|
-
sessions,
|
|
30760
|
-
receipt.attemptId,
|
|
30761
|
-
timer,
|
|
30762
|
-
turn.signal
|
|
30763
|
-
);
|
|
31570
|
+
await execute(receipt.attemptId, turn.signal);
|
|
30764
31571
|
} finally {
|
|
30765
31572
|
activeTurns.delete(command.commandId);
|
|
30766
31573
|
if (activeAttemptIds.get(command.sessionId) === receipt.attemptId) {
|
|
@@ -30839,8 +31646,50 @@ async function runRelayConnection(config2, directories, audit, sessions, install
|
|
|
30839
31646
|
}
|
|
30840
31647
|
return;
|
|
30841
31648
|
}
|
|
31649
|
+
if (kind === BOT_SESSION_PROMPT_KIND) {
|
|
31650
|
+
const command = decodeBotSessionPromptCommand(delivery.payload);
|
|
31651
|
+
await processDeliveredPrompt(
|
|
31652
|
+
delivery,
|
|
31653
|
+
command,
|
|
31654
|
+
true,
|
|
31655
|
+
(attemptId, executionSignal) => executeBotPrompt(
|
|
31656
|
+
outbox,
|
|
31657
|
+
publisher,
|
|
31658
|
+
command,
|
|
31659
|
+
config2,
|
|
31660
|
+
directories,
|
|
31661
|
+
audit,
|
|
31662
|
+
sessions,
|
|
31663
|
+
grants,
|
|
31664
|
+
contexts,
|
|
31665
|
+
applicator,
|
|
31666
|
+
ipc,
|
|
31667
|
+
attemptId,
|
|
31668
|
+
timer,
|
|
31669
|
+
executionSignal
|
|
31670
|
+
)
|
|
31671
|
+
);
|
|
31672
|
+
return;
|
|
31673
|
+
}
|
|
30842
31674
|
if (kind === SESSION_PROMPT_KIND) {
|
|
30843
|
-
|
|
31675
|
+
const command = decodeSessionPromptCommand(delivery.payload);
|
|
31676
|
+
await processDeliveredPrompt(
|
|
31677
|
+
delivery,
|
|
31678
|
+
command,
|
|
31679
|
+
command.disposition !== SessionPromptDisposition.Steer,
|
|
31680
|
+
(attemptId, executionSignal) => executePrompt(
|
|
31681
|
+
outbox,
|
|
31682
|
+
publisher,
|
|
31683
|
+
command,
|
|
31684
|
+
config2,
|
|
31685
|
+
directories,
|
|
31686
|
+
audit,
|
|
31687
|
+
sessions,
|
|
31688
|
+
attemptId,
|
|
31689
|
+
timer,
|
|
31690
|
+
executionSignal
|
|
31691
|
+
)
|
|
31692
|
+
);
|
|
30844
31693
|
return;
|
|
30845
31694
|
}
|
|
30846
31695
|
throw new Error("Runtime delivery contains an unsupported protocol message");
|
|
@@ -30878,6 +31727,8 @@ async function runRelayConnection(config2, directories, audit, sessions, install
|
|
|
30878
31727
|
payloadSessionId = decodeSessionElicitationRespondCommand(delivery.payload).sessionId;
|
|
30879
31728
|
} else if (payloadKind === SESSION_PROMPT_KIND) {
|
|
30880
31729
|
payloadSessionId = decodeSessionPromptCommand(delivery.payload).sessionId;
|
|
31730
|
+
} else if (payloadKind === BOT_SESSION_PROMPT_KIND) {
|
|
31731
|
+
payloadSessionId = decodeBotSessionPromptCommand(delivery.payload).sessionId;
|
|
30881
31732
|
} else {
|
|
30882
31733
|
throw new Error("Runtime delivery contains an unsupported protocol message");
|
|
30883
31734
|
}
|
|
@@ -31475,7 +32326,7 @@ async function runDaemon(config2, audit, signal, timer = systemDaemonTimer) {
|
|
|
31475
32326
|
}
|
|
31476
32327
|
publisher.recordAttempt(sessionId, payload, attemptId);
|
|
31477
32328
|
};
|
|
31478
|
-
const sessions = new AcpSessionManager(new DaemonAcpObserver(recordSessionEvent), sessionStore);
|
|
32329
|
+
const sessions = new AcpSessionManager(new DaemonAcpObserver(config2, recordSessionEvent), sessionStore);
|
|
31479
32330
|
const directories = new WorkspaceDirectoryService(config2.bindingId, config2.defaultWorkspace);
|
|
31480
32331
|
const installationObserver = new DaemonInstallationObserver();
|
|
31481
32332
|
const diagnostics = new RelayConnectionDiagnostics(audit, config2.channelId, config2.relayUrl);
|
|
@@ -31574,13 +32425,13 @@ async function runDaemon(config2, audit, signal, timer = systemDaemonTimer) {
|
|
|
31574
32425
|
|
|
31575
32426
|
// src/pairing/pair-local-machine.ts
|
|
31576
32427
|
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
31577
|
-
import { mkdir as mkdir4, open as open4, realpath as
|
|
32428
|
+
import { mkdir as mkdir4, open as open4, realpath as realpath8, rename as rename3, stat as stat8, writeFile as writeFile2 } from "node:fs/promises";
|
|
31578
32429
|
import { hostname as hostname3 } from "node:os";
|
|
31579
|
-
import { basename as
|
|
31580
|
-
import { fetch as
|
|
32430
|
+
import { basename as basename5, join as join17, resolve as resolve4 } from "node:path";
|
|
32431
|
+
import { fetch as fetch7 } from "undici";
|
|
31581
32432
|
var PAIRING_TIMEOUT_MILLISECONDS = 2e4;
|
|
31582
32433
|
var PAIRING_CODE_PATTERN = /^[A-HJ-NP-Z2-9]{4}(?:-[A-HJ-NP-Z2-9]{4}){4}$/;
|
|
31583
|
-
var
|
|
32434
|
+
var IDENTIFIER_PATTERN8 = /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/;
|
|
31584
32435
|
var TOKEN_PATTERN2 = /^[a-zA-Z0-9_-]{32,256}$/;
|
|
31585
32436
|
var MAX_CONNECTION_FILE_LENGTH = 16 * 1024;
|
|
31586
32437
|
var CLAIM_RESPONSE_KEYS = ["channelId", "daemonToken", "runtimeId"];
|
|
@@ -31595,7 +32446,7 @@ var PairingClientError = class extends Error {
|
|
|
31595
32446
|
this.name = "PairingClientError";
|
|
31596
32447
|
}
|
|
31597
32448
|
};
|
|
31598
|
-
function
|
|
32449
|
+
function isRecord11(value) {
|
|
31599
32450
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
31600
32451
|
}
|
|
31601
32452
|
function hasExactKeys(value, expectedKeys) {
|
|
@@ -31634,7 +32485,7 @@ function parsePairingCode(value) {
|
|
|
31634
32485
|
return code;
|
|
31635
32486
|
}
|
|
31636
32487
|
function validatePairingId(value) {
|
|
31637
|
-
if (!
|
|
32488
|
+
if (!IDENTIFIER_PATTERN8.test(value)) {
|
|
31638
32489
|
throw new PairingClientError("invalid_pairing_id", "The Runtime pairing ID is invalid");
|
|
31639
32490
|
}
|
|
31640
32491
|
return value;
|
|
@@ -31643,8 +32494,8 @@ async function resolveDefaultWorkspace2(path2) {
|
|
|
31643
32494
|
const requestedWorkspace = resolve4(path2);
|
|
31644
32495
|
try {
|
|
31645
32496
|
await mkdir4(requestedWorkspace, { recursive: true, mode: 448 });
|
|
31646
|
-
const defaultWorkspace = await
|
|
31647
|
-
const metadata = await
|
|
32497
|
+
const defaultWorkspace = await realpath8(requestedWorkspace);
|
|
32498
|
+
const metadata = await stat8(defaultWorkspace);
|
|
31648
32499
|
if (!metadata.isDirectory()) {
|
|
31649
32500
|
throw new PairingClientError("invalid_workspace", "The default workspace is not a directory");
|
|
31650
32501
|
}
|
|
@@ -31673,9 +32524,9 @@ async function readJsonResponse(response) {
|
|
|
31673
32524
|
}
|
|
31674
32525
|
}
|
|
31675
32526
|
function readRelayError(value) {
|
|
31676
|
-
if (
|
|
32527
|
+
if (isRecord11(value)) {
|
|
31677
32528
|
const error61 = value["error"];
|
|
31678
|
-
if (
|
|
32529
|
+
if (isRecord11(error61)) {
|
|
31679
32530
|
const code = error61["code"];
|
|
31680
32531
|
const message = error61["message"];
|
|
31681
32532
|
if (typeof code === "string" && typeof message === "string") {
|
|
@@ -31686,13 +32537,13 @@ function readRelayError(value) {
|
|
|
31686
32537
|
return new PairingClientError("pairing_failed", "The relay could not pair this machine");
|
|
31687
32538
|
}
|
|
31688
32539
|
function decodePairingResponse(value, credentialField, expectedKeys) {
|
|
31689
|
-
if (!
|
|
32540
|
+
if (!isRecord11(value) || !hasExactKeys(value, expectedKeys)) {
|
|
31690
32541
|
throw new PairingClientError("invalid_relay_response", "The relay returned an invalid pairing response");
|
|
31691
32542
|
}
|
|
31692
32543
|
const channelId = value["channelId"];
|
|
31693
32544
|
const runtimeCredential2 = value[credentialField];
|
|
31694
32545
|
const runtimeId = value["runtimeId"];
|
|
31695
|
-
if (typeof channelId !== "string" || !
|
|
32546
|
+
if (typeof channelId !== "string" || !IDENTIFIER_PATTERN8.test(channelId) || typeof runtimeCredential2 !== "string" || !TOKEN_PATTERN2.test(runtimeCredential2) || typeof runtimeId !== "string" || !IDENTIFIER_PATTERN8.test(runtimeId)) {
|
|
31696
32547
|
throw new PairingClientError("invalid_relay_response", "The relay returned an invalid pairing response");
|
|
31697
32548
|
}
|
|
31698
32549
|
return { channelId, runtimeCredential: runtimeCredential2, runtimeId };
|
|
@@ -31708,13 +32559,13 @@ async function claimPairing(options, defaultWorkspace, localAgents, installableA
|
|
|
31708
32559
|
const endpoint = options.pairingId.length > 0 ? mobiusApiUrl(options.relayOrigin, `/v1/runtime-pairings/${encodeURIComponent(options.pairingId)}/redeem`) : mobiusApiUrl(options.relayOrigin, "/pairings/claim");
|
|
31709
32560
|
let response;
|
|
31710
32561
|
try {
|
|
31711
|
-
response = await
|
|
32562
|
+
response = await fetch7(endpoint, {
|
|
31712
32563
|
body: JSON.stringify({
|
|
31713
32564
|
agents,
|
|
31714
32565
|
installableAgents,
|
|
31715
32566
|
machineName: hostname3(),
|
|
31716
32567
|
pairingCode: options.code,
|
|
31717
|
-
workspaceName:
|
|
32568
|
+
workspaceName: basename5(defaultWorkspace) || "Local workspace"
|
|
31718
32569
|
}),
|
|
31719
32570
|
dispatcher: environmentProxyDispatcher,
|
|
31720
32571
|
headers: { "content-type": "application/json" },
|
|
@@ -31731,10 +32582,10 @@ async function claimPairing(options, defaultWorkspace, localAgents, installableA
|
|
|
31731
32582
|
return options.pairingId.length > 0 ? decodePairingResponse(value, "runtimeCredential", REDEEM_RESPONSE_KEYS) : decodePairingResponse(value, "daemonToken", CLAIM_RESPONSE_KEYS);
|
|
31732
32583
|
}
|
|
31733
32584
|
async function persistConnection(channelId, relayOrigin, runtimeCredential2, defaultWorkspace, environment) {
|
|
31734
|
-
const connectionsDirectory =
|
|
32585
|
+
const connectionsDirectory = join17(readStateDirectory(environment), "connections");
|
|
31735
32586
|
await mkdir4(connectionsDirectory, { mode: 448, recursive: true });
|
|
31736
|
-
const connectionPath =
|
|
31737
|
-
const temporaryPath =
|
|
32587
|
+
const connectionPath = join17(connectionsDirectory, `${channelId}.json`);
|
|
32588
|
+
const temporaryPath = join17(connectionsDirectory, `.${channelId}.${randomUUID5()}.tmp`);
|
|
31738
32589
|
await writeFile2(
|
|
31739
32590
|
temporaryPath,
|
|
31740
32591
|
`${JSON.stringify(
|
|
@@ -31754,14 +32605,14 @@ async function persistConnection(channelId, relayOrigin, runtimeCredential2, def
|
|
|
31754
32605
|
return connectionPath;
|
|
31755
32606
|
}
|
|
31756
32607
|
function decodeSavedConnection(value, expectedChannelId) {
|
|
31757
|
-
if (!
|
|
32608
|
+
if (!isRecord11(value) || !hasExactKeys(value, SAVED_CONNECTION_KEYS) && !hasExactKeys(value, LEGACY_SAVED_CONNECTION_KEYS)) {
|
|
31758
32609
|
throw new PairingClientError("invalid_connection", "The saved connection is invalid");
|
|
31759
32610
|
}
|
|
31760
32611
|
const defaultWorkspace = value["defaultWorkspace"];
|
|
31761
32612
|
const channelId = value["channelId"];
|
|
31762
32613
|
const runtimeCredential2 = value["runtimeCredential"] ?? value["daemonToken"];
|
|
31763
32614
|
const relayOrigin = value["relayOrigin"];
|
|
31764
|
-
if (typeof defaultWorkspace !== "string" || typeof channelId !== "string" || channelId !== expectedChannelId || !
|
|
32615
|
+
if (typeof defaultWorkspace !== "string" || typeof channelId !== "string" || channelId !== expectedChannelId || !IDENTIFIER_PATTERN8.test(channelId) || typeof runtimeCredential2 !== "string" || !TOKEN_PATTERN2.test(runtimeCredential2) || typeof relayOrigin !== "string") {
|
|
31765
32616
|
throw new PairingClientError("invalid_connection", "The saved connection is invalid");
|
|
31766
32617
|
}
|
|
31767
32618
|
return {
|
|
@@ -31772,7 +32623,7 @@ function decodeSavedConnection(value, expectedChannelId) {
|
|
|
31772
32623
|
};
|
|
31773
32624
|
}
|
|
31774
32625
|
async function readSavedConnection(channelId, environment) {
|
|
31775
|
-
const connectionPath =
|
|
32626
|
+
const connectionPath = join17(readStateDirectory(environment), "connections", `${channelId}.json`);
|
|
31776
32627
|
let encoded = "";
|
|
31777
32628
|
const handle = await open4(connectionPath, "r");
|
|
31778
32629
|
try {
|
|
@@ -31808,7 +32659,7 @@ function buildPairedDaemon(connection, connectionPath, inventory, environment) {
|
|
|
31808
32659
|
const relayUrl = mobiusApiUrl(connection.relayOrigin, "/v1/runtimes/connect");
|
|
31809
32660
|
relayUrl.protocol = relayUrl.protocol === "https:" ? "wss:" : "ws:";
|
|
31810
32661
|
relayUrl.searchParams.set("token", connection.runtimeCredential);
|
|
31811
|
-
const auditDatabasePath =
|
|
32662
|
+
const auditDatabasePath = join17(readStateDirectory(environment), "audit", `${connection.channelId}.sqlite`);
|
|
31812
32663
|
return {
|
|
31813
32664
|
channelUrl: new URL(`/channels/${encodeURIComponent(connection.channelId)}`, connection.relayOrigin).toString(),
|
|
31814
32665
|
config: createDaemonConfig(
|
|
@@ -31867,7 +32718,7 @@ async function pairMobiusRuntime(options, signal, environment = process.env) {
|
|
|
31867
32718
|
}
|
|
31868
32719
|
async function resumeMobiusRuntime(channelId, signal, environment = process.env) {
|
|
31869
32720
|
const normalizedChannelId = validatePairingId(channelId);
|
|
31870
|
-
const connectionPath =
|
|
32721
|
+
const connectionPath = join17(readStateDirectory(environment), "connections", `${normalizedChannelId}.json`);
|
|
31871
32722
|
const connection = await readSavedConnection(normalizedChannelId, environment);
|
|
31872
32723
|
const inventory = await discoverLocalAgentInventory({
|
|
31873
32724
|
defaultWorkspace: connection.defaultWorkspace,
|
|
@@ -31880,7 +32731,7 @@ async function resumeMobiusRuntime(channelId, signal, environment = process.env)
|
|
|
31880
32731
|
// src/runtime.ts
|
|
31881
32732
|
var APP_CREDENTIAL_PATTERN = /^mapp_[a-zA-Z0-9_-]{22}_[a-zA-Z0-9_-]{43}$/;
|
|
31882
32733
|
var CONVERSATION_CREDENTIAL_PATTERN = /^mconv_[a-zA-Z0-9_-]{22}_[a-zA-Z0-9_-]{43}$/;
|
|
31883
|
-
var
|
|
32734
|
+
var IDENTIFIER_PATTERN9 = /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/;
|
|
31884
32735
|
var RUNTIME_CREDENTIAL_PATTERN = /^[a-zA-Z0-9_-]{32,256}$/;
|
|
31885
32736
|
var MobiusRuntimeConfigurationError = class extends Error {
|
|
31886
32737
|
code = "runtime_configuration_invalid";
|
|
@@ -31938,11 +32789,11 @@ function relayUrlFromConnection(connection) {
|
|
|
31938
32789
|
}
|
|
31939
32790
|
function loadMobiusRuntimeConnection(environment = process.env) {
|
|
31940
32791
|
const channelId = requiredEnvironmentValue(environment, "MOBIUS_CHANNEL_ID");
|
|
31941
|
-
if (!
|
|
32792
|
+
if (!IDENTIFIER_PATTERN9.test(channelId)) {
|
|
31942
32793
|
throw new MobiusRuntimeConfigurationError("MOBIUS_CHANNEL_ID is invalid");
|
|
31943
32794
|
}
|
|
31944
32795
|
return Object.freeze({
|
|
31945
|
-
auditDatabasePath: environment["MOBIUS_AUDIT_DATABASE"]?.trim() ||
|
|
32796
|
+
auditDatabasePath: environment["MOBIUS_AUDIT_DATABASE"]?.trim() || join18(readStateDirectory(environment), "audit", `${channelId}.sqlite`),
|
|
31946
32797
|
channelId,
|
|
31947
32798
|
defaultWorkspace: loadDefaultWorkspace(environment),
|
|
31948
32799
|
relayUrl: requiredEnvironmentValue(environment, "MOBIUS_RELAY_URL"),
|
|
@@ -31953,8 +32804,8 @@ async function resolveWorkspace(path2) {
|
|
|
31953
32804
|
const requested = resolve5(path2);
|
|
31954
32805
|
try {
|
|
31955
32806
|
await mkdir5(requested, { recursive: true, mode: 448 });
|
|
31956
|
-
const resolved = await
|
|
31957
|
-
const metadata = await
|
|
32807
|
+
const resolved = await realpath9(requested);
|
|
32808
|
+
const metadata = await stat9(resolved);
|
|
31958
32809
|
if (!metadata.isDirectory()) {
|
|
31959
32810
|
throw new MobiusRuntimeConfigurationError("The Runtime workspace is not a directory");
|
|
31960
32811
|
}
|