@moxt-ai/mobius 0.0.28 → 0.0.30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent-catalog/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/bots/bot-approve-command.d.ts +2 -0
- package/dist/bots/bot-approve-command.d.ts.map +1 -0
- package/dist/bots/bot-approve-command.js +78 -0
- package/dist/bots/bot-approve-command.js.map +1 -0
- package/dist/bots/local-bot-grant-store.d.ts +7 -0
- package/dist/bots/local-bot-grant-store.d.ts.map +1 -1
- package/dist/bots/local-bot-grant-store.js +89 -0
- package/dist/bots/local-bot-grant-store.js.map +1 -1
- package/dist/cli.js +1300 -941
- package/dist/cli.js.map +4 -4
- package/dist/index.js +476 -236
- package/dist/index.js.map +4 -4
- package/dist/run-daemon.d.ts.map +1 -1
- package/dist/run-daemon.js +18 -14
- package/dist/run-daemon.js.map +1 -1
- package/dist/runtime.js +488 -246
- package/dist/runtime.js.map +4 -4
- package/package.json +1 -1
package/dist/runtime.js
CHANGED
|
@@ -6,7 +6,7 @@ var __export = (target, all) => {
|
|
|
6
6
|
|
|
7
7
|
// src/runtime.ts
|
|
8
8
|
import { mkdir as mkdir5, realpath as realpath9, stat as stat9 } from "node:fs/promises";
|
|
9
|
-
import { dirname as dirname8, join as
|
|
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) {
|
|
@@ -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 = {};
|
|
@@ -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(
|
|
@@ -23062,7 +23201,7 @@ var decodeSessionEventRejection = (encoded) => decode5(encoded, eventRejectionSc
|
|
|
23062
23201
|
// src/config.ts
|
|
23063
23202
|
function loadDefaultWorkspace(environment = process.env) {
|
|
23064
23203
|
const { MOBIUS_DEFAULT_WORKSPACE: configuredWorkspace } = environment;
|
|
23065
|
-
return configuredWorkspace ??
|
|
23204
|
+
return configuredWorkspace ?? join14(readStateDirectory(environment), "workspace");
|
|
23066
23205
|
}
|
|
23067
23206
|
function createDaemonConfig(connection, agents = [], installableAgents = []) {
|
|
23068
23207
|
return {
|
|
@@ -23079,7 +23218,7 @@ function createDaemonConfig(connection, agents = [], installableAgents = []) {
|
|
|
23079
23218
|
|
|
23080
23219
|
// src/run-daemon.ts
|
|
23081
23220
|
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
23082
|
-
import { basename as basename4, join as
|
|
23221
|
+
import { basename as basename4, join as join16 } from "node:path";
|
|
23083
23222
|
import { styleText } from "node:util";
|
|
23084
23223
|
import { fetch as fetch6, WebSocket as WebSocket2 } from "undici";
|
|
23085
23224
|
|
|
@@ -23094,7 +23233,7 @@ import {
|
|
|
23094
23233
|
|
|
23095
23234
|
// src/authorization/local-raster.ts
|
|
23096
23235
|
import { readFile, realpath as realpath6, stat as stat5 } from "node:fs/promises";
|
|
23097
|
-
import { basename, isAbsolute as
|
|
23236
|
+
import { basename, isAbsolute as isAbsolute8, normalize as normalize2, relative as relative4, sep as sep4 } from "node:path";
|
|
23098
23237
|
import { fileURLToPath } from "node:url";
|
|
23099
23238
|
var MAX_LOCAL_RASTER_BYTES = 3e6;
|
|
23100
23239
|
var PNG_SIGNATURE = Uint8Array.of(137, 80, 78, 71);
|
|
@@ -23137,17 +23276,17 @@ function sniffRasterMime(bytes) {
|
|
|
23137
23276
|
}
|
|
23138
23277
|
function isInsideRoot(root, target) {
|
|
23139
23278
|
const relation = relative4(root, target);
|
|
23140
|
-
return relation !== ".." && !relation.startsWith(`..${sep4}`) && !
|
|
23279
|
+
return relation !== ".." && !relation.startsWith(`..${sep4}`) && !isAbsolute8(relation);
|
|
23141
23280
|
}
|
|
23142
23281
|
async function resolveCanonicalPath(requested, signal) {
|
|
23143
23282
|
signal.throwIfAborted();
|
|
23144
|
-
if (!
|
|
23283
|
+
if (!isAbsolute8(requested) || requested.includes("\0") || normalize2(requested) !== requested) {
|
|
23145
23284
|
return null;
|
|
23146
23285
|
}
|
|
23147
23286
|
try {
|
|
23148
23287
|
const target = await realpath6(requested);
|
|
23149
23288
|
signal.throwIfAborted();
|
|
23150
|
-
if (!
|
|
23289
|
+
if (!isAbsolute8(target) || normalize2(target) !== target) {
|
|
23151
23290
|
return null;
|
|
23152
23291
|
}
|
|
23153
23292
|
return target;
|
|
@@ -27677,7 +27816,7 @@ var LocalAuthorizationError = class extends Error {
|
|
|
27677
27816
|
// src/authorization/workspace-directory.ts
|
|
27678
27817
|
import { readdir, realpath as realpath7, stat as stat6 } from "node:fs/promises";
|
|
27679
27818
|
import { homedir as homedir2 } from "node:os";
|
|
27680
|
-
import { basename as basename2, 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";
|
|
27681
27820
|
var WorkspaceDirectoryListing = class {
|
|
27682
27821
|
directoryId;
|
|
27683
27822
|
directoryLabel;
|
|
@@ -27729,7 +27868,7 @@ var WorkspaceDirectoryService = class {
|
|
|
27729
27868
|
}
|
|
27730
27869
|
if (id.startsWith("path-")) {
|
|
27731
27870
|
const path2 = decodePath(id, "path-");
|
|
27732
|
-
if (
|
|
27871
|
+
if (isAbsolute9(path2)) {
|
|
27733
27872
|
return path2;
|
|
27734
27873
|
}
|
|
27735
27874
|
}
|
|
@@ -27737,7 +27876,7 @@ var WorkspaceDirectoryService = class {
|
|
|
27737
27876
|
};
|
|
27738
27877
|
resolvePath = async (requested, signal) => {
|
|
27739
27878
|
signal.throwIfAborted();
|
|
27740
|
-
if (!
|
|
27879
|
+
if (!isAbsolute9(requested) || requested.includes("\0") || normalize3(requested) !== requested) {
|
|
27741
27880
|
throw new LocalAuthorizationError("The local directory path is invalid");
|
|
27742
27881
|
}
|
|
27743
27882
|
try {
|
|
@@ -27745,7 +27884,7 @@ var WorkspaceDirectoryService = class {
|
|
|
27745
27884
|
signal.throwIfAborted();
|
|
27746
27885
|
const metadata = await stat6(target);
|
|
27747
27886
|
signal.throwIfAborted();
|
|
27748
|
-
if (!
|
|
27887
|
+
if (!isAbsolute9(target) || normalize3(target) !== target || !metadata.isDirectory()) {
|
|
27749
27888
|
throw new LocalAuthorizationError("The selected location is not a directory");
|
|
27750
27889
|
}
|
|
27751
27890
|
return target;
|
|
@@ -27761,7 +27900,7 @@ var WorkspaceDirectoryService = class {
|
|
|
27761
27900
|
};
|
|
27762
27901
|
label = (path2) => {
|
|
27763
27902
|
const suffix = relative5(homedir2(), path2);
|
|
27764
|
-
return suffix === "" ? "~" : !
|
|
27903
|
+
return suffix === "" ? "~" : !isAbsolute9(suffix) && suffix !== ".." && !suffix.startsWith(`..${process.platform === "win32" ? "\\" : "/"}`) ? `~/${suffix.replaceAll("\\", "/")}` : path2;
|
|
27765
27904
|
};
|
|
27766
27905
|
identify = async (bindingId, requestedPath, signal) => {
|
|
27767
27906
|
this.authorizeMachine(bindingId);
|
|
@@ -27791,7 +27930,7 @@ var WorkspaceDirectoryService = class {
|
|
|
27791
27930
|
continue;
|
|
27792
27931
|
}
|
|
27793
27932
|
try {
|
|
27794
|
-
const path2 = await this.resolvePath(
|
|
27933
|
+
const path2 = await this.resolvePath(join15(target, child.name), signal);
|
|
27795
27934
|
entries.push({ directoryId: encodePath(path2), name: child.name });
|
|
27796
27935
|
} catch (cause) {
|
|
27797
27936
|
signal.throwIfAborted();
|
|
@@ -27830,6 +27969,18 @@ import { createHash as createHash3, randomUUID } from "node:crypto";
|
|
|
27830
27969
|
import { stat as stat7 } from "node:fs/promises";
|
|
27831
27970
|
import { DatabaseSync as DatabaseSync3 } from "node:sqlite";
|
|
27832
27971
|
var LOCAL_BOT_GRANT_LIFETIME_MILLISECONDS = 90 * 24 * 60 * 60 * 1e3;
|
|
27972
|
+
var identifier2 = external_exports.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/);
|
|
27973
|
+
var savedApprovalSchema = external_exports.object({
|
|
27974
|
+
local_grant_id: identifier2,
|
|
27975
|
+
bot_id: identifier2,
|
|
27976
|
+
binding_id: identifier2,
|
|
27977
|
+
binding_revision: external_exports.number().int().positive(),
|
|
27978
|
+
agent_ref: identifier2,
|
|
27979
|
+
workspace_ref: external_exports.string().min(1).max(2048),
|
|
27980
|
+
revocation_epoch: external_exports.number().int().nonnegative(),
|
|
27981
|
+
agent_identity_digest: external_exports.string().regex(/^[a-f0-9]{64}$/),
|
|
27982
|
+
workspace_identity_digest: external_exports.string().regex(/^[a-f0-9]{64}$/)
|
|
27983
|
+
}).readonly();
|
|
27833
27984
|
var LocalBotAuthorizationError = class extends Error {
|
|
27834
27985
|
code;
|
|
27835
27986
|
constructor(code, message, options = {}) {
|
|
@@ -27934,6 +28085,17 @@ function parseTargets(encoded) {
|
|
|
27934
28085
|
}
|
|
27935
28086
|
var LocalBotGrantStore = class {
|
|
27936
28087
|
#database;
|
|
28088
|
+
static containsBot = (path2, botId) => {
|
|
28089
|
+
const database = new DatabaseSync3(path2, { readOnly: true });
|
|
28090
|
+
try {
|
|
28091
|
+
if (database.prepare("SELECT name FROM sqlite_master WHERE type = 'table' AND name = 'local_bot_grants'").get() === void 0) {
|
|
28092
|
+
return false;
|
|
28093
|
+
}
|
|
28094
|
+
return database.prepare("SELECT local_grant_id FROM local_bot_grants WHERE bot_id = ? LIMIT 1").get(botId) !== void 0;
|
|
28095
|
+
} finally {
|
|
28096
|
+
database.close();
|
|
28097
|
+
}
|
|
28098
|
+
};
|
|
27937
28099
|
constructor(path2) {
|
|
27938
28100
|
this.#database = new DatabaseSync3(path2);
|
|
27939
28101
|
this.#database.exec(`
|
|
@@ -27967,6 +28129,78 @@ var LocalBotGrantStore = class {
|
|
|
27967
28129
|
) STRICT;
|
|
27968
28130
|
`);
|
|
27969
28131
|
}
|
|
28132
|
+
/** Only the local CLI may invoke this explicit approval transition. */
|
|
28133
|
+
reapprove = async (botId, catalog, directories, bindingAuthorityId, now, signal) => {
|
|
28134
|
+
signal.throwIfAborted();
|
|
28135
|
+
if (!identifier2.safeParse(botId).success) {
|
|
28136
|
+
throw new LocalBotAuthorizationError("invalid_request", "The Bot ID is invalid");
|
|
28137
|
+
}
|
|
28138
|
+
const row = this.#database.prepare("SELECT * FROM local_bot_grants WHERE bot_id = ? ORDER BY binding_revision DESC LIMIT 1").get(botId);
|
|
28139
|
+
if (row === void 0) {
|
|
28140
|
+
throw new LocalBotAuthorizationError("bot_not_found", "This machine has no saved approval for that Bot");
|
|
28141
|
+
}
|
|
28142
|
+
const parsed = savedApprovalSchema.safeParse(row);
|
|
28143
|
+
if (!parsed.success) {
|
|
28144
|
+
throw new LocalBotAuthorizationError("local_grant_invalid", "The saved Bot approval is invalid", {
|
|
28145
|
+
cause: parsed.error
|
|
28146
|
+
});
|
|
28147
|
+
}
|
|
28148
|
+
const saved = parsed.data;
|
|
28149
|
+
const agent = catalog.find(saved.agent_ref);
|
|
28150
|
+
if (!agent.capabilities.embeddedContextPrompt) {
|
|
28151
|
+
throw new LocalBotAuthorizationError("binding_incompatible", "The local Agent cannot apply Bot context");
|
|
28152
|
+
}
|
|
28153
|
+
const [adapterUnchanged, agentUnchanged] = await Promise.all([
|
|
28154
|
+
revalidateExecutable(agent.adapterIdentity),
|
|
28155
|
+
revalidateExecutable(agent.agentIdentity)
|
|
28156
|
+
]);
|
|
28157
|
+
signal.throwIfAborted();
|
|
28158
|
+
if (!adapterUnchanged || !agentUnchanged) {
|
|
28159
|
+
throw new LocalBotAuthorizationError(
|
|
28160
|
+
"binding_incompatible",
|
|
28161
|
+
"The local Agent executable changed before approval"
|
|
28162
|
+
);
|
|
28163
|
+
}
|
|
28164
|
+
const workspacePath = await directories.resolve(bindingAuthorityId, saved.workspace_ref, signal);
|
|
28165
|
+
const workspaceIdentityDigest = await workspaceDigest(workspacePath);
|
|
28166
|
+
signal.throwIfAborted();
|
|
28167
|
+
this.#database.exec("BEGIN IMMEDIATE");
|
|
28168
|
+
try {
|
|
28169
|
+
const result = this.#database.prepare(`UPDATE local_bot_grants
|
|
28170
|
+
SET agent_identity_digest = ?, workspace_identity_digest = ?, workspace_path = ?,
|
|
28171
|
+
revoked_at = NULL, expires_at = ?, revocation_epoch = revocation_epoch + 1
|
|
28172
|
+
WHERE local_grant_id = ? AND revocation_epoch = ?
|
|
28173
|
+
AND agent_identity_digest = ? AND workspace_identity_digest = ?
|
|
28174
|
+
AND binding_revision = (SELECT MAX(binding_revision) FROM local_bot_grants WHERE bot_id = ?)`).run(
|
|
28175
|
+
agentDigest(agent),
|
|
28176
|
+
workspaceIdentityDigest,
|
|
28177
|
+
workspacePath,
|
|
28178
|
+
now + LOCAL_BOT_GRANT_LIFETIME_MILLISECONDS,
|
|
28179
|
+
saved.local_grant_id,
|
|
28180
|
+
saved.revocation_epoch,
|
|
28181
|
+
saved.agent_identity_digest,
|
|
28182
|
+
saved.workspace_identity_digest,
|
|
28183
|
+
botId
|
|
28184
|
+
);
|
|
28185
|
+
if (result.changes !== 1) {
|
|
28186
|
+
throw new LocalBotAuthorizationError(
|
|
28187
|
+
"binding_not_approved",
|
|
28188
|
+
"The Bot binding changed during approval; run the command again"
|
|
28189
|
+
);
|
|
28190
|
+
}
|
|
28191
|
+
this.#database.prepare(`INSERT INTO audit_events (recorded_at, event, command_id, session_id, details_json)
|
|
28192
|
+
VALUES (?, 'bot_binding_locally_reapproved', ?, '', ?)`).run(
|
|
28193
|
+
new Date(now).toISOString(),
|
|
28194
|
+
saved.binding_id,
|
|
28195
|
+
JSON.stringify({ botId, bindingId: saved.binding_id, agentRef: saved.agent_ref })
|
|
28196
|
+
);
|
|
28197
|
+
this.#database.exec("COMMIT");
|
|
28198
|
+
} catch (cause) {
|
|
28199
|
+
this.#database.exec("ROLLBACK");
|
|
28200
|
+
throw cause;
|
|
28201
|
+
}
|
|
28202
|
+
return { bindingId: saved.binding_id, workspacePath, agentRef: saved.agent_ref };
|
|
28203
|
+
};
|
|
27970
28204
|
approve = async (request, catalog, directories, bindingAuthorityId, now, signal) => {
|
|
27971
28205
|
signal.throwIfAborted();
|
|
27972
28206
|
const existing = this.#database.prepare(
|
|
@@ -28302,7 +28536,7 @@ var BotExecutionContextRegistry = class {
|
|
|
28302
28536
|
// src/bots/bot-outbound-ipc.ts
|
|
28303
28537
|
import { chmod as chmod2, mkdir as mkdir3, unlink } from "node:fs/promises";
|
|
28304
28538
|
import { createServer } from "node:net";
|
|
28305
|
-
import { dirname as dirname6, isAbsolute as
|
|
28539
|
+
import { dirname as dirname6, isAbsolute as isAbsolute10 } from "node:path";
|
|
28306
28540
|
import { fetch as fetch4 } from "undici";
|
|
28307
28541
|
var BOT_IPC_REQUEST_LIMIT = 32 * 1024;
|
|
28308
28542
|
var BOT_IPC_TIMEOUT_MILLISECONDS = 2e4;
|
|
@@ -28400,7 +28634,7 @@ var BotOutboundIpcServer = class {
|
|
|
28400
28634
|
#usesFilesystemSocket;
|
|
28401
28635
|
constructor(socketPath, relayUrl, registry2) {
|
|
28402
28636
|
const usesFilesystemSocket = !socketPath.startsWith(WINDOWS_NAMED_PIPE_PREFIX);
|
|
28403
|
-
if (usesFilesystemSocket && !
|
|
28637
|
+
if (usesFilesystemSocket && !isAbsolute10(socketPath)) {
|
|
28404
28638
|
throw new Error("The Bot IPC path must be absolute");
|
|
28405
28639
|
}
|
|
28406
28640
|
this.#registry = registry2;
|
|
@@ -30340,7 +30574,7 @@ function botIpcSocketPath() {
|
|
|
30340
30574
|
if (process.platform === "win32") {
|
|
30341
30575
|
return `\\\\.\\pipe\\mobius-bot-${randomUUID4()}`;
|
|
30342
30576
|
}
|
|
30343
|
-
return
|
|
30577
|
+
return join16("/tmp", `mobius-bot-${randomUUID4()}.sock`);
|
|
30344
30578
|
}
|
|
30345
30579
|
var DaemonAcpObserver = class {
|
|
30346
30580
|
#config;
|
|
@@ -31010,7 +31244,7 @@ async function executeSessionConfigure(publisher, socket, command, config2, dire
|
|
|
31010
31244
|
reportOperationFailure(socket, command.requestId, command.sessionId, error61);
|
|
31011
31245
|
}
|
|
31012
31246
|
}
|
|
31013
|
-
async function executePrompt(outbox, publisher, command, config2, directories, audit, sessions, attemptId, timer, signal) {
|
|
31247
|
+
async function executePrompt(outbox, publisher, command, config2, directories, audit, sessions, attemptId, activateAttempt, timer, signal) {
|
|
31014
31248
|
const activities = new CoalescingDaemonActivityPublisher(timer, (activity) => {
|
|
31015
31249
|
publisher.recordAttempt(command.sessionId, encodeDaemonActivity(command, activity), attemptId);
|
|
31016
31250
|
});
|
|
@@ -31039,6 +31273,7 @@ async function executePrompt(outbox, publisher, command, config2, directories, a
|
|
|
31039
31273
|
}),
|
|
31040
31274
|
attemptId
|
|
31041
31275
|
);
|
|
31276
|
+
activateAttempt();
|
|
31042
31277
|
const attachments = await resolvePromptArtifacts(config2, command, signal);
|
|
31043
31278
|
let stopReason;
|
|
31044
31279
|
if (command.disposition === SessionPromptDisposition.Steer) {
|
|
@@ -31150,7 +31385,7 @@ function botExecutionAgent(agent, contextHandle, socketPath) {
|
|
|
31150
31385
|
agent.capabilities
|
|
31151
31386
|
);
|
|
31152
31387
|
}
|
|
31153
|
-
async function executeBotPrompt(outbox, publisher, command, config2, directories, audit, sessions, grants, contexts, applicator, ipc, attemptId, timer, signal) {
|
|
31388
|
+
async function executeBotPrompt(outbox, publisher, command, config2, directories, audit, sessions, grants, contexts, applicator, ipc, attemptId, activateAttempt, timer, signal) {
|
|
31154
31389
|
const activities = new CoalescingDaemonActivityPublisher(timer, (activity) => {
|
|
31155
31390
|
publisher.recordAttempt(command.sessionId, encodeDaemonActivity(command, activity), attemptId);
|
|
31156
31391
|
});
|
|
@@ -31231,6 +31466,7 @@ async function executeBotPrompt(outbox, publisher, command, config2, directories
|
|
|
31231
31466
|
}),
|
|
31232
31467
|
attemptId
|
|
31233
31468
|
);
|
|
31469
|
+
activateAttempt();
|
|
31234
31470
|
const result = await sessions.runPrompt({
|
|
31235
31471
|
additionalDirectories: resolved.additionalDirectories,
|
|
31236
31472
|
agent,
|
|
@@ -31424,11 +31660,13 @@ async function runRelayConnection(config2, directories, audit, sessions, install
|
|
|
31424
31660
|
}
|
|
31425
31661
|
const turn = new ActiveDaemonTurn(command, receipt.attemptId);
|
|
31426
31662
|
activeTurns.set(command.commandId, turn);
|
|
31427
|
-
|
|
31428
|
-
|
|
31429
|
-
|
|
31663
|
+
const activateAttempt = () => {
|
|
31664
|
+
if (trackActiveAttempt) {
|
|
31665
|
+
activeAttemptIds.set(command.sessionId, receipt.attemptId);
|
|
31666
|
+
}
|
|
31667
|
+
};
|
|
31430
31668
|
try {
|
|
31431
|
-
await execute(receipt.attemptId, turn.signal);
|
|
31669
|
+
await execute(receipt.attemptId, activateAttempt, turn.signal);
|
|
31432
31670
|
} finally {
|
|
31433
31671
|
activeTurns.delete(command.commandId);
|
|
31434
31672
|
if (activeAttemptIds.get(command.sessionId) === receipt.attemptId) {
|
|
@@ -31513,7 +31751,7 @@ async function runRelayConnection(config2, directories, audit, sessions, install
|
|
|
31513
31751
|
delivery,
|
|
31514
31752
|
command,
|
|
31515
31753
|
true,
|
|
31516
|
-
(attemptId, executionSignal) => executeBotPrompt(
|
|
31754
|
+
(attemptId, activateAttempt, executionSignal) => executeBotPrompt(
|
|
31517
31755
|
outbox,
|
|
31518
31756
|
publisher,
|
|
31519
31757
|
command,
|
|
@@ -31526,6 +31764,7 @@ async function runRelayConnection(config2, directories, audit, sessions, install
|
|
|
31526
31764
|
applicator,
|
|
31527
31765
|
ipc,
|
|
31528
31766
|
attemptId,
|
|
31767
|
+
activateAttempt,
|
|
31529
31768
|
timer,
|
|
31530
31769
|
executionSignal
|
|
31531
31770
|
)
|
|
@@ -31538,7 +31777,7 @@ async function runRelayConnection(config2, directories, audit, sessions, install
|
|
|
31538
31777
|
delivery,
|
|
31539
31778
|
command,
|
|
31540
31779
|
command.disposition !== SessionPromptDisposition.Steer,
|
|
31541
|
-
(attemptId, executionSignal) => executePrompt(
|
|
31780
|
+
(attemptId, activateAttempt, executionSignal) => executePrompt(
|
|
31542
31781
|
outbox,
|
|
31543
31782
|
publisher,
|
|
31544
31783
|
command,
|
|
@@ -31547,6 +31786,7 @@ async function runRelayConnection(config2, directories, audit, sessions, install
|
|
|
31547
31786
|
audit,
|
|
31548
31787
|
sessions,
|
|
31549
31788
|
attemptId,
|
|
31789
|
+
activateAttempt,
|
|
31550
31790
|
timer,
|
|
31551
31791
|
executionSignal
|
|
31552
31792
|
)
|
|
@@ -32048,7 +32288,6 @@ async function runRelayConnection(config2, directories, audit, sessions, install
|
|
|
32048
32288
|
}
|
|
32049
32289
|
const turn2 = new ActiveDaemonTurn(command2, receipt2.attemptId);
|
|
32050
32290
|
activeTurns.set(command2.commandId, turn2);
|
|
32051
|
-
activeAttemptIds.set(command2.sessionId, receipt2.attemptId);
|
|
32052
32291
|
void executeBotPrompt(
|
|
32053
32292
|
outbox,
|
|
32054
32293
|
publisher,
|
|
@@ -32062,6 +32301,7 @@ async function runRelayConnection(config2, directories, audit, sessions, install
|
|
|
32062
32301
|
applicator,
|
|
32063
32302
|
ipc,
|
|
32064
32303
|
receipt2.attemptId,
|
|
32304
|
+
() => activeAttemptIds.set(command2.sessionId, receipt2.attemptId),
|
|
32065
32305
|
timer,
|
|
32066
32306
|
turn2.signal
|
|
32067
32307
|
).catch((error61) => {
|
|
@@ -32088,9 +32328,6 @@ async function runRelayConnection(config2, directories, audit, sessions, install
|
|
|
32088
32328
|
}
|
|
32089
32329
|
const turn = new ActiveDaemonTurn(command, receipt.attemptId);
|
|
32090
32330
|
activeTurns.set(command.commandId, turn);
|
|
32091
|
-
if (command.disposition !== SessionPromptDisposition.Steer) {
|
|
32092
|
-
activeAttemptIds.set(command.sessionId, receipt.attemptId);
|
|
32093
|
-
}
|
|
32094
32331
|
void executePrompt(
|
|
32095
32332
|
outbox,
|
|
32096
32333
|
publisher,
|
|
@@ -32100,6 +32337,11 @@ async function runRelayConnection(config2, directories, audit, sessions, install
|
|
|
32100
32337
|
audit,
|
|
32101
32338
|
sessions,
|
|
32102
32339
|
receipt.attemptId,
|
|
32340
|
+
() => {
|
|
32341
|
+
if (command.disposition !== SessionPromptDisposition.Steer) {
|
|
32342
|
+
activeAttemptIds.set(command.sessionId, receipt.attemptId);
|
|
32343
|
+
}
|
|
32344
|
+
},
|
|
32103
32345
|
timer,
|
|
32104
32346
|
turn.signal
|
|
32105
32347
|
).catch((error61) => {
|
|
@@ -32288,7 +32530,7 @@ async function runDaemon(config2, audit, signal, timer = systemDaemonTimer) {
|
|
|
32288
32530
|
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
32289
32531
|
import { mkdir as mkdir4, open as open4, realpath as realpath8, rename as rename3, stat as stat8, writeFile as writeFile2 } from "node:fs/promises";
|
|
32290
32532
|
import { hostname as hostname3 } from "node:os";
|
|
32291
|
-
import { basename as basename5, join as
|
|
32533
|
+
import { basename as basename5, join as join17, resolve as resolve4 } from "node:path";
|
|
32292
32534
|
import { fetch as fetch7 } from "undici";
|
|
32293
32535
|
var PAIRING_TIMEOUT_MILLISECONDS = 2e4;
|
|
32294
32536
|
var PAIRING_CODE_PATTERN = /^[A-HJ-NP-Z2-9]{4}(?:-[A-HJ-NP-Z2-9]{4}){4}$/;
|
|
@@ -32443,10 +32685,10 @@ async function claimPairing(options, defaultWorkspace, localAgents, installableA
|
|
|
32443
32685
|
return options.pairingId.length > 0 ? decodePairingResponse(value, "runtimeCredential", REDEEM_RESPONSE_KEYS) : decodePairingResponse(value, "daemonToken", CLAIM_RESPONSE_KEYS);
|
|
32444
32686
|
}
|
|
32445
32687
|
async function persistConnection(channelId, relayOrigin, runtimeCredential2, defaultWorkspace, environment) {
|
|
32446
|
-
const connectionsDirectory =
|
|
32688
|
+
const connectionsDirectory = join17(readStateDirectory(environment), "connections");
|
|
32447
32689
|
await mkdir4(connectionsDirectory, { mode: 448, recursive: true });
|
|
32448
|
-
const connectionPath =
|
|
32449
|
-
const temporaryPath =
|
|
32690
|
+
const connectionPath = join17(connectionsDirectory, `${channelId}.json`);
|
|
32691
|
+
const temporaryPath = join17(connectionsDirectory, `.${channelId}.${randomUUID5()}.tmp`);
|
|
32450
32692
|
await writeFile2(
|
|
32451
32693
|
temporaryPath,
|
|
32452
32694
|
`${JSON.stringify(
|
|
@@ -32484,7 +32726,7 @@ function decodeSavedConnection(value, expectedChannelId) {
|
|
|
32484
32726
|
};
|
|
32485
32727
|
}
|
|
32486
32728
|
async function readSavedConnection(channelId, environment) {
|
|
32487
|
-
const connectionPath =
|
|
32729
|
+
const connectionPath = join17(readStateDirectory(environment), "connections", `${channelId}.json`);
|
|
32488
32730
|
let encoded = "";
|
|
32489
32731
|
const handle = await open4(connectionPath, "r");
|
|
32490
32732
|
try {
|
|
@@ -32520,7 +32762,7 @@ function buildPairedDaemon(connection, connectionPath, inventory, environment) {
|
|
|
32520
32762
|
const relayUrl = mobiusApiUrl(connection.relayOrigin, "/v1/runtimes/connect");
|
|
32521
32763
|
relayUrl.protocol = relayUrl.protocol === "https:" ? "wss:" : "ws:";
|
|
32522
32764
|
relayUrl.searchParams.set("token", connection.runtimeCredential);
|
|
32523
|
-
const auditDatabasePath =
|
|
32765
|
+
const auditDatabasePath = join17(readStateDirectory(environment), "audit", `${connection.channelId}.sqlite`);
|
|
32524
32766
|
return {
|
|
32525
32767
|
channelUrl: new URL(`/channels/${encodeURIComponent(connection.channelId)}`, connection.relayOrigin).toString(),
|
|
32526
32768
|
config: createDaemonConfig(
|
|
@@ -32579,7 +32821,7 @@ async function pairMobiusRuntime(options, signal, environment = process.env) {
|
|
|
32579
32821
|
}
|
|
32580
32822
|
async function resumeMobiusRuntime(channelId, signal, environment = process.env) {
|
|
32581
32823
|
const normalizedChannelId = validatePairingId(channelId);
|
|
32582
|
-
const connectionPath =
|
|
32824
|
+
const connectionPath = join17(readStateDirectory(environment), "connections", `${normalizedChannelId}.json`);
|
|
32583
32825
|
const connection = await readSavedConnection(normalizedChannelId, environment);
|
|
32584
32826
|
const inventory = await discoverLocalAgentInventory({
|
|
32585
32827
|
defaultWorkspace: connection.defaultWorkspace,
|
|
@@ -32654,7 +32896,7 @@ function loadMobiusRuntimeConnection(environment = process.env) {
|
|
|
32654
32896
|
throw new MobiusRuntimeConfigurationError("MOBIUS_CHANNEL_ID is invalid");
|
|
32655
32897
|
}
|
|
32656
32898
|
return Object.freeze({
|
|
32657
|
-
auditDatabasePath: environment["MOBIUS_AUDIT_DATABASE"]?.trim() ||
|
|
32899
|
+
auditDatabasePath: environment["MOBIUS_AUDIT_DATABASE"]?.trim() || join18(readStateDirectory(environment), "audit", `${channelId}.sqlite`),
|
|
32658
32900
|
channelId,
|
|
32659
32901
|
defaultWorkspace: loadDefaultWorkspace(environment),
|
|
32660
32902
|
relayUrl: requiredEnvironmentValue(environment, "MOBIUS_RELAY_URL"),
|