@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.
Files changed (77) hide show
  1. package/dist/acp/activity.d.ts +1 -0
  2. package/dist/acp/activity.d.ts.map +1 -1
  3. package/dist/acp/activity.js +14 -1
  4. package/dist/acp/activity.js.map +1 -1
  5. package/dist/acp/session-history.d.ts.map +1 -1
  6. package/dist/acp/session-history.js +10 -16
  7. package/dist/acp/session-history.js.map +1 -1
  8. package/dist/acp/session-manager.d.ts +7 -0
  9. package/dist/acp/session-manager.d.ts.map +1 -1
  10. package/dist/acp/session-manager.js +65 -11
  11. package/dist/acp/session-manager.js.map +1 -1
  12. package/dist/agent-catalog/acp-readiness-probe.d.ts.map +1 -1
  13. package/dist/agent-catalog/acp-readiness-probe.js +2 -2
  14. package/dist/agent-catalog/acp-readiness-probe.js.map +1 -1
  15. package/dist/agent-catalog/agent-specification.d.ts +3 -0
  16. package/dist/agent-catalog/agent-specification.d.ts.map +1 -1
  17. package/dist/agent-catalog/agent-specification.js +3 -0
  18. package/dist/agent-catalog/agent-specification.js.map +1 -1
  19. package/dist/agent-catalog/agents/copilot-cli-agent.d.ts +18 -0
  20. package/dist/agent-catalog/agents/copilot-cli-agent.d.ts.map +1 -0
  21. package/dist/agent-catalog/agents/copilot-cli-agent.js +29 -0
  22. package/dist/agent-catalog/agents/copilot-cli-agent.js.map +1 -0
  23. package/dist/agent-catalog/agents/gemini-cli-agent.d.ts +14 -0
  24. package/dist/agent-catalog/agents/gemini-cli-agent.d.ts.map +1 -0
  25. package/dist/agent-catalog/agents/gemini-cli-agent.js +30 -0
  26. package/dist/agent-catalog/agents/gemini-cli-agent.js.map +1 -0
  27. package/dist/agent-catalog/agents/hermes-agent.d.ts +18 -0
  28. package/dist/agent-catalog/agents/hermes-agent.d.ts.map +1 -0
  29. package/dist/agent-catalog/agents/hermes-agent.js +32 -0
  30. package/dist/agent-catalog/agents/hermes-agent.js.map +1 -0
  31. package/dist/agent-catalog/agents/resolve-user-local-executable.d.ts +4 -0
  32. package/dist/agent-catalog/agents/resolve-user-local-executable.d.ts.map +1 -0
  33. package/dist/agent-catalog/agents/resolve-user-local-executable.js +14 -0
  34. package/dist/agent-catalog/agents/resolve-user-local-executable.js.map +1 -0
  35. package/dist/agent-catalog/agents/supported-agent-specifications.d.ts.map +1 -1
  36. package/dist/agent-catalog/agents/supported-agent-specifications.js +6 -0
  37. package/dist/agent-catalog/agents/supported-agent-specifications.js.map +1 -1
  38. package/dist/agent-catalog/discover-agent.d.ts.map +1 -1
  39. package/dist/agent-catalog/discover-agent.js +2 -2
  40. package/dist/agent-catalog/discover-agent.js.map +1 -1
  41. package/dist/agent-catalog/discover-local-agents.d.ts +3 -0
  42. package/dist/agent-catalog/discover-local-agents.d.ts.map +1 -1
  43. package/dist/agent-catalog/discover-local-agents.js +3 -0
  44. package/dist/agent-catalog/discover-local-agents.js.map +1 -1
  45. package/dist/agent-catalog/executable-discovery.d.ts +1 -2
  46. package/dist/agent-catalog/executable-discovery.d.ts.map +1 -1
  47. package/dist/agent-catalog/executable-discovery.js +4 -6
  48. package/dist/agent-catalog/executable-discovery.js.map +1 -1
  49. package/dist/agent-catalog/version-output.d.ts +2 -0
  50. package/dist/agent-catalog/version-output.d.ts.map +1 -0
  51. package/dist/agent-catalog/version-output.js +4 -0
  52. package/dist/agent-catalog/version-output.js.map +1 -0
  53. package/dist/artifacts/runtime-artifact-uploader.d.ts +12 -0
  54. package/dist/artifacts/runtime-artifact-uploader.d.ts.map +1 -0
  55. package/dist/artifacts/runtime-artifact-uploader.js +157 -0
  56. package/dist/artifacts/runtime-artifact-uploader.js.map +1 -0
  57. package/dist/authorization/local-raster.d.ts +10 -0
  58. package/dist/authorization/local-raster.d.ts.map +1 -0
  59. package/dist/authorization/local-raster.js +134 -0
  60. package/dist/authorization/local-raster.js.map +1 -0
  61. package/dist/cli.js +1185 -333
  62. package/dist/cli.js.map +4 -4
  63. package/dist/index.js +1245 -396
  64. package/dist/index.js.map +4 -4
  65. package/dist/native-sessions/codex-history.d.ts.map +1 -1
  66. package/dist/native-sessions/codex-history.js +11 -11
  67. package/dist/native-sessions/codex-history.js.map +1 -1
  68. package/dist/native-sessions/history-images.d.ts +3 -0
  69. package/dist/native-sessions/history-images.d.ts.map +1 -0
  70. package/dist/native-sessions/history-images.js +74 -0
  71. package/dist/native-sessions/history-images.js.map +1 -0
  72. package/dist/run-daemon.d.ts.map +1 -1
  73. package/dist/run-daemon.js +30 -7
  74. package/dist/run-daemon.js.map +1 -1
  75. package/dist/runtime.js +1205 -354
  76. package/dist/runtime.js.map +4 -4
  77. 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 realpath8, stat as stat8 } from "node:fs/promises";
9
- import { dirname as dirname8, join as join17, resolve as resolve5 } from "node:path";
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 isAbsolute2, join as join5, normalize } from "node:path";
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 join4, resolve as resolve2 } from "node:path";
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 join4(homedir(), ".mobius");
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 (!isAbsolute2(path2) || normalize(path2) !== path2) {
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 = join5(readStateDirectory(context.environment), "agents", this.id, "home");
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
- join5(stateDirectory, "agents", this.id, DEEPSEEK_HARNESS_PACKAGE.version),
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 isAbsolute3, join as join6, relative as relative2, sep as sep2 } from "node:path";
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}`) && !isAbsolute3(difference);
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
- join6(stateDirectory, "agents", this.id, GROK_BUILD_MANAGED_VERSION, "home")
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(join6(stateDirectory, "agents", this.id, GROK_BUILD_MANAGED_VERSION));
1421
- await validateManagedNpmPackage(join6(versionRoot, "package"), grokBuildManagedPackage(platform, process.arch));
1422
- const executable = await resolveExecutablePath(join6(versionRoot, "home", "bin", "grok"), platform);
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 join8 } from "node:path";
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 isAbsolute4, join as join7, relative as relative3, sep as sep3 } from "node:path";
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}`) && !isAbsolute4(difference);
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(join7(rootPath, "archive.json"));
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(join7(rootPath, "bin", definition.executableName));
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
- join8(stateDirectory, "agents", this.id, OPENCODE_MANAGED_VERSION),
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 join9 } from "node:path";
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
- join9(stateDirectory, "agents", this.id, PI_AGENT_PACKAGE.version),
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 isAbsolute5, join as join10 } from "node:path";
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
- join10(stateDirectory, "agents", this.id, WORKBUDDY_MANAGED_VERSION),
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 = [join10("/Applications", ...WORKBUDDY_MACOS_EXECUTABLE_PATH)];
2017
+ const requestedPaths = [join11("/Applications", ...WORKBUDDY_MACOS_EXECUTABLE_PATH)];
1907
2018
  const homeDirectory = context.environment["HOME"];
1908
- if (homeDirectory !== void 0 && isAbsolute5(homeDirectory)) {
1909
- requestedPaths.unshift(join10(homeDirectory, "Applications", ...WORKBUDDY_MACOS_EXECUTABLE_PATH));
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 isAbsolute6, join as join12 } from "node:path";
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 join11 } from "node:path";
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 = join11(this.#stateDirectory, "adapters", specification.id, specification.adapterVersion);
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
- join12(readStateDirectory(context.environment), "adapters", specification.id, specification.adapterVersion),
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 || !isAbsolute6(override)) {
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 normalizedVersion(output2) {
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 = normalizedVersion(result.stdout || result.stderr);
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(record2) {
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
- record2.event,
2541
- record2.commandId,
2542
- record2.sessionId,
2543
- JSON.stringify(record2.details ?? {})
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 join13 } from "node:path";
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 record2 of pendingRecords.get(ctx) ?? []) {
18607
- const seen = ctx.seen.get(record2);
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.object({
21431
- cachedInputTokens: TOKEN_COUNT,
21432
- cachedWriteTokens: TOKEN_COUNT.optional(),
21433
- inputTokens: TOKEN_COUNT,
21434
- outputTokens: TOKEN_COUNT,
21435
- reasoningOutputTokens: TOKEN_COUNT,
21436
- totalTokens: TOKEN_COUNT
21437
- }).readonly();
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 ?? join13(readStateDirectory(environment), "workspace");
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 basename3, join as join15 } from "node:path";
23221
+ import { basename as basename4, join as join16 } from "node:path";
23081
23222
  import { styleText } from "node:util";
23082
- import { fetch as fetch5, WebSocket as WebSocket2 } from "undici";
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 parsed = parseNativeHistoryText(
24043
- content.type === "text" ? content.text : content.type === "image" ? `[@image](data:${content.mimeType};base64,${content.data})` : `[${content.type} attachment]`
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 || this.#imageCharacters > SESSION_HISTORY_IMAGE_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 history.snapshot();
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.#turn.onText(update.content.text, truncate3(update.messageId ?? "", 255));
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.#getObserver().onContent({
25632
- commandId: this.#turn.commandId,
25633
- content: normalizeContentBlock(update.content),
25634
- contentId: `content-${crypto.randomUUID()}`,
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 realpath6, stat as stat5 } from "node:fs/promises";
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 isAbsolute7, join as join14, normalize as normalize2, relative as relative4 } from "node:path";
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") || normalize2(decoded) !== decoded) {
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 (isAbsolute7(path2)) {
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 (!isAbsolute7(requested) || requested.includes("\0") || normalize2(requested) !== requested) {
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 realpath6(requested);
27883
+ const target = await realpath7(requested);
27076
27884
  signal.throwIfAborted();
27077
- const metadata = await stat5(target);
27885
+ const metadata = await stat6(target);
27078
27886
  signal.throwIfAborted();
27079
- if (!isAbsolute7(target) || normalize2(target) !== target || !metadata.isDirectory()) {
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 = relative4(homedir2(), path2);
27095
- return suffix === "" ? "~" : !isAbsolute7(suffix) && suffix !== ".." && !suffix.startsWith(`..${process.platform === "win32" ? "\\" : "/"}`) ? `~/${suffix.replaceAll("\\", "/")}` : path2;
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: basename(path2) || path2,
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(join14(target, child.name), signal);
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 createHash2, randomUUID } from "node:crypto";
27161
- import { stat as stat6 } from "node:fs/promises";
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 createHash2("sha256").update(value, "utf8").digest("hex");
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 stat6(path2);
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 isAbsolute8 } from "node:path";
27637
- import { fetch as fetch3 } from "undici";
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 IDENTIFIER_PATTERN5 = /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/;
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 isRecord9(value) {
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 (!isRecord9(value)) {
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" || !IDENTIFIER_PATTERN5.test(idempotencyKey) || typeof target !== "string" || !IDENTIFIER_PATTERN5.test(target) || typeof text !== "string" || text.trim().length === 0 || text.length > 1e4) {
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 daemonToken(relayUrl) {
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 && isRecord9(value) && typeof value["outboundMessageId"] === "string") {
28523
+ if (response.status === 202 && isRecord10(value) && typeof value["outboundMessageId"] === "string") {
27716
28524
  return value["outboundMessageId"];
27717
28525
  }
27718
- if (isRecord9(value) && isRecord9(value["error"])) {
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 && !isAbsolute8(socketPath)) {
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 (!isRecord9(error61) || error61["code"] !== "ENOENT") {
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 (!isRecord9(error61) || error61["code"] !== "ENOENT") {
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 fetch3(relayEndpoint(this.#relayUrl, context, request.target), {
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 ${daemonToken(this.#relayUrl)}`,
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 basename2 } from "node:path";
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 parsed = parseNativeHistoryText(
27916
- content.map((block) => {
27917
- const { type: type2 } = itemTypeSchema.parse(block);
27918
- if (type2 === "text") {
27919
- return textSchema.parse(block).text;
27920
- }
27921
- if (type2 === "image") {
27922
- return `[@image](${imageSchema.parse(block).url})`;
27923
- }
27924
- return "[Attachment]";
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: parsed.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
- imageCharacters += (message.images ?? []).reduce((size, image) => size + image.data.length, 0);
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
- return await response.promise;
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: basename2(path2) });
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 createHash3 } from "node:crypto";
28505
- import { fetch as fetch4 } from "undici";
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 IDENTIFIER_PATTERN6 = /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/;
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 || !IDENTIFIER_PATTERN6.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)) {
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 fetch4(downloadUrl(config2, command, reference), {
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 (createHash3("sha256").update(bytes).digest("hex") !== reference.sha256) {
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 join15("/tmp", `mobius-bot-${randomUUID4()}.sock`);
30482
+ return join16("/tmp", `mobius-bot-${randomUUID4()}.sock`);
29677
30483
  }
29678
30484
  var DaemonAcpObserver = class {
30485
+ #config;
29679
30486
  #record;
29680
- constructor(record2) {
29681
- this.#record = record2;
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 fetch5(activeTurnReconciliationEndpoint(config2, turn), {
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: basename3(directory)
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 (command.disposition !== SessionPromptDisposition.Steer) {
31566
+ if (trackActiveAttempt) {
30749
31567
  activeAttemptIds.set(command.sessionId, receipt.attemptId);
30750
31568
  }
30751
31569
  try {
30752
- await executePrompt(
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
- await processDeliveredPrompt(delivery);
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 realpath7, rename as rename3, stat as stat7, writeFile as writeFile2 } from "node:fs/promises";
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 basename4, join as join16, resolve as resolve4 } from "node:path";
31580
- import { fetch as fetch6 } from "undici";
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 IDENTIFIER_PATTERN7 = /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/;
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 isRecord10(value) {
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 (!IDENTIFIER_PATTERN7.test(value)) {
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 realpath7(requestedWorkspace);
31647
- const metadata = await stat7(defaultWorkspace);
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 (isRecord10(value)) {
32527
+ if (isRecord11(value)) {
31677
32528
  const error61 = value["error"];
31678
- if (isRecord10(error61)) {
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 (!isRecord10(value) || !hasExactKeys(value, expectedKeys)) {
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" || !IDENTIFIER_PATTERN7.test(channelId) || typeof runtimeCredential2 !== "string" || !TOKEN_PATTERN2.test(runtimeCredential2) || typeof runtimeId !== "string" || !IDENTIFIER_PATTERN7.test(runtimeId)) {
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 fetch6(endpoint, {
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: basename4(defaultWorkspace) || "Local workspace"
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 = join16(readStateDirectory(environment), "connections");
32585
+ const connectionsDirectory = join17(readStateDirectory(environment), "connections");
31735
32586
  await mkdir4(connectionsDirectory, { mode: 448, recursive: true });
31736
- const connectionPath = join16(connectionsDirectory, `${channelId}.json`);
31737
- const temporaryPath = join16(connectionsDirectory, `.${channelId}.${randomUUID5()}.tmp`);
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 (!isRecord10(value) || !hasExactKeys(value, SAVED_CONNECTION_KEYS) && !hasExactKeys(value, LEGACY_SAVED_CONNECTION_KEYS)) {
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 || !IDENTIFIER_PATTERN7.test(channelId) || typeof runtimeCredential2 !== "string" || !TOKEN_PATTERN2.test(runtimeCredential2) || typeof relayOrigin !== "string") {
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 = join16(readStateDirectory(environment), "connections", `${channelId}.json`);
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 = join16(readStateDirectory(environment), "audit", `${connection.channelId}.sqlite`);
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 = join16(readStateDirectory(environment), "connections", `${normalizedChannelId}.json`);
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 IDENTIFIER_PATTERN8 = /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/;
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 (!IDENTIFIER_PATTERN8.test(channelId)) {
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() || join17(readStateDirectory(environment), "audit", `${channelId}.sqlite`),
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 realpath8(requested);
31957
- const metadata = await stat8(resolved);
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
  }