@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/cli.js CHANGED
@@ -11,7 +11,7 @@ import { mkdir as mkdir5 } from "node:fs/promises";
11
11
  // package.json
12
12
  var package_default = {
13
13
  name: "@moxt-ai/mobius",
14
- version: "0.0.27",
14
+ version: "0.0.29",
15
15
  description: "Mobius CLI for pairing and running local AI agent services.",
16
16
  type: "module",
17
17
  bin: {
@@ -55,6 +55,7 @@ var package_default = {
55
55
  },
56
56
  devDependencies: {
57
57
  "@moxt-ai/mobius-protocol": "workspace:*",
58
+ "@moxt-ai/mobius-sdk": "workspace:*",
58
59
  "@types/node": "^24.13.3",
59
60
  esbuild: "0.28.2"
60
61
  },
@@ -1157,6 +1158,13 @@ var ManagedNpmPackageInstaller = class {
1157
1158
 
1158
1159
  // src/agent-catalog/agent-specification.ts
1159
1160
  import { join as join3 } from "node:path";
1161
+
1162
+ // src/agent-catalog/version-output.ts
1163
+ function normalizeVersionOutput(output2) {
1164
+ return output2.trim().split(/\r?\n/, 1)[0]?.trim().slice(0, 128) ?? "";
1165
+ }
1166
+
1167
+ // src/agent-catalog/agent-specification.ts
1160
1168
  var VERSION_PROBE_TIMEOUT_MILLISECONDS = 3e3;
1161
1169
  var ACP_PROBE_TIMEOUT_MILLISECONDS = 5e3;
1162
1170
  var DEFAULT_PROMPT_TIMEOUT_MILLISECONDS = 30 * 60 * 1e3;
@@ -1165,6 +1173,8 @@ var LocalAgentSpecification = class {
1165
1173
  authenticationCommand = () => "";
1166
1174
  adapterVersionArguments = ["--version"];
1167
1175
  agentVersionArguments = ["--version"];
1176
+ normalizeAdapterVersion = normalizeVersionOutput;
1177
+ normalizeAgentVersion = normalizeVersionOutput;
1168
1178
  promptTimeoutMilliseconds = DEFAULT_PROMPT_TIMEOUT_MILLISECONDS;
1169
1179
  versionProbeTimeoutMilliseconds = VERSION_PROBE_TIMEOUT_MILLISECONDS;
1170
1180
  resolveManagedAgent = async (stateDirectory, platform, signal) => {
@@ -1276,6 +1286,20 @@ var AgentProbeError = class extends Error {
1276
1286
  }
1277
1287
  };
1278
1288
 
1289
+ // src/agent-catalog/agents/resolve-user-local-executable.ts
1290
+ import { isAbsolute as isAbsolute2, join as join4 } from "node:path";
1291
+ async function resolveUserLocalExecutable(executableName, context) {
1292
+ context.signal.throwIfAborted();
1293
+ const platform = context.platform ?? process.platform;
1294
+ const homeDirectory = context.environment["HOME"];
1295
+ if (platform === "win32" || homeDirectory === void 0 || !isAbsolute2(homeDirectory)) {
1296
+ return [];
1297
+ }
1298
+ const executable = await resolveExecutablePath(join4(homeDirectory, ".local", "bin", executableName), platform);
1299
+ context.signal.throwIfAborted();
1300
+ return executable === null ? [] : [executable];
1301
+ }
1302
+
1279
1303
  // src/agent-catalog/agents/verify-session-creation.ts
1280
1304
  import { methods } from "@agentclientprotocol/sdk";
1281
1305
  async function verifySessionCreation(connection, capabilities, defaultWorkspace, signal, label) {
@@ -1300,6 +1324,37 @@ async function verifySessionCreation(connection, capabilities, defaultWorkspace,
1300
1324
  }
1301
1325
  }
1302
1326
 
1327
+ // src/agent-catalog/agents/copilot-cli-agent.ts
1328
+ var COPILOT_CLI_TESTED_VERSION = "1.0.83";
1329
+ var CopilotCliAgentSpecification = class extends DirectAcpAgentDefinition {
1330
+ acpProbeTimeoutMilliseconds = 2e4;
1331
+ adapterVersion = COPILOT_CLI_TESTED_VERSION;
1332
+ authenticationCommand = () => "copilot login";
1333
+ agentExecutable = "copilot";
1334
+ id = "github-copilot-cli";
1335
+ label = "GitHub Copilot CLI";
1336
+ versionProbeTimeoutMilliseconds = 1e4;
1337
+ constructor() {
1338
+ super(
1339
+ "MOBIUS_COPILOT_PATH",
1340
+ ["--no-auto-update", "--acp", "--stdio"],
1341
+ ["agents", "github-copilot-cli", COPILOT_CLI_TESTED_VERSION, "bin", "copilot"]
1342
+ );
1343
+ }
1344
+ createLaunchEnvironment = async (_agent, _context) => Object.freeze({ COPILOT_AUTO_UPDATE: "false" });
1345
+ resolveInstalledAgentExecutables = async (context) => await resolveUserLocalExecutable(this.agentExecutable, context);
1346
+ verifyAcp = async (connection, initialized, defaultWorkspace, signal) => {
1347
+ const capabilities = initialized.agentCapabilities ?? {};
1348
+ if (capabilities.loadSession !== true || capabilities.sessionCapabilities?.list == null || (initialized.authMethods ?? []).length === 0) {
1349
+ throw new AgentProbeError(
1350
+ "acp_incompatible",
1351
+ "GitHub Copilot CLI reported an unsupported ACP capability set"
1352
+ );
1353
+ }
1354
+ await verifySessionCreation(connection, capabilities, defaultWorkspace, signal, this.label);
1355
+ };
1356
+ };
1357
+
1303
1358
  // src/agent-catalog/agents/cursor-cli-agent.ts
1304
1359
  var CURSOR_CLI_TESTED_VERSION = "2026.09.02-c22c1a3";
1305
1360
  var CursorCliAgentSpecification = class extends DirectAcpAgentDefinition {
@@ -1326,7 +1381,7 @@ var CursorCliAgentSpecification = class extends DirectAcpAgentDefinition {
1326
1381
 
1327
1382
  // src/agent-catalog/agents/deepseek-harness-agent.ts
1328
1383
  import { realpath as realpath3, stat as stat3 } from "node:fs/promises";
1329
- import { isAbsolute as isAbsolute2, join as join5, normalize } from "node:path";
1384
+ import { isAbsolute as isAbsolute3, join as join6, normalize } from "node:path";
1330
1385
 
1331
1386
  // src/agent-installation/deepseek-managed-package.ts
1332
1387
  var DeepSeekHarnessManagedPackage = class extends SriManagedNpmPackageDefinition {
@@ -1344,18 +1399,18 @@ var DEEPSEEK_HARNESS_PACKAGE = new DeepSeekHarnessManagedPackage(
1344
1399
 
1345
1400
  // src/storage/state-directory.ts
1346
1401
  import { homedir } from "node:os";
1347
- import { join as join4, resolve as resolve2 } from "node:path";
1402
+ import { join as join5, resolve as resolve2 } from "node:path";
1348
1403
  function readStateDirectory(environment = process.env) {
1349
1404
  const configured = environment["MOBIUS_STATE_DIRECTORY"]?.trim();
1350
1405
  if (configured !== void 0 && configured.length > 0) {
1351
1406
  return resolve2(configured);
1352
1407
  }
1353
- return join4(homedir(), ".mobius");
1408
+ return join5(homedir(), ".mobius");
1354
1409
  }
1355
1410
 
1356
1411
  // src/agent-catalog/agents/deepseek-harness-agent.ts
1357
1412
  async function validateAgentHome(path2) {
1358
- if (!isAbsolute2(path2) || normalize(path2) !== path2) {
1413
+ if (!isAbsolute3(path2) || normalize(path2) !== path2) {
1359
1414
  throw new AgentProbeError("agent_environment_invalid", "The configured Agent home is invalid");
1360
1415
  }
1361
1416
  try {
@@ -1405,7 +1460,7 @@ var DeepSeekHarnessAgentSpecification = class extends DirectAcpAgentDefinition {
1405
1460
  context.signal
1406
1461
  );
1407
1462
  if (managed.path === agent.path) {
1408
- selectedHome = join5(readStateDirectory(context.environment), "agents", this.id, "home");
1463
+ selectedHome = join6(readStateDirectory(context.environment), "agents", this.id, "home");
1409
1464
  }
1410
1465
  } catch {
1411
1466
  context.signal.throwIfAborted();
@@ -1421,7 +1476,7 @@ var DeepSeekHarnessAgentSpecification = class extends DirectAcpAgentDefinition {
1421
1476
  resolveManagedAgent = async (stateDirectory, _platform, signal) => {
1422
1477
  signal.throwIfAborted();
1423
1478
  const executable = await validateManagedNpmPackage(
1424
- join5(stateDirectory, "agents", this.id, DEEPSEEK_HARNESS_PACKAGE.version),
1479
+ join6(stateDirectory, "agents", this.id, DEEPSEEK_HARNESS_PACKAGE.version),
1425
1480
  DEEPSEEK_HARNESS_PACKAGE
1426
1481
  );
1427
1482
  signal.throwIfAborted();
@@ -1441,9 +1496,41 @@ var DeepSeekHarnessAgentSpecification = class extends DirectAcpAgentDefinition {
1441
1496
  };
1442
1497
  };
1443
1498
 
1499
+ // src/agent-catalog/agents/gemini-cli-agent.ts
1500
+ var GEMINI_CLI_TESTED_VERSION = "0.59.0";
1501
+ var GeminiCliAgentSpecification = class extends DirectAcpAgentDefinition {
1502
+ acpProbeTimeoutMilliseconds = 2e4;
1503
+ adapterVersion = GEMINI_CLI_TESTED_VERSION;
1504
+ authenticationCommand = () => "gemini";
1505
+ agentExecutable = "gemini";
1506
+ id = "gemini-cli";
1507
+ label = "Gemini CLI";
1508
+ versionProbeTimeoutMilliseconds = 1e4;
1509
+ constructor() {
1510
+ super(
1511
+ "MOBIUS_GEMINI_PATH",
1512
+ ["--acp"],
1513
+ [
1514
+ "agents",
1515
+ "gemini-cli",
1516
+ GEMINI_CLI_TESTED_VERSION,
1517
+ "bin",
1518
+ process.platform === "win32" ? "gemini.cmd" : "gemini"
1519
+ ]
1520
+ );
1521
+ }
1522
+ verifyAcp = async (connection, initialized, defaultWorkspace, signal) => {
1523
+ const capabilities = initialized.agentCapabilities ?? {};
1524
+ if (capabilities.loadSession !== true || (initialized.authMethods ?? []).length === 0) {
1525
+ throw new AgentProbeError("acp_incompatible", "Gemini CLI reported an unsupported ACP capability set");
1526
+ }
1527
+ await verifySessionCreation(connection, capabilities, defaultWorkspace, signal, this.label);
1528
+ };
1529
+ };
1530
+
1444
1531
  // src/agent-catalog/agents/grok-build-agent.ts
1445
1532
  import { realpath as realpath4 } from "node:fs/promises";
1446
- import { isAbsolute as isAbsolute3, join as join6, relative as relative2, sep as sep2 } from "node:path";
1533
+ import { isAbsolute as isAbsolute4, join as join7, relative as relative2, sep as sep2 } from "node:path";
1447
1534
 
1448
1535
  // src/agent-installation/grok-managed-package.ts
1449
1536
  var GROK_BUILD_MANAGED_VERSION = "1.0.21";
@@ -1506,7 +1593,7 @@ function grokBuildManagedPackage(platform, architecture) {
1506
1593
  // src/agent-catalog/agents/grok-build-agent.ts
1507
1594
  function isContainedPath2(root, candidate) {
1508
1595
  const difference = relative2(root, candidate);
1509
- return difference.length > 0 && difference !== ".." && !difference.startsWith(`..${sep2}`) && !isAbsolute3(difference);
1596
+ return difference.length > 0 && difference !== ".." && !difference.startsWith(`..${sep2}`) && !isAbsolute4(difference);
1510
1597
  }
1511
1598
  var GrokBuildAgentSpecification = class extends DirectAcpAgentDefinition {
1512
1599
  adapterVersion = GROK_BUILD_MANAGED_VERSION;
@@ -1534,7 +1621,7 @@ var GrokBuildAgentSpecification = class extends DirectAcpAgentDefinition {
1534
1621
  if (managed.path === agent.path) {
1535
1622
  return Object.freeze({
1536
1623
  GROK_HOME: await realpath4(
1537
- join6(stateDirectory, "agents", this.id, GROK_BUILD_MANAGED_VERSION, "home")
1624
+ join7(stateDirectory, "agents", this.id, GROK_BUILD_MANAGED_VERSION, "home")
1538
1625
  )
1539
1626
  });
1540
1627
  }
@@ -1545,9 +1632,9 @@ var GrokBuildAgentSpecification = class extends DirectAcpAgentDefinition {
1545
1632
  };
1546
1633
  resolveManagedAgent = async (stateDirectory, platform, signal) => {
1547
1634
  signal.throwIfAborted();
1548
- const versionRoot = await realpath4(join6(stateDirectory, "agents", this.id, GROK_BUILD_MANAGED_VERSION));
1549
- await validateManagedNpmPackage(join6(versionRoot, "package"), grokBuildManagedPackage(platform, process.arch));
1550
- const executable = await resolveExecutablePath(join6(versionRoot, "home", "bin", "grok"), platform);
1635
+ const versionRoot = await realpath4(join7(stateDirectory, "agents", this.id, GROK_BUILD_MANAGED_VERSION));
1636
+ await validateManagedNpmPackage(join7(versionRoot, "package"), grokBuildManagedPackage(platform, process.arch));
1637
+ const executable = await resolveExecutablePath(join7(versionRoot, "home", "bin", "grok"), platform);
1551
1638
  signal.throwIfAborted();
1552
1639
  if (executable === null || !isContainedPath2(versionRoot, executable.path)) {
1553
1640
  throw new AgentProbeError("managed_agent_invalid", "The managed Grok Build executable is invalid");
@@ -1564,14 +1651,39 @@ var GrokBuildAgentSpecification = class extends DirectAcpAgentDefinition {
1564
1651
  };
1565
1652
  };
1566
1653
 
1654
+ // src/agent-catalog/agents/hermes-agent.ts
1655
+ var HERMES_TESTED_VERSION = "0.21.1";
1656
+ var HermesAgentSpecification = class extends DirectAcpAgentDefinition {
1657
+ acpProbeTimeoutMilliseconds = 2e4;
1658
+ adapterVersion = HERMES_TESTED_VERSION;
1659
+ adapterVersionArguments = ["acp", "--version"];
1660
+ authenticationCommand = () => "hermes acp --setup";
1661
+ agentExecutable = "hermes";
1662
+ agentVersionArguments = ["acp", "--version"];
1663
+ id = "hermes";
1664
+ label = "Hermes Agent";
1665
+ constructor() {
1666
+ super("MOBIUS_HERMES_PATH", ["acp"], ["agents", "hermes", HERMES_TESTED_VERSION, "bin", "hermes"]);
1667
+ }
1668
+ resolveInstalledAgentExecutables = async (context) => await resolveUserLocalExecutable(this.agentExecutable, context);
1669
+ verifyAcp = async (connection, initialized, defaultWorkspace, signal) => {
1670
+ const capabilities = initialized.agentCapabilities ?? {};
1671
+ const session = capabilities.sessionCapabilities;
1672
+ if (capabilities.loadSession !== true || session?.fork == null || session.list == null || session.resume == null || (initialized.authMethods ?? []).length === 0) {
1673
+ throw new AgentProbeError("acp_incompatible", "Hermes Agent reported an unsupported ACP capability set");
1674
+ }
1675
+ await verifySessionCreation(connection, capabilities, defaultWorkspace, signal, this.label);
1676
+ };
1677
+ };
1678
+
1567
1679
  // src/agent-catalog/agents/opencode-agent.ts
1568
- import { join as join8 } from "node:path";
1680
+ import { join as join9 } from "node:path";
1569
1681
 
1570
1682
  // src/agent-installation/managed-agent-archive.ts
1571
1683
  import { createHash } from "node:crypto";
1572
1684
  import { createReadStream } from "node:fs";
1573
1685
  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";
1574
- import { dirname as dirname2, isAbsolute as isAbsolute4, join as join7, relative as relative3, sep as sep3 } from "node:path";
1686
+ import { dirname as dirname2, isAbsolute as isAbsolute5, join as join8, relative as relative3, sep as sep3 } from "node:path";
1575
1687
 
1576
1688
  // src/agent-installation/verified-download.ts
1577
1689
  import { fetch } from "undici";
@@ -1677,7 +1789,7 @@ function isRecord3(value) {
1677
1789
  }
1678
1790
  function isContainedPath3(root, candidate) {
1679
1791
  const difference = relative3(root, candidate);
1680
- return difference.length > 0 && difference !== ".." && !difference.startsWith(`..${sep3}`) && !isAbsolute4(difference);
1792
+ return difference.length > 0 && difference !== ".." && !difference.startsWith(`..${sep3}`) && !isAbsolute5(difference);
1681
1793
  }
1682
1794
  async function hashFile(path2, signal) {
1683
1795
  signal.throwIfAborted();
@@ -1756,11 +1868,11 @@ async function validateManagedAgentArchive(root, definition, signal) {
1756
1868
  if (!rootMetadata.isDirectory() || typeof process.getuid === "function" && rootMetadata.uid !== process.getuid()) {
1757
1869
  throw new Error("Managed Agent root is not user-owned");
1758
1870
  }
1759
- const manifest = await readManifest(join7(rootPath, "archive.json"));
1871
+ const manifest = await readManifest(join8(rootPath, "archive.json"));
1760
1872
  if (manifest["archiveSha256"] !== definition.archiveSha256 || manifest["archiveUrl"] !== definition.archiveUrl.toString() || manifest["version"] !== definition.version || typeof manifest["executableSha256"] !== "string") {
1761
1873
  throw new Error("Managed Agent archive identity is invalid");
1762
1874
  }
1763
- const executable = await resolveExecutablePath(join7(rootPath, "bin", definition.executableName));
1875
+ const executable = await resolveExecutablePath(join8(rootPath, "bin", definition.executableName));
1764
1876
  if (executable === null || !isContainedPath3(rootPath, executable.path) || await hashFile(executable.path, signal) !== manifest["executableSha256"]) {
1765
1877
  throw new Error("Managed Agent executable is invalid");
1766
1878
  }
@@ -1852,7 +1964,7 @@ var OpenCodeAgentSpecification = class extends DirectAcpAgentDefinition {
1852
1964
  }
1853
1965
  createLaunchEnvironment = async (_agent, _context) => Object.freeze({ OPENCODE_DISABLE_AUTOUPDATE: "1" });
1854
1966
  resolveManagedAgent = async (stateDirectory, platform, signal) => await validateManagedAgentArchive(
1855
- join8(stateDirectory, "agents", this.id, OPENCODE_MANAGED_VERSION),
1967
+ join9(stateDirectory, "agents", this.id, OPENCODE_MANAGED_VERSION),
1856
1968
  openCodeManagedArchive(platform, process.arch),
1857
1969
  signal
1858
1970
  );
@@ -1870,7 +1982,7 @@ var OpenCodeAgentSpecification = class extends DirectAcpAgentDefinition {
1870
1982
  };
1871
1983
 
1872
1984
  // src/agent-catalog/agents/pi-agent.ts
1873
- import { join as join9 } from "node:path";
1985
+ import { join as join10 } from "node:path";
1874
1986
  import {
1875
1987
  methods as methods2
1876
1988
  } from "@agentclientprotocol/sdk";
@@ -1929,7 +2041,7 @@ var PiAgentSpecification = class extends BridgedAcpAgentDefinition {
1929
2041
  resolveManagedAgent = async (stateDirectory, _platform, signal) => {
1930
2042
  signal.throwIfAborted();
1931
2043
  const executable = await validateManagedNpmPackage(
1932
- join9(stateDirectory, "agents", this.id, PI_AGENT_PACKAGE.version),
2044
+ join10(stateDirectory, "agents", this.id, PI_AGENT_PACKAGE.version),
1933
2045
  PI_AGENT_PACKAGE
1934
2046
  );
1935
2047
  signal.throwIfAborted();
@@ -1967,7 +2079,7 @@ var PiAgentSpecification = class extends BridgedAcpAgentDefinition {
1967
2079
  };
1968
2080
 
1969
2081
  // src/agent-catalog/agents/workbuddy-agent.ts
1970
- import { isAbsolute as isAbsolute5, join as join10 } from "node:path";
2082
+ import { isAbsolute as isAbsolute6, join as join11 } from "node:path";
1971
2083
 
1972
2084
  // src/agent-installation/workbuddy-managed-package.ts
1973
2085
  var WORKBUDDY_MANAGED_VERSION = "2.146.0";
@@ -2020,7 +2132,7 @@ var WorkBuddyAgentSpecification = class extends DirectAcpAgentDefinition {
2020
2132
  resolveManagedAgent = async (stateDirectory, _platform, signal) => {
2021
2133
  signal.throwIfAborted();
2022
2134
  const executable = await validateManagedNpmPackage(
2023
- join10(stateDirectory, "agents", this.id, WORKBUDDY_MANAGED_VERSION),
2135
+ join11(stateDirectory, "agents", this.id, WORKBUDDY_MANAGED_VERSION),
2024
2136
  WORKBUDDY_MANAGED_PACKAGE
2025
2137
  );
2026
2138
  signal.throwIfAborted();
@@ -2031,10 +2143,10 @@ var WorkBuddyAgentSpecification = class extends DirectAcpAgentDefinition {
2031
2143
  if ((context.platform ?? process.platform) !== "darwin") {
2032
2144
  return [];
2033
2145
  }
2034
- const requestedPaths = [join10("/Applications", ...WORKBUDDY_MACOS_EXECUTABLE_PATH)];
2146
+ const requestedPaths = [join11("/Applications", ...WORKBUDDY_MACOS_EXECUTABLE_PATH)];
2035
2147
  const homeDirectory = context.environment["HOME"];
2036
- if (homeDirectory !== void 0 && isAbsolute5(homeDirectory)) {
2037
- requestedPaths.unshift(join10(homeDirectory, "Applications", ...WORKBUDDY_MACOS_EXECUTABLE_PATH));
2148
+ if (homeDirectory !== void 0 && isAbsolute6(homeDirectory)) {
2149
+ requestedPaths.unshift(join11(homeDirectory, "Applications", ...WORKBUDDY_MACOS_EXECUTABLE_PATH));
2038
2150
  }
2039
2151
  const executables = [];
2040
2152
  for (const requestedPath of requestedPaths) {
@@ -2060,12 +2172,15 @@ function supportedLocalAgentSpecifications() {
2060
2172
  return Object.freeze([
2061
2173
  new CodexAgentSpecification(),
2062
2174
  new ClaudeCodeAgentSpecification(),
2175
+ new CopilotCliAgentSpecification(),
2063
2176
  new PiAgentSpecification(),
2064
2177
  new DeepSeekHarnessAgentSpecification(),
2178
+ new HermesAgentSpecification(),
2065
2179
  new OpenCodeAgentSpecification(),
2066
2180
  new CursorCliAgentSpecification(),
2067
2181
  new GrokBuildAgentSpecification(),
2068
- new WorkBuddyAgentSpecification()
2182
+ new WorkBuddyAgentSpecification(),
2183
+ new GeminiCliAgentSpecification()
2069
2184
  ]);
2070
2185
  }
2071
2186
 
@@ -2105,11 +2220,173 @@ var createAcpClient = (handler) => client({ name: "mobius" }).onRequest(
2105
2220
  outcome: { outcome: "cancelled" }
2106
2221
  })).onNotification("cursor/update_todos", discardExtensionParams, async () => Promise.resolve()).onNotification("cursor/task", discardExtensionParams, async () => Promise.resolve()).onNotification("cursor/generate_image", discardExtensionParams, async () => Promise.resolve());
2107
2222
 
2223
+ // src/agent-catalog/acp-readiness-probe.ts
2224
+ var ACP_OUTPUT_LIMIT_BYTES = 1024 * 1024;
2225
+ var VerifiedAcpReadiness = class {
2226
+ adapterVersion;
2227
+ capabilities;
2228
+ constructor(adapterVersion, capabilities) {
2229
+ this.adapterVersion = adapterVersion;
2230
+ this.capabilities = capabilities;
2231
+ }
2232
+ };
2233
+ var DiscoveryAcpHandler = class {
2234
+ onElicitation = (_request, _signal) => Promise.reject(new Error("ACP probe does not accept elicitations"));
2235
+ onElicitationComplete = (_notification) => Promise.resolve();
2236
+ onPermission = (_request, _signal) => Promise.reject(new Error("ACP probe does not grant permissions"));
2237
+ onUpdate = (_notification) => Promise.resolve();
2238
+ };
2239
+ function readableAcpStream(input2) {
2240
+ let byteLength = 0;
2241
+ let open5 = true;
2242
+ return new ReadableStream({
2243
+ start(controller) {
2244
+ input2.on("data", (chunk) => {
2245
+ if (!open5) {
2246
+ return;
2247
+ }
2248
+ if (!(chunk instanceof Uint8Array)) {
2249
+ open5 = false;
2250
+ controller.error(new Error("ACP adapter produced invalid output"));
2251
+ return;
2252
+ }
2253
+ byteLength += chunk.byteLength;
2254
+ if (byteLength > ACP_OUTPUT_LIMIT_BYTES) {
2255
+ open5 = false;
2256
+ controller.error(new Error("ACP adapter output limit exceeded"));
2257
+ return;
2258
+ }
2259
+ controller.enqueue(new Uint8Array(chunk));
2260
+ });
2261
+ input2.once("end", () => {
2262
+ if (open5) {
2263
+ open5 = false;
2264
+ controller.close();
2265
+ }
2266
+ });
2267
+ input2.once("error", (error61) => {
2268
+ if (open5) {
2269
+ open5 = false;
2270
+ controller.error(error61);
2271
+ }
2272
+ });
2273
+ },
2274
+ cancel() {
2275
+ open5 = false;
2276
+ }
2277
+ });
2278
+ }
2279
+ function writableAcpStream(output2) {
2280
+ return new WritableStream({
2281
+ write(chunk) {
2282
+ return new Promise((resolveWrite, rejectWrite) => {
2283
+ output2.write(chunk, (error61) => {
2284
+ if (error61) {
2285
+ rejectWrite(error61);
2286
+ return;
2287
+ }
2288
+ resolveWrite();
2289
+ });
2290
+ });
2291
+ }
2292
+ });
2293
+ }
2294
+ async function probeAcpReadiness(specification, agent, environment, defaultWorkspace, signal) {
2295
+ signal.throwIfAborted();
2296
+ const controller = new AbortController();
2297
+ let timedOut = false;
2298
+ const timeout = setTimeout(() => {
2299
+ timedOut = true;
2300
+ controller.abort(new Error("ACP probe timed out"));
2301
+ }, specification.acpProbeTimeoutMilliseconds);
2302
+ const abort = () => controller.abort(signal.reason);
2303
+ signal.addEventListener("abort", abort, { once: true });
2304
+ if (signal.aborted) {
2305
+ abort();
2306
+ }
2307
+ const child = spawn2(agent.adapterPath, [...agent.arguments], {
2308
+ cwd: defaultWorkspace,
2309
+ detached: process.platform !== "win32",
2310
+ env: { ...environment, ...agent.environment },
2311
+ shell: false,
2312
+ stdio: ["pipe", "pipe", "pipe"]
2313
+ });
2314
+ const processExit = new Promise((_resolve, reject) => {
2315
+ const rejectExit = () => reject(new Error("ACP adapter exited during initialization"));
2316
+ child.once("error", reject);
2317
+ child.once("exit", rejectExit);
2318
+ if (child.exitCode !== null || child.signalCode !== null) {
2319
+ rejectExit();
2320
+ }
2321
+ });
2322
+ const stdin = child.stdin;
2323
+ const stdout = child.stdout;
2324
+ const stderr = child.stderr;
2325
+ if (stdin === null || stdout === null || stderr === null) {
2326
+ await stopProcessTree(child);
2327
+ throw new AgentProbeError("acp_incompatible", "ACP adapter streams are unavailable");
2328
+ }
2329
+ let stderrBytes = 0;
2330
+ const consumeStderr = (chunk) => {
2331
+ stderrBytes += chunk.byteLength;
2332
+ if (stderrBytes > ACP_OUTPUT_LIMIT_BYTES) {
2333
+ controller.abort(new Error("ACP adapter output limit exceeded"));
2334
+ }
2335
+ };
2336
+ stderr.on("data", consumeStderr);
2337
+ const connection = createAcpClient(new DiscoveryAcpHandler()).connect(
2338
+ ndJsonStream(writableAcpStream(stdin), readableAcpStream(stdout))
2339
+ );
2340
+ try {
2341
+ const initialized = await Promise.race([
2342
+ connection.agent.request(
2343
+ methods4.agent.initialize,
2344
+ {
2345
+ clientCapabilities: {},
2346
+ clientInfo: { name: "mobius", version: "0.0.3" },
2347
+ protocolVersion: PROTOCOL_VERSION
2348
+ },
2349
+ { cancellationSignal: controller.signal }
2350
+ ),
2351
+ processExit
2352
+ ]);
2353
+ if (initialized.protocolVersion !== PROTOCOL_VERSION) {
2354
+ throw new AgentProbeError("acp_incompatible", "ACP adapter selected an unsupported protocol version");
2355
+ }
2356
+ await specification.verifyAcp(connection, initialized, defaultWorkspace, controller.signal);
2357
+ return new VerifiedAcpReadiness(
2358
+ normalizeVersionOutput(initialized.agentInfo?.version ?? ""),
2359
+ normalizeAcpCapabilities(initialized)
2360
+ );
2361
+ } catch (error61) {
2362
+ if (signal.aborted) {
2363
+ signal.throwIfAborted();
2364
+ }
2365
+ if (timedOut) {
2366
+ throw new AgentProbeError("adapter_probe_timeout", "ACP adapter probe timed out", { cause: error61 });
2367
+ }
2368
+ if (error61 instanceof AgentProbeError) {
2369
+ throw error61;
2370
+ }
2371
+ if (error61 instanceof RequestError && error61.code === -32e3 && specification.authenticationCommand().length > 0) {
2372
+ throw new AgentProbeError("authentication_required", "Agent authentication is required", { cause: error61 });
2373
+ }
2374
+ throw new AgentProbeError("acp_incompatible", "ACP adapter initialization failed", { cause: error61 });
2375
+ } finally {
2376
+ clearTimeout(timeout);
2377
+ signal.removeEventListener("abort", abort);
2378
+ connection.close();
2379
+ stdin.end();
2380
+ stderr.removeListener("data", consumeStderr);
2381
+ await stopProcessTree(child);
2382
+ }
2383
+ }
2384
+
2108
2385
  // src/agent-catalog/executable-discovery.ts
2109
- import { isAbsolute as isAbsolute6, join as join12 } from "node:path";
2386
+ import { isAbsolute as isAbsolute7, join as join13 } from "node:path";
2110
2387
 
2111
2388
  // src/agent-installation/managed-adapter-installer.ts
2112
- import { join as join11 } from "node:path";
2389
+ import { join as join12 } from "node:path";
2113
2390
  var ManagedAdapterInstallError = class extends Error {
2114
2391
  code;
2115
2392
  constructor(code, message, options = {}) {
@@ -2166,7 +2443,7 @@ var ManagedAdapterInstaller = class {
2166
2443
  this.#stateDirectory = options.stateDirectory;
2167
2444
  }
2168
2445
  install = async (specification, signal) => {
2169
- const root = join11(this.#stateDirectory, "adapters", specification.id, specification.adapterVersion);
2446
+ const root = join12(this.#stateDirectory, "adapters", specification.id, specification.adapterVersion);
2170
2447
  try {
2171
2448
  return await this.#npmInstaller.install(
2172
2449
  root,
@@ -2200,7 +2477,7 @@ async function resolveManagedAdapterExecutable(specification, context) {
2200
2477
  let managed;
2201
2478
  try {
2202
2479
  managed = await validateManagedAdapter(
2203
- join12(readStateDirectory(context.environment), "adapters", specification.id, specification.adapterVersion),
2480
+ join13(readStateDirectory(context.environment), "adapters", specification.id, specification.adapterVersion),
2204
2481
  specification
2205
2482
  );
2206
2483
  } catch {
@@ -2211,7 +2488,7 @@ async function resolveManagedAdapterExecutable(specification, context) {
2211
2488
  async function resolveSpecificationExecutables(executableName, overrideVariable, resolveInstalled, resolveManaged, context) {
2212
2489
  const override = context.environment[overrideVariable];
2213
2490
  if (override !== void 0) {
2214
- if (override.length === 0 || !isAbsolute6(override)) {
2491
+ if (override.length === 0 || !isAbsolute7(override)) {
2215
2492
  return [];
2216
2493
  }
2217
2494
  const executable = await resolveExecutablePath(override, context.platform);
@@ -2265,10 +2542,7 @@ async function resolveAdapterExecutable(specification, context) {
2265
2542
  const executables = await resolveAdapterExecutables(specification, context);
2266
2543
  return executables[0] ?? null;
2267
2544
  }
2268
- function normalizedVersion(output2) {
2269
- return output2.trim().split(/\r?\n/, 1)[0]?.trim().slice(0, 128) ?? "";
2270
- }
2271
- async function probeVersion(executable, arguments_, environment, defaultWorkspace, signal, timeoutMilliseconds) {
2545
+ async function probeVersion(executable, arguments_, environment, defaultWorkspace, signal, timeoutMilliseconds, normalize4 = normalizeVersionOutput) {
2272
2546
  const result = await runBoundedProcess({
2273
2547
  arguments: arguments_,
2274
2548
  command: executable.path,
@@ -2277,7 +2551,7 @@ async function probeVersion(executable, arguments_, environment, defaultWorkspac
2277
2551
  signal,
2278
2552
  timeoutMilliseconds
2279
2553
  });
2280
- const version2 = normalizedVersion(result.stdout || result.stderr);
2554
+ const version2 = normalize4(result.stdout || result.stderr);
2281
2555
  if (version2.length === 0) {
2282
2556
  throw new ProcessExecutionError("process_exit_failed", "The executable did not report a version");
2283
2557
  }
@@ -2301,7 +2575,8 @@ async function findVerifiedAgentExecutable(specification, context) {
2301
2575
  context.environment,
2302
2576
  context.defaultWorkspace,
2303
2577
  context.signal,
2304
- specification.versionProbeTimeoutMilliseconds
2578
+ specification.versionProbeTimeoutMilliseconds,
2579
+ specification.normalizeAgentVersion
2305
2580
  );
2306
2581
  return new VerifiedAgentExecutable(executable, version2);
2307
2582
  } catch {
@@ -2313,168 +2588,6 @@ async function findVerifiedAgentExecutable(specification, context) {
2313
2588
  return null;
2314
2589
  }
2315
2590
 
2316
- // src/agent-catalog/acp-readiness-probe.ts
2317
- var ACP_OUTPUT_LIMIT_BYTES = 1024 * 1024;
2318
- var VerifiedAcpReadiness = class {
2319
- adapterVersion;
2320
- capabilities;
2321
- constructor(adapterVersion, capabilities) {
2322
- this.adapterVersion = adapterVersion;
2323
- this.capabilities = capabilities;
2324
- }
2325
- };
2326
- var DiscoveryAcpHandler = class {
2327
- onElicitation = (_request, _signal) => Promise.reject(new Error("ACP probe does not accept elicitations"));
2328
- onElicitationComplete = (_notification) => Promise.resolve();
2329
- onPermission = (_request, _signal) => Promise.reject(new Error("ACP probe does not grant permissions"));
2330
- onUpdate = (_notification) => Promise.resolve();
2331
- };
2332
- function readableAcpStream(input2) {
2333
- let byteLength = 0;
2334
- let open5 = true;
2335
- return new ReadableStream({
2336
- start(controller) {
2337
- input2.on("data", (chunk) => {
2338
- if (!open5) {
2339
- return;
2340
- }
2341
- if (!(chunk instanceof Uint8Array)) {
2342
- open5 = false;
2343
- controller.error(new Error("ACP adapter produced invalid output"));
2344
- return;
2345
- }
2346
- byteLength += chunk.byteLength;
2347
- if (byteLength > ACP_OUTPUT_LIMIT_BYTES) {
2348
- open5 = false;
2349
- controller.error(new Error("ACP adapter output limit exceeded"));
2350
- return;
2351
- }
2352
- controller.enqueue(new Uint8Array(chunk));
2353
- });
2354
- input2.once("end", () => {
2355
- if (open5) {
2356
- open5 = false;
2357
- controller.close();
2358
- }
2359
- });
2360
- input2.once("error", (error61) => {
2361
- if (open5) {
2362
- open5 = false;
2363
- controller.error(error61);
2364
- }
2365
- });
2366
- },
2367
- cancel() {
2368
- open5 = false;
2369
- }
2370
- });
2371
- }
2372
- function writableAcpStream(output2) {
2373
- return new WritableStream({
2374
- write(chunk) {
2375
- return new Promise((resolveWrite, rejectWrite) => {
2376
- output2.write(chunk, (error61) => {
2377
- if (error61) {
2378
- rejectWrite(error61);
2379
- return;
2380
- }
2381
- resolveWrite();
2382
- });
2383
- });
2384
- }
2385
- });
2386
- }
2387
- async function probeAcpReadiness(specification, agent, environment, defaultWorkspace, signal) {
2388
- signal.throwIfAborted();
2389
- const controller = new AbortController();
2390
- let timedOut = false;
2391
- const timeout = setTimeout(() => {
2392
- timedOut = true;
2393
- controller.abort(new Error("ACP probe timed out"));
2394
- }, specification.acpProbeTimeoutMilliseconds);
2395
- const abort = () => controller.abort(signal.reason);
2396
- signal.addEventListener("abort", abort, { once: true });
2397
- if (signal.aborted) {
2398
- abort();
2399
- }
2400
- const child = spawn2(agent.adapterPath, [...agent.arguments], {
2401
- cwd: defaultWorkspace,
2402
- detached: process.platform !== "win32",
2403
- env: { ...environment, ...agent.environment },
2404
- shell: false,
2405
- stdio: ["pipe", "pipe", "pipe"]
2406
- });
2407
- const processExit = new Promise((_resolve, reject) => {
2408
- const rejectExit = () => reject(new Error("ACP adapter exited during initialization"));
2409
- child.once("error", reject);
2410
- child.once("exit", rejectExit);
2411
- if (child.exitCode !== null || child.signalCode !== null) {
2412
- rejectExit();
2413
- }
2414
- });
2415
- const stdin = child.stdin;
2416
- const stdout = child.stdout;
2417
- const stderr = child.stderr;
2418
- if (stdin === null || stdout === null || stderr === null) {
2419
- await stopProcessTree(child);
2420
- throw new AgentProbeError("acp_incompatible", "ACP adapter streams are unavailable");
2421
- }
2422
- let stderrBytes = 0;
2423
- const consumeStderr = (chunk) => {
2424
- stderrBytes += chunk.byteLength;
2425
- if (stderrBytes > ACP_OUTPUT_LIMIT_BYTES) {
2426
- controller.abort(new Error("ACP adapter output limit exceeded"));
2427
- }
2428
- };
2429
- stderr.on("data", consumeStderr);
2430
- const connection = createAcpClient(new DiscoveryAcpHandler()).connect(
2431
- ndJsonStream(writableAcpStream(stdin), readableAcpStream(stdout))
2432
- );
2433
- try {
2434
- const initialized = await Promise.race([
2435
- connection.agent.request(
2436
- methods4.agent.initialize,
2437
- {
2438
- clientCapabilities: {},
2439
- clientInfo: { name: "mobius", version: "0.0.3" },
2440
- protocolVersion: PROTOCOL_VERSION
2441
- },
2442
- { cancellationSignal: controller.signal }
2443
- ),
2444
- processExit
2445
- ]);
2446
- if (initialized.protocolVersion !== PROTOCOL_VERSION) {
2447
- throw new AgentProbeError("acp_incompatible", "ACP adapter selected an unsupported protocol version");
2448
- }
2449
- await specification.verifyAcp(connection, initialized, defaultWorkspace, controller.signal);
2450
- return new VerifiedAcpReadiness(
2451
- normalizedVersion(initialized.agentInfo?.version ?? ""),
2452
- normalizeAcpCapabilities(initialized)
2453
- );
2454
- } catch (error61) {
2455
- if (signal.aborted) {
2456
- signal.throwIfAborted();
2457
- }
2458
- if (timedOut) {
2459
- throw new AgentProbeError("adapter_probe_timeout", "ACP adapter probe timed out", { cause: error61 });
2460
- }
2461
- if (error61 instanceof AgentProbeError) {
2462
- throw error61;
2463
- }
2464
- if (error61 instanceof RequestError && error61.code === -32e3 && specification.authenticationCommand().length > 0) {
2465
- throw new AgentProbeError("authentication_required", "Agent authentication is required", { cause: error61 });
2466
- }
2467
- throw new AgentProbeError("acp_incompatible", "ACP adapter initialization failed", { cause: error61 });
2468
- } finally {
2469
- clearTimeout(timeout);
2470
- signal.removeEventListener("abort", abort);
2471
- connection.close();
2472
- stdin.end();
2473
- stderr.removeListener("data", consumeStderr);
2474
- await stopProcessTree(child);
2475
- }
2476
- }
2477
-
2478
2591
  // src/agent-catalog/discover-agent.ts
2479
2592
  function agentProbeFailure(specification, error61) {
2480
2593
  if (error61 instanceof AgentProbeError) {
@@ -2518,7 +2631,8 @@ async function discoverAgent(specification, context) {
2518
2631
  context.environment,
2519
2632
  context.defaultWorkspace,
2520
2633
  context.signal,
2521
- specification.versionProbeTimeoutMilliseconds
2634
+ specification.versionProbeTimeoutMilliseconds,
2635
+ specification.normalizeAgentVersion
2522
2636
  );
2523
2637
  } catch (error61) {
2524
2638
  if (context.signal.aborted) {
@@ -2554,7 +2668,8 @@ async function discoverAgent(specification, context) {
2554
2668
  },
2555
2669
  context.defaultWorkspace,
2556
2670
  context.signal,
2557
- specification.versionProbeTimeoutMilliseconds
2671
+ specification.versionProbeTimeoutMilliseconds,
2672
+ specification.normalizeAdapterVersion
2558
2673
  );
2559
2674
  }
2560
2675
  } catch (error61) {
@@ -2787,7 +2902,7 @@ async function executeBotMessageCommand(arguments_, environment, signal) {
2787
2902
  }
2788
2903
 
2789
2904
  // src/config.ts
2790
- import { join as join13 } from "node:path";
2905
+ import { join as join14 } from "node:path";
2791
2906
 
2792
2907
  // ../../node_modules/.pnpm/zod@4.5.4/node_modules/zod/v4/classic/external.js
2793
2908
  var external_exports = {};
@@ -18841,8 +18956,8 @@ function rewriteKeyNames(ctx) {
18841
18956
  bySchema.set(entry.schema, entry);
18842
18957
  }
18843
18958
  const rewrites = /* @__PURE__ */ new Map();
18844
- for (const record2 of pendingRecords.get(ctx) ?? []) {
18845
- const seen = ctx.seen.get(record2);
18959
+ for (const record3 of pendingRecords.get(ctx) ?? []) {
18960
+ const seen = ctx.seen.get(record3);
18846
18961
  const names = (seen?.def ?? seen?.schema)?.propertyNames;
18847
18962
  if (!names || names === true || rewrites.has(names))
18848
18963
  continue;
@@ -21657,6 +21772,28 @@ function date4(params) {
21657
21772
 
21658
21773
  // ../protocol/src/prompt-usage.ts
21659
21774
  var TOKEN_COUNT = external_exports.number().int().nonnegative();
21775
+ function normalizeQuotaTokenCount(value) {
21776
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
21777
+ return value;
21778
+ }
21779
+ if (Reflect.has(value, "inputTokens") || Reflect.has(value, "outputTokens") || Reflect.has(value, "totalTokens")) {
21780
+ return value;
21781
+ }
21782
+ if (!Reflect.has(value, "input_tokens") && !Reflect.has(value, "output_tokens")) {
21783
+ return value;
21784
+ }
21785
+ const inputTokens = Reflect.get(value, "input_tokens");
21786
+ const outputTokens = Reflect.get(value, "output_tokens");
21787
+ const reportedTotal = Reflect.get(value, "total_tokens");
21788
+ return {
21789
+ cachedInputTokens: Reflect.get(value, "cached_input_tokens"),
21790
+ cachedWriteTokens: Reflect.get(value, "cached_write_tokens"),
21791
+ inputTokens,
21792
+ outputTokens,
21793
+ reasoningOutputTokens: Reflect.get(value, "reasoning_output_tokens"),
21794
+ totalTokens: reportedTotal === void 0 && typeof inputTokens === "number" && typeof outputTokens === "number" ? inputTokens + outputTokens : reportedTotal
21795
+ };
21796
+ }
21660
21797
  var promptUsageSchema = external_exports.object({
21661
21798
  cachedReadTokens: TOKEN_COUNT.nullish(),
21662
21799
  cachedWriteTokens: TOKEN_COUNT.nullish(),
@@ -21665,14 +21802,17 @@ var promptUsageSchema = external_exports.object({
21665
21802
  thoughtTokens: TOKEN_COUNT.nullish(),
21666
21803
  totalTokens: TOKEN_COUNT
21667
21804
  }).readonly();
21668
- var quotaTokenCountSchema = external_exports.object({
21669
- cachedInputTokens: TOKEN_COUNT,
21670
- cachedWriteTokens: TOKEN_COUNT.optional(),
21671
- inputTokens: TOKEN_COUNT,
21672
- outputTokens: TOKEN_COUNT,
21673
- reasoningOutputTokens: TOKEN_COUNT,
21674
- totalTokens: TOKEN_COUNT
21675
- }).readonly();
21805
+ var quotaTokenCountSchema = external_exports.preprocess(
21806
+ normalizeQuotaTokenCount,
21807
+ external_exports.object({
21808
+ cachedInputTokens: TOKEN_COUNT.optional(),
21809
+ cachedWriteTokens: TOKEN_COUNT.optional(),
21810
+ inputTokens: TOKEN_COUNT,
21811
+ outputTokens: TOKEN_COUNT,
21812
+ reasoningOutputTokens: TOKEN_COUNT.optional(),
21813
+ totalTokens: TOKEN_COUNT
21814
+ }).readonly()
21815
+ );
21676
21816
  var promptMetadataSchema = external_exports.object({
21677
21817
  quota: external_exports.object({
21678
21818
  model_usage: external_exports.array(
@@ -21799,6 +21939,7 @@ var elicitationFieldSchema = external_exports.strictObject({
21799
21939
  type: external_exports.enum(["boolean", "integer", "multiselect", "number", "select", "string"])
21800
21940
  }).readonly();
21801
21941
  var displayContentSchema = external_exports.strictObject({
21942
+ artifactId: external_exports.string().max(128).default(""),
21802
21943
  data: external_exports.string().max(4e6),
21803
21944
  mimeType: external_exports.string().max(255),
21804
21945
  name: external_exports.string().max(500),
@@ -21811,6 +21952,7 @@ var displayContentSchema = external_exports.strictObject({
21811
21952
  uri: external_exports.string().max(4096)
21812
21953
  }).readonly();
21813
21954
  var recordedDisplayContentSchema = external_exports.strictObject({
21955
+ artifactId: external_exports.string().max(128).default(""),
21814
21956
  data: external_exports.string().max(4e6),
21815
21957
  mimeType: external_exports.string().max(255),
21816
21958
  name: external_exports.string().max(500),
@@ -23298,7 +23440,7 @@ var decodeSessionEventRejection = (encoded) => decode5(encoded, eventRejectionSc
23298
23440
  // src/config.ts
23299
23441
  function loadDefaultWorkspace(environment = process.env) {
23300
23442
  const { MOBIUS_DEFAULT_WORKSPACE: configuredWorkspace } = environment;
23301
- return configuredWorkspace ?? join13(readStateDirectory(environment), "workspace");
23443
+ return configuredWorkspace ?? join14(readStateDirectory(environment), "workspace");
23302
23444
  }
23303
23445
  function createDaemonConfig(connection, agents = [], installableAgents = []) {
23304
23446
  return {
@@ -23317,7 +23459,7 @@ function createDaemonConfig(connection, agents = [], installableAgents = []) {
23317
23459
  import { randomUUID as randomUUID2 } from "node:crypto";
23318
23460
  import { mkdir as mkdir3, open as open4, realpath as realpath6, rename as rename3, stat as stat5, writeFile as writeFile2 } from "node:fs/promises";
23319
23461
  import { hostname as hostname3 } from "node:os";
23320
- import { basename, join as join14, resolve as resolve3 } from "node:path";
23462
+ import { basename, join as join15, resolve as resolve3 } from "node:path";
23321
23463
  import { fetch as fetch2 } from "undici";
23322
23464
  var PAIRING_TIMEOUT_MILLISECONDS = 2e4;
23323
23465
  var PAIRING_CODE_PATTERN = /^[A-HJ-NP-Z2-9]{4}(?:-[A-HJ-NP-Z2-9]{4}){4}$/;
@@ -23517,10 +23659,10 @@ async function claimPairing(options, defaultWorkspace, localAgents, installableA
23517
23659
  return options.pairingId.length > 0 ? decodePairingResponse(value, "runtimeCredential", REDEEM_RESPONSE_KEYS) : decodePairingResponse(value, "daemonToken", CLAIM_RESPONSE_KEYS);
23518
23660
  }
23519
23661
  async function persistConnection(channelId, relayOrigin, runtimeCredential2, defaultWorkspace, environment) {
23520
- const connectionsDirectory = join14(readStateDirectory(environment), "connections");
23662
+ const connectionsDirectory = join15(readStateDirectory(environment), "connections");
23521
23663
  await mkdir3(connectionsDirectory, { mode: 448, recursive: true });
23522
- const connectionPath = join14(connectionsDirectory, `${channelId}.json`);
23523
- const temporaryPath = join14(connectionsDirectory, `.${channelId}.${randomUUID2()}.tmp`);
23664
+ const connectionPath = join15(connectionsDirectory, `${channelId}.json`);
23665
+ const temporaryPath = join15(connectionsDirectory, `.${channelId}.${randomUUID2()}.tmp`);
23524
23666
  await writeFile2(
23525
23667
  temporaryPath,
23526
23668
  `${JSON.stringify(
@@ -23558,7 +23700,7 @@ function decodeSavedConnection(value, expectedChannelId) {
23558
23700
  };
23559
23701
  }
23560
23702
  async function readSavedConnection(channelId, environment) {
23561
- const connectionPath = join14(readStateDirectory(environment), "connections", `${channelId}.json`);
23703
+ const connectionPath = join15(readStateDirectory(environment), "connections", `${channelId}.json`);
23562
23704
  let encoded = "";
23563
23705
  const handle = await open4(connectionPath, "r");
23564
23706
  try {
@@ -23594,7 +23736,7 @@ function buildPairedDaemon(connection, connectionPath, inventory, environment) {
23594
23736
  const relayUrl = mobiusApiUrl(connection.relayOrigin, "/v1/runtimes/connect");
23595
23737
  relayUrl.protocol = relayUrl.protocol === "https:" ? "wss:" : "ws:";
23596
23738
  relayUrl.searchParams.set("token", connection.runtimeCredential);
23597
- const auditDatabasePath = join14(readStateDirectory(environment), "audit", `${connection.channelId}.sqlite`);
23739
+ const auditDatabasePath = join15(readStateDirectory(environment), "audit", `${connection.channelId}.sqlite`);
23598
23740
  return {
23599
23741
  channelUrl: new URL(`/channels/${encodeURIComponent(connection.channelId)}`, connection.relayOrigin).toString(),
23600
23742
  config: createDaemonConfig(
@@ -23644,7 +23786,7 @@ async function pairLocalMachine(arguments_, signal = new AbortController().signa
23644
23786
  }
23645
23787
  async function resumeMobiusRuntime(channelId, signal, environment = process.env) {
23646
23788
  const normalizedChannelId = validatePairingId(channelId);
23647
- const connectionPath = join14(readStateDirectory(environment), "connections", `${normalizedChannelId}.json`);
23789
+ const connectionPath = join15(readStateDirectory(environment), "connections", `${normalizedChannelId}.json`);
23648
23790
  const connection = await readSavedConnection(normalizedChannelId, environment);
23649
23791
  const inventory = await discoverLocalAgentInventory({
23650
23792
  defaultWorkspace: connection.defaultWorkspace,
@@ -23681,7 +23823,7 @@ var AuditStore = class {
23681
23823
  this.database.exec("ALTER TABLE audit_events ADD COLUMN details_json TEXT NOT NULL DEFAULT '{}'");
23682
23824
  }
23683
23825
  }
23684
- record(record2) {
23826
+ record(record3) {
23685
23827
  this.database.prepare(
23686
23828
  `
23687
23829
  INSERT INTO audit_events (
@@ -23694,10 +23836,10 @@ var AuditStore = class {
23694
23836
  `
23695
23837
  ).run(
23696
23838
  (/* @__PURE__ */ new Date()).toISOString(),
23697
- record2.event,
23698
- record2.commandId,
23699
- record2.sessionId,
23700
- JSON.stringify(record2.details ?? {})
23839
+ record3.event,
23840
+ record3.commandId,
23841
+ record3.sessionId,
23842
+ JSON.stringify(record3.details ?? {})
23701
23843
  );
23702
23844
  }
23703
23845
  close() {
@@ -23707,9 +23849,9 @@ var AuditStore = class {
23707
23849
 
23708
23850
  // src/run-daemon.ts
23709
23851
  import { randomUUID as randomUUID6 } from "node:crypto";
23710
- import { basename as basename4, join as join16 } from "node:path";
23852
+ import { basename as basename5, join as join17 } from "node:path";
23711
23853
  import { styleText } from "node:util";
23712
- import { fetch as fetch6, WebSocket as WebSocket2 } from "undici";
23854
+ import { fetch as fetch7, WebSocket as WebSocket2 } from "undici";
23713
23855
 
23714
23856
  // src/acp/session-manager.ts
23715
23857
  import { spawn as spawn3 } from "node:child_process";
@@ -23720,6 +23862,212 @@ import {
23720
23862
  RequestError as RequestError2
23721
23863
  } from "@agentclientprotocol/sdk";
23722
23864
 
23865
+ // src/authorization/local-raster.ts
23866
+ import { readFile, realpath as realpath7, stat as stat6 } from "node:fs/promises";
23867
+ import { basename as basename2, isAbsolute as isAbsolute8, normalize as normalize2, relative as relative4, sep as sep4 } from "node:path";
23868
+ import { fileURLToPath } from "node:url";
23869
+ var MAX_LOCAL_RASTER_BYTES = 3e6;
23870
+ var PNG_SIGNATURE = Uint8Array.of(137, 80, 78, 71);
23871
+ var JPEG_SIGNATURE = Uint8Array.of(255, 216, 255);
23872
+ var GIF87_SIGNATURE = new TextEncoder().encode("GIF87a");
23873
+ var GIF89_SIGNATURE = new TextEncoder().encode("GIF89a");
23874
+ var RIFF_SIGNATURE = new TextEncoder().encode("RIFF");
23875
+ var WEBP_SIGNATURE = new TextEncoder().encode("WEBP");
23876
+ var LocalRasterImage = class {
23877
+ bytes;
23878
+ mimeType;
23879
+ name;
23880
+ constructor(name, mimeType, bytes) {
23881
+ this.bytes = bytes;
23882
+ this.mimeType = mimeType;
23883
+ this.name = name;
23884
+ }
23885
+ base64 = () => Buffer.from(this.bytes).toString("base64");
23886
+ };
23887
+ function startsWith(bytes, signature, offset = 0) {
23888
+ if (bytes.byteLength < offset + signature.byteLength) {
23889
+ return false;
23890
+ }
23891
+ return signature.every((value, index) => bytes[offset + index] === value);
23892
+ }
23893
+ function sniffRasterMime(bytes) {
23894
+ if (startsWith(bytes, PNG_SIGNATURE)) {
23895
+ return "image/png";
23896
+ }
23897
+ if (startsWith(bytes, JPEG_SIGNATURE)) {
23898
+ return "image/jpeg";
23899
+ }
23900
+ if (startsWith(bytes, GIF87_SIGNATURE) || startsWith(bytes, GIF89_SIGNATURE)) {
23901
+ return "image/gif";
23902
+ }
23903
+ if (startsWith(bytes, RIFF_SIGNATURE) && startsWith(bytes, WEBP_SIGNATURE, 8)) {
23904
+ return "image/webp";
23905
+ }
23906
+ return null;
23907
+ }
23908
+ function isInsideRoot(root, target) {
23909
+ const relation = relative4(root, target);
23910
+ return relation !== ".." && !relation.startsWith(`..${sep4}`) && !isAbsolute8(relation);
23911
+ }
23912
+ async function resolveCanonicalPath(requested, signal) {
23913
+ signal.throwIfAborted();
23914
+ if (!isAbsolute8(requested) || requested.includes("\0") || normalize2(requested) !== requested) {
23915
+ return null;
23916
+ }
23917
+ try {
23918
+ const target = await realpath7(requested);
23919
+ signal.throwIfAborted();
23920
+ if (!isAbsolute8(target) || normalize2(target) !== target) {
23921
+ return null;
23922
+ }
23923
+ return target;
23924
+ } catch (cause) {
23925
+ signal.throwIfAborted();
23926
+ if (cause instanceof Error && cause.name === "AbortError") {
23927
+ throw cause;
23928
+ }
23929
+ return null;
23930
+ }
23931
+ }
23932
+ function parseLocalImageUri(uri) {
23933
+ const trimmed = uri.trim();
23934
+ if (trimmed.length === 0 || trimmed.length > 2048 || trimmed.includes("\0")) {
23935
+ return null;
23936
+ }
23937
+ if (trimmed.startsWith("data:")) {
23938
+ return null;
23939
+ }
23940
+ if (trimmed.startsWith("file:")) {
23941
+ try {
23942
+ const url2 = new URL(trimmed);
23943
+ if (url2.protocol !== "file:" || url2.host.length > 0) {
23944
+ return null;
23945
+ }
23946
+ return fileURLToPath(url2);
23947
+ } catch {
23948
+ return null;
23949
+ }
23950
+ }
23951
+ if (/^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(trimmed)) {
23952
+ return null;
23953
+ }
23954
+ return trimmed;
23955
+ }
23956
+ async function readAuthorizedRaster(uri, roots, signal) {
23957
+ signal.throwIfAborted();
23958
+ const requested = parseLocalImageUri(uri);
23959
+ if (requested === null) {
23960
+ return null;
23961
+ }
23962
+ const target = await resolveCanonicalPath(requested, signal);
23963
+ if (target === null) {
23964
+ return null;
23965
+ }
23966
+ const targetMetadata = await stat6(target);
23967
+ signal.throwIfAborted();
23968
+ if (!targetMetadata.isFile() || targetMetadata.size < 1 || targetMetadata.size > MAX_LOCAL_RASTER_BYTES) {
23969
+ return null;
23970
+ }
23971
+ const authorizedRoots = [];
23972
+ for (const root of roots) {
23973
+ const directory = await resolveCanonicalPath(root, signal);
23974
+ if (directory === null) {
23975
+ continue;
23976
+ }
23977
+ const metadata = await stat6(directory);
23978
+ signal.throwIfAborted();
23979
+ if (metadata.isDirectory()) {
23980
+ authorizedRoots.push(directory);
23981
+ }
23982
+ }
23983
+ if (!authorizedRoots.some((root) => isInsideRoot(root, target))) {
23984
+ return null;
23985
+ }
23986
+ const bytes = new Uint8Array(await readFile(target));
23987
+ signal.throwIfAborted();
23988
+ if (bytes.byteLength < 1 || bytes.byteLength > MAX_LOCAL_RASTER_BYTES) {
23989
+ return null;
23990
+ }
23991
+ const mimeType = sniffRasterMime(bytes);
23992
+ if (mimeType === null) {
23993
+ return null;
23994
+ }
23995
+ return new LocalRasterImage(basename2(target) || "Image", mimeType, bytes);
23996
+ }
23997
+
23998
+ // src/native-sessions/history-images.ts
23999
+ var IMAGE_MARKER = /\[@image\]\(([^)\r\n]*)(?:\)|$)/g;
24000
+ async function embedLocalHistoryImages(history, roots, signal) {
24001
+ if (history.status !== "available") {
24002
+ return history;
24003
+ }
24004
+ const messages = [];
24005
+ let imageCharacters = 0;
24006
+ for (const message of history.messages) {
24007
+ signal.throwIfAborted();
24008
+ const resolved = await resolveMessageImages(message, roots, imageCharacters, signal);
24009
+ imageCharacters += (resolved.images ?? []).reduce((size, image) => size + image.data.length, 0);
24010
+ messages.push(resolved);
24011
+ }
24012
+ return {
24013
+ ...history,
24014
+ messages
24015
+ };
24016
+ }
24017
+ async function resolveMessageImages(message, roots, usedCharacters, signal) {
24018
+ const images = [...message.images ?? []];
24019
+ let imageCharacters = images.reduce((size, image) => size + image.data.length, 0);
24020
+ const text = await replaceImageMarkers(message.text, async (uri) => {
24021
+ if (images.length >= 8 || usedCharacters + imageCharacters >= SESSION_HISTORY_IMAGE_CHARACTER_LIMIT) {
24022
+ return "[Image unavailable]";
24023
+ }
24024
+ const embedded = parseNativeHistoryText(`[@image](${uri})`).images[0];
24025
+ if (embedded !== void 0) {
24026
+ if (usedCharacters + imageCharacters + embedded.data.length > SESSION_HISTORY_IMAGE_CHARACTER_LIMIT) {
24027
+ return "[Image unavailable]";
24028
+ }
24029
+ images.push(embedded);
24030
+ imageCharacters += embedded.data.length;
24031
+ return "";
24032
+ }
24033
+ const local = await readAuthorizedRaster(uri, roots, signal);
24034
+ if (local === null) {
24035
+ return "[Image unavailable]";
24036
+ }
24037
+ const data = local.base64();
24038
+ if (usedCharacters + imageCharacters + data.length > SESSION_HISTORY_IMAGE_CHARACTER_LIMIT) {
24039
+ return "[Image unavailable]";
24040
+ }
24041
+ images.push({
24042
+ data,
24043
+ mimeType: local.mimeType,
24044
+ name: local.name
24045
+ });
24046
+ imageCharacters += data.length;
24047
+ return "";
24048
+ });
24049
+ return {
24050
+ ...message,
24051
+ text,
24052
+ ...images.length > 0 ? { images } : {}
24053
+ };
24054
+ }
24055
+ async function replaceImageMarkers(text, replace) {
24056
+ const matches = [...text.matchAll(IMAGE_MARKER)];
24057
+ if (matches.length === 0) {
24058
+ return text;
24059
+ }
24060
+ let cursor = 0;
24061
+ let rewritten = "";
24062
+ for (const match of matches) {
24063
+ const index = match.index ?? 0;
24064
+ rewritten += text.slice(cursor, index);
24065
+ rewritten += await replace(match[1] ?? "");
24066
+ cursor = index + match[0].length;
24067
+ }
24068
+ return `${rewritten}${text.slice(cursor)}`;
24069
+ }
24070
+
23723
24071
  // src/acp/activity.ts
23724
24072
  var TRUNCATION_MARKER = "\n\u2026 output truncated by Mobius";
23725
24073
  function isRecord8(value) {
@@ -23817,6 +24165,7 @@ function readContentOutputDetail(content) {
23817
24165
  function summarizeDisplayContent(content) {
23818
24166
  return {
23819
24167
  ...content,
24168
+ artifactId: truncate(content.artifactId, 128),
23820
24169
  data: truncate(content.data, AGENT_ACTIVITY_DETAIL_LIMIT),
23821
24170
  mimeType: truncate(content.mimeType, 255),
23822
24171
  name: truncate(content.name, 500),
@@ -23829,7 +24178,7 @@ function summarizeDisplayContent(content) {
23829
24178
  };
23830
24179
  }
23831
24180
  function contentFitsRecordingEnvelope(content) {
23832
- 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;
24181
+ 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;
23833
24182
  }
23834
24183
  function encodedByteLength(value) {
23835
24184
  return new TextEncoder().encode(JSON.stringify(value)).byteLength;
@@ -23855,6 +24204,7 @@ function recordedDetail(activity) {
23855
24204
  }
23856
24205
  function emptyDisplayContent(type) {
23857
24206
  return {
24207
+ artifactId: "",
23858
24208
  data: "",
23859
24209
  mimeType: "",
23860
24210
  name: "",
@@ -23867,6 +24217,16 @@ function emptyDisplayContent(type) {
23867
24217
  uri: ""
23868
24218
  };
23869
24219
  }
24220
+ function imageDisplayContent(mimeType, name, data, artifactId = "", uri = "") {
24221
+ return {
24222
+ ...emptyDisplayContent("image"),
24223
+ artifactId,
24224
+ data,
24225
+ mimeType,
24226
+ name,
24227
+ uri
24228
+ };
24229
+ }
23870
24230
  function normalizeContentBlock(content) {
23871
24231
  if (content.type === "text") {
23872
24232
  return { ...emptyDisplayContent("text"), text: content.text };
@@ -24658,7 +25018,6 @@ var AcpHistoryReplay = class {
24658
25018
  #messages = [];
24659
25019
  #lastMessageId = null;
24660
25020
  #characters = 0;
24661
- #imageCharacters = 0;
24662
25021
  #truncated = false;
24663
25022
  record = (update) => {
24664
25023
  if (update.sessionUpdate !== "user_message_chunk" && update.sessionUpdate !== "agent_message_chunk") {
@@ -24669,40 +25028,30 @@ var AcpHistoryReplay = class {
24669
25028
  }
24670
25029
  const role = update.sessionUpdate === "user_message_chunk" ? "user" : "assistant";
24671
25030
  const content = update.content;
24672
- const parsed = parseNativeHistoryText(
24673
- content.type === "text" ? content.text : content.type === "image" ? `[@image](data:${content.mimeType};base64,${content.data})` : `[${content.type} attachment]`
24674
- );
24675
- const text = parsed.text;
24676
- if (text.length === 0 && parsed.images.length === 0) {
25031
+ 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]`;
25032
+ if (text.length === 0) {
24677
25033
  return;
24678
25034
  }
24679
25035
  const previous = this.#messages.at(-1);
24680
25036
  const id = update.messageId ?? null;
24681
25037
  const continuation = previous?.role === role && id === this.#lastMessageId;
24682
25038
  const combined = continuation ? `${previous.text}${text}` : text;
24683
- const allImages = continuation ? [...previous.images ?? [], ...parsed.images] : parsed.images;
24684
- const images = allImages.slice(0, 8);
24685
- this.#truncated ||= images.length < allImages.length;
24686
25039
  if (continuation) {
24687
25040
  this.#messages.pop();
24688
25041
  this.#characters -= previous.text.length;
24689
- this.#imageCharacters -= (previous.images ?? []).reduce((size, image) => size + image.data.length, 0);
24690
25042
  }
24691
25043
  const bounded = combined.slice(-SESSION_HISTORY_CHARACTER_LIMIT);
24692
25044
  this.#truncated ||= bounded.length < combined.length;
24693
25045
  this.#messages.push({
24694
25046
  role,
24695
- text: bounded,
24696
- ...images.length > 0 ? { images } : {}
25047
+ text: bounded
24697
25048
  });
24698
25049
  this.#characters += bounded.length;
24699
- this.#imageCharacters += images.reduce((size, image) => size + image.data.length, 0);
24700
25050
  this.#lastMessageId = id;
24701
- while (this.#messages.length > SESSION_HISTORY_PREVIEW_MESSAGE_LIMIT || this.#characters > SESSION_HISTORY_CHARACTER_LIMIT || this.#imageCharacters > SESSION_HISTORY_IMAGE_CHARACTER_LIMIT) {
25051
+ while (this.#messages.length > SESSION_HISTORY_PREVIEW_MESSAGE_LIMIT || this.#characters > SESSION_HISTORY_CHARACTER_LIMIT) {
24702
25052
  const removed = this.#messages.shift();
24703
25053
  if (removed !== void 0) {
24704
25054
  this.#characters -= removed.text.length;
24705
- this.#imageCharacters -= (removed.images ?? []).reduce((size, image) => size + image.data.length, 0);
24706
25055
  }
24707
25056
  this.#truncated = true;
24708
25057
  }
@@ -24925,6 +25274,10 @@ var MAX_PRE_SESSION_UPDATES = 100;
24925
25274
  var MAX_PRE_SESSION_UPDATE_BYTES = 1024 * 1024;
24926
25275
  var SESSION_CONTROL_COMMAND_ID = "session-control";
24927
25276
  var NullAcpSessionObserver = class {
25277
+ importLocalImage = (_sessionId, _image, signal) => {
25278
+ signal.throwIfAborted();
25279
+ return Promise.resolve("");
25280
+ };
24928
25281
  onCommands = () => Promise.resolve();
24929
25282
  onConfig = () => Promise.resolve();
24930
25283
  onContent = () => Promise.resolve();
@@ -25547,11 +25900,75 @@ var AcpProcessSession = class _AcpProcessSession {
25547
25900
  );
25548
25901
  await this.#updateTail;
25549
25902
  signal.throwIfAborted();
25550
- return history.snapshot();
25903
+ return await embedLocalHistoryImages(
25904
+ history.snapshot(),
25905
+ [this.#cwd, ...this.#additionalDirectories],
25906
+ signal
25907
+ );
25551
25908
  } finally {
25552
25909
  this.#replay = { kind: "idle" };
25553
25910
  }
25554
25911
  };
25912
+ imageRoots = () => [this.#cwd, ...this.#additionalDirectories];
25913
+ emitAgentText = async (text, messageId) => {
25914
+ const signal = AbortSignal.timeout(2e4);
25915
+ const parts = text.split(/(\[@image\]\([^)\r\n]*(?:\)|$))/);
25916
+ let leftover = "";
25917
+ for (const part of parts) {
25918
+ const marker = /^\[@image\]\(([^)\r\n]*)(?:\)|$)/.exec(part);
25919
+ if (marker === null) {
25920
+ leftover += part;
25921
+ continue;
25922
+ }
25923
+ if (leftover.length > 0) {
25924
+ await this.#turn.onText(leftover, messageId);
25925
+ leftover = "";
25926
+ }
25927
+ const raster = await readAuthorizedRaster(marker[1] ?? "", this.imageRoots(), signal);
25928
+ if (raster === null) {
25929
+ leftover += "[Image unavailable]";
25930
+ continue;
25931
+ }
25932
+ await this.emitRaster(raster, messageId, signal);
25933
+ }
25934
+ if (leftover.length > 0) {
25935
+ await this.#turn.onText(leftover, messageId);
25936
+ }
25937
+ };
25938
+ emitAgentContent = async (content, messageId) => {
25939
+ if (content.type === "image" && content.data.length === 0 && content.uri.length > 0) {
25940
+ const signal = AbortSignal.timeout(2e4);
25941
+ const raster = await readAuthorizedRaster(content.uri, this.imageRoots(), signal);
25942
+ if (raster !== null) {
25943
+ await this.emitRaster(raster, messageId, signal);
25944
+ return;
25945
+ }
25946
+ }
25947
+ await this.#getObserver().onContent({
25948
+ commandId: this.#turn.commandId,
25949
+ content,
25950
+ contentId: `content-${crypto.randomUUID()}`,
25951
+ kind: AGENT_CONTENT_KIND,
25952
+ messageId,
25953
+ sessionId: this.#mobiusSessionId
25954
+ });
25955
+ };
25956
+ emitRaster = async (raster, messageId, signal) => {
25957
+ const artifactId = await this.#getObserver().importLocalImage(this.#mobiusSessionId, raster, signal);
25958
+ await this.#getObserver().onContent({
25959
+ commandId: this.#turn.commandId,
25960
+ content: imageDisplayContent(
25961
+ raster.mimeType,
25962
+ raster.name,
25963
+ artifactId.length > 0 ? "" : raster.base64(),
25964
+ artifactId
25965
+ ),
25966
+ contentId: `content-${crypto.randomUUID()}`,
25967
+ kind: AGENT_CONTENT_KIND,
25968
+ messageId,
25969
+ sessionId: this.#mobiusSessionId
25970
+ });
25971
+ };
25555
25972
  async #initializeAgent(signal) {
25556
25973
  const initialized = await this.race(
25557
25974
  this.#connection.agent.request(
@@ -26254,18 +26671,14 @@ var AcpProcessSession = class _AcpProcessSession {
26254
26671
  );
26255
26672
  } else {
26256
26673
  await this.#turn.activities.finishNarrative();
26257
- await this.#turn.onText(update.content.text, truncate3(update.messageId ?? "", 255));
26674
+ await this.emitAgentText(update.content.text, truncate3(update.messageId ?? "", 255));
26258
26675
  }
26259
26676
  } else {
26260
26677
  await this.#turn.activities.finishNarrative();
26261
- await this.#getObserver().onContent({
26262
- commandId: this.#turn.commandId,
26263
- content: normalizeContentBlock(update.content),
26264
- contentId: `content-${crypto.randomUUID()}`,
26265
- kind: AGENT_CONTENT_KIND,
26266
- messageId: truncate3(update.messageId ?? "", 255),
26267
- sessionId: this.#mobiusSessionId
26268
- });
26678
+ await this.emitAgentContent(
26679
+ normalizeContentBlock(update.content),
26680
+ truncate3(update.messageId ?? "", 255)
26681
+ );
26269
26682
  }
26270
26683
  return;
26271
26684
  }
@@ -27626,6 +28039,402 @@ var FixedInstallationExecutor = class {
27626
28039
  };
27627
28040
  };
27628
28041
 
28042
+ // src/artifacts/runtime-artifact-uploader.ts
28043
+ import { createHash as createHash2 } from "node:crypto";
28044
+
28045
+ // ../mobius-sdk/src/errors.ts
28046
+ var MobiusError = class extends Error {
28047
+ code;
28048
+ constructor(code, message, options = {}) {
28049
+ super(message, options);
28050
+ this.code = code;
28051
+ this.name = "MobiusError";
28052
+ }
28053
+ };
28054
+ var MobiusProtocolError = class extends MobiusError {
28055
+ constructor(message, options = {}) {
28056
+ super("invalid_service_response", message, options);
28057
+ this.name = "MobiusProtocolError";
28058
+ }
28059
+ };
28060
+ var MobiusValidationError = class extends MobiusError {
28061
+ constructor(message, options = {}) {
28062
+ super("invalid_request", message, options);
28063
+ this.name = "MobiusValidationError";
28064
+ }
28065
+ };
28066
+
28067
+ // ../mobius-sdk/src/resources.ts
28068
+ var IDENTIFIER_PATTERN6 = /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/;
28069
+ function invalidResponse(message) {
28070
+ return new MobiusProtocolError(message);
28071
+ }
28072
+ function isRecord11(value) {
28073
+ return typeof value === "object" && value !== null && !Array.isArray(value);
28074
+ }
28075
+ function record2(value, name) {
28076
+ if (!isRecord11(value)) {
28077
+ throw invalidResponse(`The service returned an invalid ${name}`);
28078
+ }
28079
+ return value;
28080
+ }
28081
+ function stringField(value, field, maximumLength = 85e5) {
28082
+ const candidate = value[field];
28083
+ if (typeof candidate !== "string" || candidate.length > maximumLength) {
28084
+ throw invalidResponse(`The service returned an invalid ${field}`);
28085
+ }
28086
+ return candidate;
28087
+ }
28088
+ function identifierField(value, field) {
28089
+ const candidate = stringField(value, field, 128);
28090
+ if (!IDENTIFIER_PATTERN6.test(candidate)) {
28091
+ throw invalidResponse(`The service returned an invalid ${field}`);
28092
+ }
28093
+ return candidate;
28094
+ }
28095
+ function integerField(value, field) {
28096
+ const candidate = value[field];
28097
+ if (typeof candidate !== "number" || !Number.isSafeInteger(candidate) || candidate < 0) {
28098
+ throw invalidResponse(`The service returned an invalid ${field}`);
28099
+ }
28100
+ return candidate;
28101
+ }
28102
+ function validateTimestamp(value, field) {
28103
+ if (Number.isNaN(Date.parse(value))) {
28104
+ throw invalidResponse(`The service returned an invalid ${field}`);
28105
+ }
28106
+ return value;
28107
+ }
28108
+ var MobiusArtifactUploadRequest = class {
28109
+ byteLength;
28110
+ mediaType;
28111
+ name;
28112
+ sha256;
28113
+ constructor(name, mediaType, byteLength, sha256) {
28114
+ 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)) {
28115
+ throw new MobiusValidationError("The artifact upload request is invalid");
28116
+ }
28117
+ this.byteLength = byteLength;
28118
+ this.mediaType = mediaType;
28119
+ this.name = name;
28120
+ this.sha256 = sha256;
28121
+ }
28122
+ };
28123
+ var MobiusArtifact = class {
28124
+ artifactId;
28125
+ byteLength;
28126
+ createdAt;
28127
+ mediaType;
28128
+ name;
28129
+ sessionId;
28130
+ sha256;
28131
+ constructor(sessionId, artifactId, name, mediaType, byteLength, sha256, createdAt) {
28132
+ this.artifactId = artifactId;
28133
+ this.byteLength = byteLength;
28134
+ this.createdAt = createdAt;
28135
+ this.mediaType = mediaType;
28136
+ this.name = name;
28137
+ this.sessionId = sessionId;
28138
+ this.sha256 = sha256;
28139
+ }
28140
+ };
28141
+ var MobiusUploadingArtifact = class extends MobiusArtifact {
28142
+ expiresAt;
28143
+ state = "uploading";
28144
+ constructor(sessionId, artifactId, name, mediaType, byteLength, sha256, createdAt, expiresAt) {
28145
+ super(sessionId, artifactId, name, mediaType, byteLength, sha256, createdAt);
28146
+ this.expiresAt = expiresAt;
28147
+ }
28148
+ };
28149
+ var MobiusArtifactUpload = class extends MobiusUploadingArtifact {
28150
+ uploadToken;
28151
+ constructor(artifact, uploadToken) {
28152
+ super(
28153
+ artifact.sessionId,
28154
+ artifact.artifactId,
28155
+ artifact.name,
28156
+ artifact.mediaType,
28157
+ artifact.byteLength,
28158
+ artifact.sha256,
28159
+ artifact.createdAt,
28160
+ artifact.expiresAt
28161
+ );
28162
+ this.uploadToken = uploadToken;
28163
+ }
28164
+ };
28165
+ var MobiusAvailableArtifact = class extends MobiusArtifact {
28166
+ availableAt;
28167
+ state = "available";
28168
+ constructor(sessionId, artifactId, name, mediaType, byteLength, sha256, createdAt, availableAt) {
28169
+ super(sessionId, artifactId, name, mediaType, byteLength, sha256, createdAt);
28170
+ this.availableAt = availableAt;
28171
+ }
28172
+ };
28173
+ var MobiusExpiredArtifact = class extends MobiusArtifact {
28174
+ expiredAt;
28175
+ state = "expired";
28176
+ constructor(sessionId, artifactId, name, mediaType, byteLength, sha256, createdAt, expiredAt) {
28177
+ super(sessionId, artifactId, name, mediaType, byteLength, sha256, createdAt);
28178
+ this.expiredAt = expiredAt;
28179
+ }
28180
+ };
28181
+ function artifactFields(value) {
28182
+ const sha256 = stringField(value, "sha256", 64);
28183
+ if (!/^[a-f0-9]{64}$/.test(sha256)) {
28184
+ throw invalidResponse("The service returned an invalid artifact digest");
28185
+ }
28186
+ return {
28187
+ artifactId: identifierField(value, "artifactId"),
28188
+ byteLength: integerField(value, "byteLength"),
28189
+ createdAt: validateTimestamp(stringField(value, "createdAt", 128), "createdAt"),
28190
+ mediaType: stringField(value, "mediaType", 255),
28191
+ name: stringField(value, "name", 500),
28192
+ sessionId: identifierField(value, "sessionId"),
28193
+ sha256
28194
+ };
28195
+ }
28196
+ function uploadingArtifact(value) {
28197
+ const fields = artifactFields(value);
28198
+ return new MobiusUploadingArtifact(
28199
+ fields.sessionId,
28200
+ fields.artifactId,
28201
+ fields.name,
28202
+ fields.mediaType,
28203
+ fields.byteLength,
28204
+ fields.sha256,
28205
+ fields.createdAt,
28206
+ validateTimestamp(stringField(value, "expiresAt", 128), "expiresAt")
28207
+ );
28208
+ }
28209
+ function decodeMobiusArtifactUpload(value) {
28210
+ const artifact = record2(value, "artifact upload authorization");
28211
+ return new MobiusArtifactUpload(uploadingArtifact(artifact), stringField(artifact, "uploadToken", 256));
28212
+ }
28213
+ function decodeMobiusArtifact(value) {
28214
+ const artifact = record2(value, "artifact");
28215
+ const state = stringField(artifact, "state", 32);
28216
+ if (state === "uploading") {
28217
+ return uploadingArtifact(artifact);
28218
+ }
28219
+ const fields = artifactFields(artifact);
28220
+ if (state === "available") {
28221
+ return new MobiusAvailableArtifact(
28222
+ fields.sessionId,
28223
+ fields.artifactId,
28224
+ fields.name,
28225
+ fields.mediaType,
28226
+ fields.byteLength,
28227
+ fields.sha256,
28228
+ fields.createdAt,
28229
+ validateTimestamp(stringField(artifact, "availableAt", 128), "availableAt")
28230
+ );
28231
+ }
28232
+ if (state === "expired") {
28233
+ return new MobiusExpiredArtifact(
28234
+ fields.sessionId,
28235
+ fields.artifactId,
28236
+ fields.name,
28237
+ fields.mediaType,
28238
+ fields.byteLength,
28239
+ fields.sha256,
28240
+ fields.createdAt,
28241
+ validateTimestamp(stringField(artifact, "expiredAt", 128), "expiredAt")
28242
+ );
28243
+ }
28244
+ throw invalidResponse("The service returned an invalid artifact state");
28245
+ }
28246
+ function decodeMobiusAvailableArtifact(value) {
28247
+ const artifact = decodeMobiusArtifact(value);
28248
+ if (!(artifact instanceof MobiusAvailableArtifact)) {
28249
+ throw invalidResponse("The service did not make the artifact available");
28250
+ }
28251
+ return artifact;
28252
+ }
28253
+ var MobiusRuntimePairingLifecycle = Object.freeze({
28254
+ Expired: "expired",
28255
+ Paired: "paired",
28256
+ Pending: "pending",
28257
+ Revoked: "revoked"
28258
+ });
28259
+
28260
+ // src/artifacts/runtime-artifact-uploader.ts
28261
+ import { fetch as fetch4 } from "undici";
28262
+ var UPLOAD_TIMEOUT_MILLISECONDS = 2e4;
28263
+ var RuntimeArtifactUploadError = class extends Error {
28264
+ code;
28265
+ constructor(code, message, options = {}) {
28266
+ super(message, options);
28267
+ this.code = code;
28268
+ this.name = "RuntimeArtifactUploadError";
28269
+ }
28270
+ };
28271
+ var UploadedRuntimeArtifact = class {
28272
+ artifactId;
28273
+ byteLength;
28274
+ mimeType;
28275
+ name;
28276
+ sha256;
28277
+ constructor(artifactId, name, mimeType, byteLength, sha256) {
28278
+ this.artifactId = artifactId;
28279
+ this.byteLength = byteLength;
28280
+ this.mimeType = mimeType;
28281
+ this.name = name;
28282
+ this.sha256 = sha256;
28283
+ }
28284
+ };
28285
+ function daemonToken(config2) {
28286
+ const token = config2.relayUrl.searchParams.get("token");
28287
+ if (token === null || token.length < 32) {
28288
+ throw new RuntimeArtifactUploadError("artifact_endpoint_invalid", "The Relay daemon token is missing");
28289
+ }
28290
+ return token;
28291
+ }
28292
+ function channelOrigin(config2) {
28293
+ const url2 = new URL(config2.relayUrl);
28294
+ url2.protocol = url2.protocol === "wss:" ? "https:" : "http:";
28295
+ let channelPath = "";
28296
+ if (url2.pathname.endsWith("/daemon")) {
28297
+ channelPath = url2.pathname.slice(0, -"/daemon".length);
28298
+ } else {
28299
+ const runtimePath = `${MOBIUS_API_PREFIX}/v1/runtimes/connect`;
28300
+ if (!url2.pathname.endsWith("/v1/runtimes/connect") && !url2.pathname.endsWith(runtimePath)) {
28301
+ throw new RuntimeArtifactUploadError("artifact_endpoint_invalid", "The Relay artifact endpoint is invalid");
28302
+ }
28303
+ channelPath = `${url2.pathname.replace(/\/v1\/runtimes\/connect$/, "")}/channels/${encodeURIComponent(config2.channelId)}`;
28304
+ }
28305
+ url2.pathname = channelPath;
28306
+ url2.search = "";
28307
+ url2.hash = "";
28308
+ return url2;
28309
+ }
28310
+ function uploadError(code, message, cause) {
28311
+ return new RuntimeArtifactUploadError(code, message, cause === void 0 ? {} : { cause });
28312
+ }
28313
+ function translateSdkError(cause) {
28314
+ if (cause instanceof MobiusValidationError) {
28315
+ throw uploadError("artifact_upload_failed", cause.message, cause);
28316
+ }
28317
+ if (cause instanceof MobiusProtocolError) {
28318
+ throw uploadError("artifact_upload_failed", "The Relay returned an invalid upload response", cause);
28319
+ }
28320
+ throw cause;
28321
+ }
28322
+ async function readJson(response) {
28323
+ try {
28324
+ return await response.json();
28325
+ } catch (cause) {
28326
+ throw uploadError("artifact_upload_failed", "The Relay returned an invalid upload response", cause);
28327
+ }
28328
+ }
28329
+ async function readAuthorization(response) {
28330
+ try {
28331
+ return decodeMobiusArtifactUpload(await readJson(response));
28332
+ } catch (cause) {
28333
+ translateSdkError(cause);
28334
+ }
28335
+ }
28336
+ function sessionArtifactUrl(origin, sessionId, resourcePath, token) {
28337
+ const url2 = new URL(`${origin.pathname}/sessions/${encodeURIComponent(sessionId)}/${resourcePath}`, origin);
28338
+ url2.searchParams.set("token", token);
28339
+ return url2;
28340
+ }
28341
+ async function postLease(url2, request, signal) {
28342
+ return await fetch4(url2, {
28343
+ dispatcher: environmentProxyDispatcher,
28344
+ headers: { "content-type": "application/json" },
28345
+ method: "POST",
28346
+ body: JSON.stringify(request),
28347
+ signal
28348
+ });
28349
+ }
28350
+ async function putContent(url2, authorization, bytes, signal) {
28351
+ return await fetch4(url2, {
28352
+ dispatcher: environmentProxyDispatcher,
28353
+ headers: {
28354
+ "content-type": authorization.mediaType,
28355
+ "x-mobius-upload-token": authorization.uploadToken
28356
+ },
28357
+ method: "PUT",
28358
+ body: bytes,
28359
+ signal
28360
+ });
28361
+ }
28362
+ async function uploadRuntimeArtifact(config2, sessionId, image, signal) {
28363
+ signal.throwIfAborted();
28364
+ let request;
28365
+ try {
28366
+ request = new MobiusArtifactUploadRequest(
28367
+ image.name,
28368
+ image.mimeType,
28369
+ image.bytes.byteLength,
28370
+ createHash2("sha256").update(image.bytes).digest("hex")
28371
+ );
28372
+ } catch (cause) {
28373
+ translateSdkError(cause);
28374
+ }
28375
+ const timeoutSignal = AbortSignal.timeout(UPLOAD_TIMEOUT_MILLISECONDS);
28376
+ const requestSignal = AbortSignal.any([signal, timeoutSignal]);
28377
+ const origin = channelOrigin(config2);
28378
+ const token = daemonToken(config2);
28379
+ let created;
28380
+ try {
28381
+ created = await postLease(
28382
+ sessionArtifactUrl(origin, sessionId, "artifacts/uploads", token),
28383
+ request,
28384
+ requestSignal
28385
+ );
28386
+ } catch (cause) {
28387
+ signal.throwIfAborted();
28388
+ throw uploadError(
28389
+ timeoutSignal.aborted ? "artifact_upload_timeout" : "artifact_upload_failed",
28390
+ timeoutSignal.aborted ? "The artifact upload authorization timed out" : "The artifact upload could not start",
28391
+ cause
28392
+ );
28393
+ }
28394
+ if (!created.ok) {
28395
+ await created.body?.cancel();
28396
+ throw uploadError("artifact_upload_rejected", "The Relay rejected the artifact upload");
28397
+ }
28398
+ const authorization = await readAuthorization(created);
28399
+ let uploaded;
28400
+ try {
28401
+ uploaded = await putContent(
28402
+ sessionArtifactUrl(
28403
+ origin,
28404
+ sessionId,
28405
+ `artifacts/${encodeURIComponent(authorization.artifactId)}/content`,
28406
+ token
28407
+ ),
28408
+ authorization,
28409
+ image.bytes,
28410
+ requestSignal
28411
+ );
28412
+ } catch (cause) {
28413
+ signal.throwIfAborted();
28414
+ throw uploadError(
28415
+ timeoutSignal.aborted ? "artifact_upload_timeout" : "artifact_upload_failed",
28416
+ timeoutSignal.aborted ? "The artifact upload timed out" : "The artifact content could not be uploaded",
28417
+ cause
28418
+ );
28419
+ }
28420
+ if (!uploaded.ok) {
28421
+ await uploaded.body?.cancel();
28422
+ throw uploadError("artifact_upload_rejected", "The Relay rejected the artifact content");
28423
+ }
28424
+ try {
28425
+ const available = decodeMobiusAvailableArtifact(await readJson(uploaded));
28426
+ return new UploadedRuntimeArtifact(
28427
+ available.artifactId,
28428
+ available.name,
28429
+ available.mediaType,
28430
+ available.byteLength,
28431
+ available.sha256
28432
+ );
28433
+ } catch (cause) {
28434
+ translateSdkError(cause);
28435
+ }
28436
+ }
28437
+
27629
28438
  // src/authorization/local-authorization-error.ts
27630
28439
  var LocalAuthorizationError = class extends Error {
27631
28440
  code = "local_authorization_failed";
@@ -27636,9 +28445,9 @@ var LocalAuthorizationError = class extends Error {
27636
28445
  };
27637
28446
 
27638
28447
  // src/authorization/workspace-directory.ts
27639
- import { readdir, realpath as realpath7, stat as stat6 } from "node:fs/promises";
28448
+ import { readdir, realpath as realpath8, stat as stat7 } from "node:fs/promises";
27640
28449
  import { homedir as homedir2 } from "node:os";
27641
- import { basename as basename2, dirname as dirname5, isAbsolute as isAbsolute7, join as join15, normalize as normalize2, relative as relative4 } from "node:path";
28450
+ import { basename as basename3, dirname as dirname5, isAbsolute as isAbsolute9, join as join16, normalize as normalize3, relative as relative5 } from "node:path";
27642
28451
  var WorkspaceDirectoryListing = class {
27643
28452
  directoryId;
27644
28453
  directoryLabel;
@@ -27664,7 +28473,7 @@ function decodePath(value, prefix) {
27664
28473
  throw new LocalAuthorizationError("The directory identifier is invalid");
27665
28474
  }
27666
28475
  const decoded = Buffer.from(encoded, "base64url").toString("utf8");
27667
- if (Buffer.from(decoded, "utf8").toString("base64url") !== encoded || decoded.includes("\0") || normalize2(decoded) !== decoded) {
28476
+ if (Buffer.from(decoded, "utf8").toString("base64url") !== encoded || decoded.includes("\0") || normalize3(decoded) !== decoded) {
27668
28477
  throw new LocalAuthorizationError("The directory identifier is invalid");
27669
28478
  }
27670
28479
  return decoded;
@@ -27690,7 +28499,7 @@ var WorkspaceDirectoryService = class {
27690
28499
  }
27691
28500
  if (id.startsWith("path-")) {
27692
28501
  const path2 = decodePath(id, "path-");
27693
- if (isAbsolute7(path2)) {
28502
+ if (isAbsolute9(path2)) {
27694
28503
  return path2;
27695
28504
  }
27696
28505
  }
@@ -27698,15 +28507,15 @@ var WorkspaceDirectoryService = class {
27698
28507
  };
27699
28508
  resolvePath = async (requested, signal) => {
27700
28509
  signal.throwIfAborted();
27701
- if (!isAbsolute7(requested) || requested.includes("\0") || normalize2(requested) !== requested) {
28510
+ if (!isAbsolute9(requested) || requested.includes("\0") || normalize3(requested) !== requested) {
27702
28511
  throw new LocalAuthorizationError("The local directory path is invalid");
27703
28512
  }
27704
28513
  try {
27705
- const target = await realpath7(requested);
28514
+ const target = await realpath8(requested);
27706
28515
  signal.throwIfAborted();
27707
- const metadata = await stat6(target);
28516
+ const metadata = await stat7(target);
27708
28517
  signal.throwIfAborted();
27709
- if (!isAbsolute7(target) || normalize2(target) !== target || !metadata.isDirectory()) {
28518
+ if (!isAbsolute9(target) || normalize3(target) !== target || !metadata.isDirectory()) {
27710
28519
  throw new LocalAuthorizationError("The selected location is not a directory");
27711
28520
  }
27712
28521
  return target;
@@ -27721,8 +28530,8 @@ var WorkspaceDirectoryService = class {
27721
28530
  }
27722
28531
  };
27723
28532
  label = (path2) => {
27724
- const suffix = relative4(homedir2(), path2);
27725
- return suffix === "" ? "~" : !isAbsolute7(suffix) && suffix !== ".." && !suffix.startsWith(`..${process.platform === "win32" ? "\\" : "/"}`) ? `~/${suffix.replaceAll("\\", "/")}` : path2;
28533
+ const suffix = relative5(homedir2(), path2);
28534
+ return suffix === "" ? "~" : !isAbsolute9(suffix) && suffix !== ".." && !suffix.startsWith(`..${process.platform === "win32" ? "\\" : "/"}`) ? `~/${suffix.replaceAll("\\", "/")}` : path2;
27726
28535
  };
27727
28536
  identify = async (bindingId, requestedPath, signal) => {
27728
28537
  this.authorizeMachine(bindingId);
@@ -27730,7 +28539,7 @@ var WorkspaceDirectoryService = class {
27730
28539
  return {
27731
28540
  path: path2,
27732
28541
  directoryId: encodePath(path2),
27733
- name: basename2(path2) || path2,
28542
+ name: basename3(path2) || path2,
27734
28543
  label: this.label(path2)
27735
28544
  };
27736
28545
  };
@@ -27752,7 +28561,7 @@ var WorkspaceDirectoryService = class {
27752
28561
  continue;
27753
28562
  }
27754
28563
  try {
27755
- const path2 = await this.resolvePath(join15(target, child.name), signal);
28564
+ const path2 = await this.resolvePath(join16(target, child.name), signal);
27756
28565
  entries.push({ directoryId: encodePath(path2), name: child.name });
27757
28566
  } catch (cause) {
27758
28567
  signal.throwIfAborted();
@@ -27787,8 +28596,8 @@ var WorkspaceDirectoryService = class {
27787
28596
  };
27788
28597
 
27789
28598
  // src/bots/local-bot-grant-store.ts
27790
- import { createHash as createHash2, randomUUID as randomUUID3 } from "node:crypto";
27791
- import { stat as stat7 } from "node:fs/promises";
28599
+ import { createHash as createHash3, randomUUID as randomUUID3 } from "node:crypto";
28600
+ import { stat as stat8 } from "node:fs/promises";
27792
28601
  import { DatabaseSync as DatabaseSync3 } from "node:sqlite";
27793
28602
  var LOCAL_BOT_GRANT_LIFETIME_MILLISECONDS = 90 * 24 * 60 * 60 * 1e3;
27794
28603
  var LocalBotAuthorizationError = class extends Error {
@@ -27832,7 +28641,7 @@ var LocalBotGrant = class {
27832
28641
  }
27833
28642
  };
27834
28643
  function digest(value) {
27835
- return createHash2("sha256").update(value, "utf8").digest("hex");
28644
+ return createHash3("sha256").update(value, "utf8").digest("hex");
27836
28645
  }
27837
28646
  function agentDigest(agent) {
27838
28647
  return digest(
@@ -27846,7 +28655,7 @@ function agentDigest(agent) {
27846
28655
  );
27847
28656
  }
27848
28657
  async function workspaceDigest(path2) {
27849
- const metadata = await stat7(path2);
28658
+ const metadata = await stat8(path2);
27850
28659
  if (!metadata.isDirectory()) {
27851
28660
  throw new LocalBotAuthorizationError("binding_incompatible", "The Bot workspace is not a directory");
27852
28661
  }
@@ -28263,12 +29072,12 @@ var BotExecutionContextRegistry = class {
28263
29072
  // src/bots/bot-outbound-ipc.ts
28264
29073
  import { chmod as chmod2, mkdir as mkdir4, unlink } from "node:fs/promises";
28265
29074
  import { createServer } from "node:net";
28266
- import { dirname as dirname6, isAbsolute as isAbsolute8 } from "node:path";
28267
- import { fetch as fetch4 } from "undici";
29075
+ import { dirname as dirname6, isAbsolute as isAbsolute10 } from "node:path";
29076
+ import { fetch as fetch5 } from "undici";
28268
29077
  var BOT_IPC_REQUEST_LIMIT = 32 * 1024;
28269
29078
  var BOT_IPC_TIMEOUT_MILLISECONDS2 = 2e4;
28270
29079
  var BOT_RELAY_TIMEOUT_MILLISECONDS = 2e4;
28271
- var IDENTIFIER_PATTERN6 = /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/;
29080
+ var IDENTIFIER_PATTERN7 = /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/;
28272
29081
  var WINDOWS_NAMED_PIPE_PREFIX = "\\\\.\\pipe\\";
28273
29082
  var BotOutboundIpcRequest = class {
28274
29083
  contextHandle;
@@ -28282,7 +29091,7 @@ var BotOutboundIpcRequest = class {
28282
29091
  this.text = text;
28283
29092
  }
28284
29093
  };
28285
- function isRecord11(value) {
29094
+ function isRecord12(value) {
28286
29095
  return typeof value === "object" && value !== null && !Array.isArray(value);
28287
29096
  }
28288
29097
  function decodeRequest(encoded) {
@@ -28292,7 +29101,7 @@ function decodeRequest(encoded) {
28292
29101
  } catch (cause) {
28293
29102
  throw new LocalBotAuthorizationError("invalid_request", "The local Bot request is invalid", { cause });
28294
29103
  }
28295
- if (!isRecord11(value)) {
29104
+ if (!isRecord12(value)) {
28296
29105
  throw new LocalBotAuthorizationError("invalid_request", "The local Bot request is invalid");
28297
29106
  }
28298
29107
  const keys = Object.keys(value);
@@ -28303,7 +29112,7 @@ function decodeRequest(encoded) {
28303
29112
  const idempotencyKey = value["idempotencyKey"];
28304
29113
  const target = value["target"];
28305
29114
  const text = value["text"];
28306
- 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) {
29115
+ if (typeof contextHandle !== "string" || !/^ctx_[a-zA-Z0-9_-]{43}$/.test(contextHandle) || typeof idempotencyKey !== "string" || !IDENTIFIER_PATTERN7.test(idempotencyKey) || typeof target !== "string" || !IDENTIFIER_PATTERN7.test(target) || typeof text !== "string" || text.trim().length === 0 || text.length > 1e4) {
28307
29116
  throw new LocalBotAuthorizationError("invalid_request", "The local Bot request is invalid");
28308
29117
  }
28309
29118
  return new BotOutboundIpcRequest(contextHandle, idempotencyKey, target, text);
@@ -28325,7 +29134,7 @@ function relayEndpoint(relayUrl, context, target) {
28325
29134
  endpoint.pathname = `${MOBIUS_API_PREFIX}/v1/bot-executions/${execution}/delivery-targets/${encodeURIComponent(deliveryTargetId)}/messages`;
28326
29135
  return endpoint;
28327
29136
  }
28328
- function daemonToken(relayUrl) {
29137
+ function daemonToken2(relayUrl) {
28329
29138
  const token = relayUrl.searchParams.get("token") ?? "";
28330
29139
  if (!/^[a-zA-Z0-9_-]{32,256}$/.test(token)) {
28331
29140
  throw new LocalBotAuthorizationError("bot_service_unavailable", "The Runtime credential is unavailable");
@@ -28342,10 +29151,10 @@ async function decodeRelayResponse(response) {
28342
29151
  cause
28343
29152
  });
28344
29153
  }
28345
- if (response.status === 202 && isRecord11(value) && typeof value["outboundMessageId"] === "string") {
29154
+ if (response.status === 202 && isRecord12(value) && typeof value["outboundMessageId"] === "string") {
28346
29155
  return value["outboundMessageId"];
28347
29156
  }
28348
- if (isRecord11(value) && isRecord11(value["error"])) {
29157
+ if (isRecord12(value) && isRecord12(value["error"])) {
28349
29158
  const error61 = value["error"];
28350
29159
  if (typeof error61["code"] === "string" && typeof error61["message"] === "string") {
28351
29160
  throw new LocalBotAuthorizationError(error61["code"], error61["message"]);
@@ -28361,7 +29170,7 @@ var BotOutboundIpcServer = class {
28361
29170
  #usesFilesystemSocket;
28362
29171
  constructor(socketPath, relayUrl, registry2) {
28363
29172
  const usesFilesystemSocket = !socketPath.startsWith(WINDOWS_NAMED_PIPE_PREFIX);
28364
- if (usesFilesystemSocket && !isAbsolute8(socketPath)) {
29173
+ if (usesFilesystemSocket && !isAbsolute10(socketPath)) {
28365
29174
  throw new Error("The Bot IPC path must be absolute");
28366
29175
  }
28367
29176
  this.#registry = registry2;
@@ -28378,7 +29187,7 @@ var BotOutboundIpcServer = class {
28378
29187
  if (this.#usesFilesystemSocket) {
28379
29188
  await mkdir4(dirname6(this.#socketPath), { mode: 448, recursive: true });
28380
29189
  await unlink(this.#socketPath).catch((error61) => {
28381
- if (!isRecord11(error61) || error61["code"] !== "ENOENT") {
29190
+ if (!isRecord12(error61) || error61["code"] !== "ENOENT") {
28382
29191
  throw error61;
28383
29192
  }
28384
29193
  });
@@ -28413,7 +29222,7 @@ var BotOutboundIpcServer = class {
28413
29222
  }
28414
29223
  if (this.#usesFilesystemSocket) {
28415
29224
  await unlink(this.#socketPath).catch((error61) => {
28416
- if (!isRecord11(error61) || error61["code"] !== "ENOENT") {
29225
+ if (!isRecord12(error61) || error61["code"] !== "ENOENT") {
28417
29226
  throw error61;
28418
29227
  }
28419
29228
  });
@@ -28477,10 +29286,10 @@ var BotOutboundIpcServer = class {
28477
29286
  const requestSignal = AbortSignal.any([signal, timeout]);
28478
29287
  let response;
28479
29288
  try {
28480
- response = await fetch4(relayEndpoint(this.#relayUrl, context, request.target), {
29289
+ response = await fetch5(relayEndpoint(this.#relayUrl, context, request.target), {
28481
29290
  body: JSON.stringify({ idempotencyKey: request.idempotencyKey, text: request.text }),
28482
29291
  headers: {
28483
- authorization: `Bearer ${daemonToken(this.#relayUrl)}`,
29292
+ authorization: `Bearer ${daemonToken2(this.#relayUrl)}`,
28484
29293
  "content-type": "application/json",
28485
29294
  "x-mobius-bot-execution-capability": context.command.executionCapabilitySecret
28486
29295
  },
@@ -28501,7 +29310,7 @@ var BotOutboundIpcServer = class {
28501
29310
 
28502
29311
  // src/native-sessions/service.ts
28503
29312
  import { randomUUID as randomUUID4 } from "node:crypto";
28504
- import { basename as basename3 } from "node:path";
29313
+ import { basename as basename4 } from "node:path";
28505
29314
 
28506
29315
  // src/native-sessions/codex-history.ts
28507
29316
  import { spawn as spawn4 } from "node:child_process";
@@ -28534,7 +29343,6 @@ function decodeHistory(thread, value) {
28534
29343
  const page = turnsSchema.parse(value);
28535
29344
  const messages = [];
28536
29345
  let characters = 0;
28537
- let imageCharacters = 0;
28538
29346
  let truncated = page.nextCursor != null;
28539
29347
  for (const turn of page.data.toReversed()) {
28540
29348
  for (const item of turn.items) {
@@ -28542,22 +29350,19 @@ function decodeHistory(thread, value) {
28542
29350
  let message;
28543
29351
  if (type === "userMessage") {
28544
29352
  const { content } = userMessageSchema.parse(item);
28545
- const parsed = parseNativeHistoryText(
28546
- content.map((block) => {
28547
- const { type: type2 } = itemTypeSchema.parse(block);
28548
- if (type2 === "text") {
28549
- return textSchema.parse(block).text;
28550
- }
28551
- if (type2 === "image") {
28552
- return `[@image](${imageSchema.parse(block).url})`;
28553
- }
28554
- return "[Attachment]";
28555
- }).join("")
28556
- );
29353
+ const text2 = content.map((block) => {
29354
+ const { type: type2 } = itemTypeSchema.parse(block);
29355
+ if (type2 === "text") {
29356
+ return textSchema.parse(block).text;
29357
+ }
29358
+ if (type2 === "image") {
29359
+ return `[@image](${imageSchema.parse(block).url})`;
29360
+ }
29361
+ return "[Attachment]";
29362
+ }).join("");
28557
29363
  message = {
28558
29364
  role: "user",
28559
- text: parsed.text,
28560
- ...parsed.images.length > 0 ? { images: parsed.images } : {}
29365
+ text: text2
28561
29366
  };
28562
29367
  } else if (type === "agentMessage") {
28563
29368
  const agent = agentMessageSchema.parse(item);
@@ -28575,12 +29380,10 @@ function decodeHistory(thread, value) {
28575
29380
  truncated ||= text.length < message.text.length;
28576
29381
  messages.push({ ...message, text });
28577
29382
  characters += text.length;
28578
- imageCharacters += (message.images ?? []).reduce((size, image) => size + image.data.length, 0);
28579
- while (messages.length > SESSION_HISTORY_PREVIEW_MESSAGE_LIMIT || characters > SESSION_HISTORY_CHARACTER_LIMIT || imageCharacters > SESSION_HISTORY_IMAGE_CHARACTER_LIMIT) {
29383
+ while (messages.length > SESSION_HISTORY_PREVIEW_MESSAGE_LIMIT || characters > SESSION_HISTORY_CHARACTER_LIMIT) {
28580
29384
  const removed = messages.shift();
28581
29385
  if (removed !== void 0) {
28582
29386
  characters -= removed.text.length;
28583
- imageCharacters -= (removed.images ?? []).reduce((size, image) => size + image.data.length, 0);
28584
29387
  }
28585
29388
  truncated = true;
28586
29389
  }
@@ -28738,7 +29541,11 @@ async function readCodexHistory(agent, cwd, nativeSessionId, signal) {
28738
29541
  params: { clientInfo: { name: "mobius_history", version: "1.0.0" } }
28739
29542
  });
28740
29543
  }
28741
- return await response.promise;
29544
+ const snapshot = await response.promise;
29545
+ return {
29546
+ ...snapshot,
29547
+ history: await embedLocalHistoryImages(snapshot.history, [cwd, snapshot.cwd], signal)
29548
+ };
28742
29549
  } finally {
28743
29550
  clearTimeout(timeout);
28744
29551
  signal.removeEventListener("abort", abort);
@@ -28992,7 +29799,7 @@ var NativeSessionService = class {
28992
29799
  }
28993
29800
  resolvedPaths.add(path2);
28994
29801
  additionalDirectories.push(path2);
28995
- additionalEntries.push({ directoryId: directoryId2, name: basename3(path2) });
29802
+ additionalEntries.push({ directoryId: directoryId2, name: basename4(path2) });
28996
29803
  }
28997
29804
  const listing = await this.#directories.list(this.#config.bindingId, command.directoryId, signal);
28998
29805
  const opened = await this.#sessions.forkSessionAtTurn(
@@ -29131,13 +29938,13 @@ var NativeSessionService = class {
29131
29938
  };
29132
29939
 
29133
29940
  // src/prompt-artifact-resolver.ts
29134
- import { createHash as createHash3 } from "node:crypto";
29135
- import { fetch as fetch5 } from "undici";
29941
+ import { createHash as createHash4 } from "node:crypto";
29942
+ import { fetch as fetch6 } from "undici";
29136
29943
  var ARTIFACT_SCHEME = "mobius-artifact:";
29137
29944
  var ARTIFACT_DOWNLOAD_TIMEOUT_MILLISECONDS = 2e4;
29138
29945
  var MAX_AGENT_IMAGE_BASE64_LENGTH = 4e6;
29139
29946
  var MAX_AGENT_RESOURCE_BYTE_LENGTH = 1e6;
29140
- var IDENTIFIER_PATTERN7 = /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/;
29947
+ var IDENTIFIER_PATTERN8 = /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/;
29141
29948
  var PromptArtifactError = class extends Error {
29142
29949
  code;
29143
29950
  constructor(code, message, options = {}) {
@@ -29180,7 +29987,7 @@ function parseReference(resource) {
29180
29987
  const encodedByteLength2 = url2.searchParams.get("byteLength") ?? "";
29181
29988
  const sha256 = url2.searchParams.get("sha256") ?? "";
29182
29989
  const byteLength = Number(encodedByteLength2);
29183
- 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)) {
29990
+ if (url2.protocol !== ARTIFACT_SCHEME || url2.hash.length > 0 || resource.type !== "link" || resource.text.length > 0 || !IDENTIFIER_PATTERN8.test(artifactId) || keys.length !== 2 || keys[0] !== "byteLength" || keys[1] !== "sha256" || !/^[1-9][0-9]*$/.test(encodedByteLength2) || !Number.isSafeInteger(byteLength) || !/^[a-f0-9]{64}$/.test(sha256)) {
29184
29991
  throw new PromptArtifactError("artifact_reference_invalid", "The prompt artifact reference is invalid");
29185
29992
  }
29186
29993
  return new PromptArtifactReference(artifactId, byteLength, sha256, resource);
@@ -29246,7 +30053,7 @@ async function download(config2, command, reference, signal) {
29246
30053
  const requestSignal = AbortSignal.any([signal, timeoutSignal]);
29247
30054
  let response;
29248
30055
  try {
29249
- response = await fetch5(downloadUrl(config2, command, reference), {
30056
+ response = await fetch6(downloadUrl(config2, command, reference), {
29250
30057
  dispatcher: environmentProxyDispatcher,
29251
30058
  headers: {
29252
30059
  accept: reference.resource.mimeType,
@@ -29270,7 +30077,7 @@ async function download(config2, command, reference, signal) {
29270
30077
  );
29271
30078
  }
29272
30079
  const bytes = await responseBytes(response, reference.byteLength, requestSignal);
29273
- if (createHash3("sha256").update(bytes).digest("hex") !== reference.sha256) {
30080
+ if (createHash4("sha256").update(bytes).digest("hex") !== reference.sha256) {
29274
30081
  throw new PromptArtifactError(
29275
30082
  "artifact_integrity_failed",
29276
30083
  "The prompt artifact failed integrity validation"
@@ -30303,13 +31110,26 @@ function botIpcSocketPath() {
30303
31110
  if (process.platform === "win32") {
30304
31111
  return `\\\\.\\pipe\\mobius-bot-${randomUUID6()}`;
30305
31112
  }
30306
- return join16("/tmp", `mobius-bot-${randomUUID6()}.sock`);
31113
+ return join17("/tmp", `mobius-bot-${randomUUID6()}.sock`);
30307
31114
  }
30308
31115
  var DaemonAcpObserver = class {
31116
+ #config;
30309
31117
  #record;
30310
- constructor(record2) {
30311
- this.#record = record2;
31118
+ constructor(config2, record3) {
31119
+ this.#config = config2;
31120
+ this.#record = record3;
30312
31121
  }
31122
+ importLocalImage = async (sessionId, image, signal) => {
31123
+ try {
31124
+ return (await uploadRuntimeArtifact(this.#config, sessionId, image, signal)).artifactId;
31125
+ } catch (cause) {
31126
+ signal.throwIfAborted();
31127
+ if (cause instanceof Error && cause.name === "AbortError") {
31128
+ throw cause;
31129
+ }
31130
+ return "";
31131
+ }
31132
+ };
30313
31133
  onCommands = (event) => {
30314
31134
  this.#record(event.sessionId, encodeSessionCommandsUpdatedEvent(event));
30315
31135
  return Promise.resolve();
@@ -30519,7 +31339,7 @@ async function reconcileActiveTurn(config2, turn, signal) {
30519
31339
  const requestSignal = AbortSignal.any([signal, timeoutSignal]);
30520
31340
  let response;
30521
31341
  try {
30522
- response = await fetch6(activeTurnReconciliationEndpoint(config2, turn), {
31342
+ response = await fetch7(activeTurnReconciliationEndpoint(config2, turn), {
30523
31343
  body: JSON.stringify({ outcome: { kind: "running" } }),
30524
31344
  dispatcher: environmentProxyDispatcher,
30525
31345
  headers: { ...runtimeAuthorization(config2.relayUrl), "content-type": "application/json" },
@@ -30835,7 +31655,7 @@ async function resolveSessionDirectories(directories, bindingId, directoryId2, a
30835
31655
  additionalDirectories.push(directory);
30836
31656
  additionalDirectoryEntries.push({
30837
31657
  directoryId: additionalDirectoryId,
30838
- name: basename4(directory)
31658
+ name: basename5(directory)
30839
31659
  });
30840
31660
  }
30841
31661
  return new ResolvedSessionDirectories(cwd, additionalDirectories, additionalDirectoryEntries);
@@ -31346,8 +32166,7 @@ async function runRelayConnection(config2, directories, audit, sessions, install
31346
32166
  rejectConnection(failure);
31347
32167
  };
31348
32168
  const processingDeliveryIds = /* @__PURE__ */ new Set();
31349
- const processDeliveredPrompt = async (delivery) => {
31350
- const command = decodeSessionPromptCommand(delivery.payload);
32169
+ const processDeliveredPrompt = async (delivery, command, trackActiveAttempt, execute) => {
31351
32170
  if (command.sessionId !== delivery.sessionId) {
31352
32171
  throw new Error("Runtime delivery Session identity does not match its payload");
31353
32172
  }
@@ -31375,22 +32194,11 @@ async function runRelayConnection(config2, directories, audit, sessions, install
31375
32194
  }
31376
32195
  const turn = new ActiveDaemonTurn(command, receipt.attemptId);
31377
32196
  activeTurns.set(command.commandId, turn);
31378
- if (command.disposition !== SessionPromptDisposition.Steer) {
32197
+ if (trackActiveAttempt) {
31379
32198
  activeAttemptIds.set(command.sessionId, receipt.attemptId);
31380
32199
  }
31381
32200
  try {
31382
- await executePrompt(
31383
- outbox,
31384
- publisher,
31385
- command,
31386
- config2,
31387
- directories,
31388
- audit,
31389
- sessions,
31390
- receipt.attemptId,
31391
- timer,
31392
- turn.signal
31393
- );
32201
+ await execute(receipt.attemptId, turn.signal);
31394
32202
  } finally {
31395
32203
  activeTurns.delete(command.commandId);
31396
32204
  if (activeAttemptIds.get(command.sessionId) === receipt.attemptId) {
@@ -31469,8 +32277,50 @@ async function runRelayConnection(config2, directories, audit, sessions, install
31469
32277
  }
31470
32278
  return;
31471
32279
  }
32280
+ if (kind === BOT_SESSION_PROMPT_KIND) {
32281
+ const command = decodeBotSessionPromptCommand(delivery.payload);
32282
+ await processDeliveredPrompt(
32283
+ delivery,
32284
+ command,
32285
+ true,
32286
+ (attemptId, executionSignal) => executeBotPrompt(
32287
+ outbox,
32288
+ publisher,
32289
+ command,
32290
+ config2,
32291
+ directories,
32292
+ audit,
32293
+ sessions,
32294
+ grants,
32295
+ contexts,
32296
+ applicator,
32297
+ ipc,
32298
+ attemptId,
32299
+ timer,
32300
+ executionSignal
32301
+ )
32302
+ );
32303
+ return;
32304
+ }
31472
32305
  if (kind === SESSION_PROMPT_KIND) {
31473
- await processDeliveredPrompt(delivery);
32306
+ const command = decodeSessionPromptCommand(delivery.payload);
32307
+ await processDeliveredPrompt(
32308
+ delivery,
32309
+ command,
32310
+ command.disposition !== SessionPromptDisposition.Steer,
32311
+ (attemptId, executionSignal) => executePrompt(
32312
+ outbox,
32313
+ publisher,
32314
+ command,
32315
+ config2,
32316
+ directories,
32317
+ audit,
32318
+ sessions,
32319
+ attemptId,
32320
+ timer,
32321
+ executionSignal
32322
+ )
32323
+ );
31474
32324
  return;
31475
32325
  }
31476
32326
  throw new Error("Runtime delivery contains an unsupported protocol message");
@@ -31508,6 +32358,8 @@ async function runRelayConnection(config2, directories, audit, sessions, install
31508
32358
  payloadSessionId = decodeSessionElicitationRespondCommand(delivery.payload).sessionId;
31509
32359
  } else if (payloadKind === SESSION_PROMPT_KIND) {
31510
32360
  payloadSessionId = decodeSessionPromptCommand(delivery.payload).sessionId;
32361
+ } else if (payloadKind === BOT_SESSION_PROMPT_KIND) {
32362
+ payloadSessionId = decodeBotSessionPromptCommand(delivery.payload).sessionId;
31511
32363
  } else {
31512
32364
  throw new Error("Runtime delivery contains an unsupported protocol message");
31513
32365
  }
@@ -32105,7 +32957,7 @@ async function runDaemon(config2, audit, signal, timer = systemDaemonTimer) {
32105
32957
  }
32106
32958
  publisher.recordAttempt(sessionId, payload, attemptId);
32107
32959
  };
32108
- const sessions = new AcpSessionManager(new DaemonAcpObserver(recordSessionEvent), sessionStore);
32960
+ const sessions = new AcpSessionManager(new DaemonAcpObserver(config2, recordSessionEvent), sessionStore);
32109
32961
  const directories = new WorkspaceDirectoryService(config2.bindingId, config2.defaultWorkspace);
32110
32962
  const installationObserver = new DaemonInstallationObserver();
32111
32963
  const diagnostics = new RelayConnectionDiagnostics(audit, config2.channelId, config2.relayUrl);