@moxt-ai/mobius 0.0.16 → 0.0.18

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 (87) hide show
  1. package/dist/acp/session-config/grok-build-session-config.d.ts +10 -0
  2. package/dist/acp/session-config/grok-build-session-config.d.ts.map +1 -0
  3. package/dist/acp/session-config/grok-build-session-config.js +202 -0
  4. package/dist/acp/session-config/grok-build-session-config.js.map +1 -0
  5. package/dist/acp/session-config/session-config-protocol.d.ts +32 -0
  6. package/dist/acp/session-config/session-config-protocol.d.ts.map +1 -0
  7. package/dist/acp/session-config/session-config-protocol.js +237 -0
  8. package/dist/acp/session-config/session-config-protocol.js.map +1 -0
  9. package/dist/acp/session-config/session-config-registry.d.ts +3 -0
  10. package/dist/acp/session-config/session-config-registry.d.ts.map +1 -0
  11. package/dist/acp/session-config/session-config-registry.js +8 -0
  12. package/dist/acp/session-config/session-config-registry.js.map +1 -0
  13. package/dist/acp/session-manager.d.ts.map +1 -1
  14. package/dist/acp/session-manager.js +29 -155
  15. package/dist/acp/session-manager.js.map +1 -1
  16. package/dist/agent-catalog/agent-discovery.d.ts +19 -9
  17. package/dist/agent-catalog/agent-discovery.d.ts.map +1 -1
  18. package/dist/agent-catalog/agent-discovery.js +32 -16
  19. package/dist/agent-catalog/agent-discovery.js.map +1 -1
  20. package/dist/agent-catalog/agent-specification.d.ts +0 -1
  21. package/dist/agent-catalog/agent-specification.d.ts.map +1 -1
  22. package/dist/agent-catalog/agent-specification.js +0 -2
  23. package/dist/agent-catalog/agent-specification.js.map +1 -1
  24. package/dist/agent-catalog/agents/cursor-cli-agent.d.ts +0 -1
  25. package/dist/agent-catalog/agents/cursor-cli-agent.d.ts.map +1 -1
  26. package/dist/agent-catalog/agents/cursor-cli-agent.js +0 -1
  27. package/dist/agent-catalog/agents/cursor-cli-agent.js.map +1 -1
  28. package/dist/agent-catalog/discover-agent.d.ts.map +1 -1
  29. package/dist/agent-catalog/discover-agent.js +30 -21
  30. package/dist/agent-catalog/discover-agent.js.map +1 -1
  31. package/dist/agent-catalog/discover-local-agents.d.ts +0 -1
  32. package/dist/agent-catalog/discover-local-agents.d.ts.map +1 -1
  33. package/dist/agent-catalog/discover-local-agents.js +1 -1
  34. package/dist/agent-catalog/discover-local-agents.js.map +1 -1
  35. package/dist/agent-catalog/local-agent.d.ts +12 -1
  36. package/dist/agent-catalog/local-agent.d.ts.map +1 -1
  37. package/dist/agent-catalog/local-agent.js +16 -0
  38. package/dist/agent-catalog/local-agent.js.map +1 -1
  39. package/dist/agent-catalog/publish-agent-catalog.d.ts.map +1 -1
  40. package/dist/agent-catalog/publish-agent-catalog.js +3 -4
  41. package/dist/agent-catalog/publish-agent-catalog.js.map +1 -1
  42. package/dist/agent-installation/agent-installation-manager.d.ts.map +1 -1
  43. package/dist/agent-installation/agent-installation-manager.js +6 -7
  44. package/dist/agent-installation/agent-installation-manager.js.map +1 -1
  45. package/dist/agent-installation/fixed-installation-executor.d.ts +2 -3
  46. package/dist/agent-installation/fixed-installation-executor.d.ts.map +1 -1
  47. package/dist/agent-installation/fixed-installation-executor.js +47 -67
  48. package/dist/agent-installation/fixed-installation-executor.js.map +1 -1
  49. package/dist/agent-installation/managed-agent-archive.d.ts +2 -5
  50. package/dist/agent-installation/managed-agent-archive.d.ts.map +1 -1
  51. package/dist/agent-installation/managed-agent-archive.js +1 -1
  52. package/dist/agent-installation/managed-agent-archive.js.map +1 -1
  53. package/dist/agent-installation/verified-download.d.ts +0 -4
  54. package/dist/agent-installation/verified-download.d.ts.map +1 -1
  55. package/dist/agent-installation/verified-download.js +1 -1
  56. package/dist/agent-installation/verified-download.js.map +1 -1
  57. package/dist/cli.js +1128 -1782
  58. package/dist/cli.js.map +4 -4
  59. package/dist/index.js +1129 -1783
  60. package/dist/index.js.map +4 -4
  61. package/dist/pairing/pair-local-machine.d.ts.map +1 -1
  62. package/dist/pairing/pair-local-machine.js +4 -5
  63. package/dist/pairing/pair-local-machine.js.map +1 -1
  64. package/dist/run-daemon.d.ts.map +1 -1
  65. package/dist/run-daemon.js +162 -57
  66. package/dist/run-daemon.js.map +1 -1
  67. package/package.json +1 -1
  68. package/dist/agent-installation/automatic-adapter-provisioner.d.ts +0 -19
  69. package/dist/agent-installation/automatic-adapter-provisioner.d.ts.map +0 -1
  70. package/dist/agent-installation/automatic-adapter-provisioner.js +0 -125
  71. package/dist/agent-installation/automatic-adapter-provisioner.js.map +0 -1
  72. package/dist/agent-installation/fixed-agent-install-recipe.d.ts +0 -20
  73. package/dist/agent-installation/fixed-agent-install-recipe.d.ts.map +0 -1
  74. package/dist/agent-installation/fixed-agent-install-recipe.js +0 -18
  75. package/dist/agent-installation/fixed-agent-install-recipe.js.map +0 -1
  76. package/dist/agent-installation/fixed-agent-install-recipes.d.ts +0 -26
  77. package/dist/agent-installation/fixed-agent-install-recipes.d.ts.map +0 -1
  78. package/dist/agent-installation/fixed-agent-install-recipes.js +0 -301
  79. package/dist/agent-installation/fixed-agent-install-recipes.js.map +0 -1
  80. package/dist/agent-installation/grok-build-install-recipe.d.ts +0 -12
  81. package/dist/agent-installation/grok-build-install-recipe.d.ts.map +0 -1
  82. package/dist/agent-installation/grok-build-install-recipe.js +0 -102
  83. package/dist/agent-installation/grok-build-install-recipe.js.map +0 -1
  84. package/dist/agent-installation/workbuddy-install-recipe.d.ts +0 -12
  85. package/dist/agent-installation/workbuddy-install-recipe.d.ts.map +0 -1
  86. package/dist/agent-installation/workbuddy-install-recipe.js +0 -51
  87. package/dist/agent-installation/workbuddy-install-recipe.js.map +0 -1
package/dist/cli.js CHANGED
@@ -6,7 +6,7 @@ var __export = (target, all) => {
6
6
  };
7
7
 
8
8
  // src/cli.ts
9
- import { mkdir as mkdir6 } from "node:fs/promises";
9
+ import { mkdir as mkdir4 } from "node:fs/promises";
10
10
 
11
11
  // src/agent-catalog/local-agent.ts
12
12
  import { realpathSync, statSync } from "node:fs";
@@ -526,6 +526,22 @@ var InstallableAgentDefinition = class {
526
526
  this.label = label;
527
527
  }
528
528
  };
529
+ var MissingAgentDefinition = class extends InstallableAgentDefinition {
530
+ status = "agent_not_installed";
531
+ constructor(id, label) {
532
+ super(id, label);
533
+ }
534
+ };
535
+ var AgentIntegrationDefinition = class extends InstallableAgentDefinition {
536
+ agentPath;
537
+ agentVersion;
538
+ status = "integration_not_installed";
539
+ constructor(id, label, agentPath, agentVersion) {
540
+ super(id, label);
541
+ this.agentPath = agentPath;
542
+ this.agentVersion = agentVersion;
543
+ }
544
+ };
529
545
  var LocalAgentCatalogSnapshot = class {
530
546
  agents;
531
547
  installableAgents;
@@ -595,12 +611,19 @@ var AvailableAgent = class extends AgentDiscovery {
595
611
  };
596
612
  var UnavailableAgent = class extends AgentDiscovery {
597
613
  };
598
- var MissingAdapter = class extends UnavailableAgent {
614
+ var UnavailableInstalledAgent = class extends UnavailableAgent {
615
+ agent;
616
+ constructor(specification, agent) {
617
+ super(specification);
618
+ this.agent = agent;
619
+ }
620
+ };
621
+ var MissingAdapter = class extends UnavailableInstalledAgent {
599
622
  code = "adapter_not_found";
600
623
  message = "ACP adapter not found";
601
624
  status = "missing_adapter";
602
- constructor(specification) {
603
- super(specification);
625
+ constructor(specification, agent) {
626
+ super(specification, agent);
604
627
  }
605
628
  };
606
629
  var MissingAgent = class extends UnavailableAgent {
@@ -611,7 +634,7 @@ var MissingAgent = class extends UnavailableAgent {
611
634
  super(specification);
612
635
  }
613
636
  };
614
- var ProbeFailed = class extends UnavailableAgent {
637
+ var AgentProbeFailed = class extends UnavailableAgent {
615
638
  code;
616
639
  message;
617
640
  status = "probe_failed";
@@ -621,20 +644,30 @@ var ProbeFailed = class extends UnavailableAgent {
621
644
  this.message = message;
622
645
  }
623
646
  };
624
- var IncompatibleAdapter = class extends UnavailableAgent {
647
+ var IntegrationProbeFailed = class extends UnavailableInstalledAgent {
648
+ code;
649
+ message;
650
+ status = "probe_failed";
651
+ constructor(specification, agent, code, message) {
652
+ super(specification, agent);
653
+ this.code = code;
654
+ this.message = message;
655
+ }
656
+ };
657
+ var IncompatibleAdapter = class extends UnavailableInstalledAgent {
625
658
  code = "acp_incompatible";
626
659
  message = "ACP adapter is incompatible";
627
660
  status = "incompatible_adapter";
628
- constructor(specification) {
629
- super(specification);
661
+ constructor(specification, agent) {
662
+ super(specification, agent);
630
663
  }
631
664
  };
632
- var AuthenticationRequiredAgent = class extends UnavailableAgent {
665
+ var AuthenticationRequiredAgent = class extends UnavailableInstalledAgent {
633
666
  code = "authentication_required";
634
667
  message = "Agent authentication is required";
635
668
  status = "authentication_required";
636
- constructor(specification) {
637
- super(specification);
669
+ constructor(specification, agent) {
670
+ super(specification, agent);
638
671
  }
639
672
  };
640
673
  var LocalAgentInventory = class {
@@ -642,7 +675,7 @@ var LocalAgentInventory = class {
642
675
  discoveries;
643
676
  installable;
644
677
  unavailable;
645
- constructor(discoveries, platform = process.platform, architecture = process.arch) {
678
+ constructor(discoveries) {
646
679
  const available = [];
647
680
  const unavailable = [];
648
681
  for (const discovery of discoveries) {
@@ -657,13 +690,8 @@ var LocalAgentInventory = class {
657
690
  this.available = Object.freeze(available);
658
691
  this.discoveries = Object.freeze([...discoveries]);
659
692
  this.installable = Object.freeze(
660
- unavailable.filter(
661
- (discovery) => !(discovery instanceof AuthenticationRequiredAgent) && discovery.specification.supportsInstallation(
662
- platform,
663
- architecture
664
- )
665
- ).map(
666
- (discovery) => new InstallableAgentDefinition(
693
+ unavailable.map(
694
+ (discovery) => discovery instanceof UnavailableInstalledAgent ? discovery.agent : new MissingAgentDefinition(
667
695
  discovery.specification.id,
668
696
  discovery.specification.label
669
697
  )
@@ -1132,7 +1160,6 @@ var LocalAgentSpecification = class {
1132
1160
  createLaunchEnvironment = async (_agent, _context) => Object.freeze({});
1133
1161
  recoveryCommand = () => "";
1134
1162
  resolveInstalledAgentExecutables = (_context) => Promise.resolve([]);
1135
- supportsInstallation = (platform, architecture) => (platform === "darwin" || platform === "linux") && (architecture === "arm64" || architecture === "x64");
1136
1163
  verifyAcp = (_connection, _initialized, _defaultWorkspace, _signal) => Promise.resolve();
1137
1164
  };
1138
1165
  var DirectAcpAgentDefinition = class extends LocalAgentSpecification {
@@ -1280,7 +1307,6 @@ var CursorCliAgentSpecification = class extends DirectAcpAgentDefinition {
1280
1307
  ["agents", "cursor", CURSOR_CLI_TESTED_VERSION, "bin", "cursor-agent"]
1281
1308
  );
1282
1309
  }
1283
- supportsInstallation = (_platform, _architecture) => false;
1284
1310
  verifyAcp = async (connection, initialized, defaultWorkspace, signal) => {
1285
1311
  const capabilities = initialized.agentCapabilities ?? {};
1286
1312
  if (capabilities.loadSession !== true || capabilities.sessionCapabilities?.list == null || !(initialized.authMethods ?? []).some(
@@ -1594,14 +1620,14 @@ var GrokBuildAgentSpecification = class extends DirectAcpAgentDefinition {
1594
1620
  import { join as join8 } from "node:path";
1595
1621
 
1596
1622
  // src/agent-installation/managed-agent-archive.ts
1597
- import { createHash as createHash2 } from "node:crypto";
1623
+ import { createHash } from "node:crypto";
1598
1624
  import { createReadStream } from "node:fs";
1599
1625
  import {
1600
1626
  chmod,
1601
1627
  copyFile,
1602
1628
  mkdir as mkdir2,
1603
1629
  mkdtemp as mkdtemp2,
1604
- open as open3,
1630
+ open as open2,
1605
1631
  realpath as realpath5,
1606
1632
  rename as rename2,
1607
1633
  rm as rm2,
@@ -1611,208 +1637,16 @@ import {
1611
1637
  import { dirname as dirname2, isAbsolute as isAbsolute4, join as join7, relative as relative3, sep as sep3 } from "node:path";
1612
1638
 
1613
1639
  // src/agent-installation/verified-download.ts
1614
- import { createHash } from "node:crypto";
1615
- import { open as open2, unlink } from "node:fs/promises";
1616
1640
  import { fetch } from "undici";
1617
1641
 
1618
1642
  // src/network/environment-proxy.ts
1619
1643
  import { EnvHttpProxyAgent } from "undici";
1620
1644
  var environmentProxyDispatcher = new EnvHttpProxyAgent();
1621
1645
 
1622
- // src/agent-installation/verified-download.ts
1623
- var MAX_REDIRECTS = 4;
1624
- var REDIRECT_STATUSES = /* @__PURE__ */ new Set([301, 302, 303, 307, 308]);
1625
- var InstallerDownloadError = class extends Error {
1626
- code;
1627
- constructor(code, message, options = {}) {
1628
- super(message, options);
1629
- this.code = code;
1630
- this.name = "InstallerDownloadError";
1631
- }
1632
- };
1633
- var VerifiedDownload = class {
1634
- bytes;
1635
- sha256;
1636
- url;
1637
- constructor(url2, bytes, sha256) {
1638
- this.bytes = bytes;
1639
- this.sha256 = sha256;
1640
- this.url = url2;
1641
- }
1642
- };
1643
- var UndiciInstallerDownloadTransport = class {
1644
- get = async (url2, signal) => await fetch(url2, {
1645
- dispatcher: environmentProxyDispatcher,
1646
- headers: {
1647
- accept: "text/plain, application/octet-stream;q=0.9",
1648
- "user-agent": "Mobius-Agent-Installer/0.0.3"
1649
- },
1650
- method: "GET",
1651
- redirect: "manual",
1652
- signal
1653
- });
1654
- };
1655
- function validateUrl(url2, allowedHosts) {
1656
- if (url2.protocol !== "https:" || url2.username.length > 0 || url2.password.length > 0 || url2.port.length > 0 || !allowedHosts.has(url2.hostname)) {
1657
- throw new InstallerDownloadError(
1658
- "installer_host_not_allowed",
1659
- "The installer download target is not allowed"
1660
- );
1661
- }
1662
- }
1663
- async function fetchInstaller(options, signal, transport) {
1664
- let url2 = new URL(options.url);
1665
- for (let redirectCount = 0; redirectCount <= MAX_REDIRECTS; redirectCount += 1) {
1666
- validateUrl(url2, options.allowedHosts);
1667
- const response = await transport.get(url2, signal);
1668
- if (!REDIRECT_STATUSES.has(response.status)) {
1669
- return { response, url: url2 };
1670
- }
1671
- await response.body?.cancel();
1672
- const location = response.headers.get("location");
1673
- if (location === null || redirectCount === MAX_REDIRECTS) {
1674
- throw new InstallerDownloadError(
1675
- "installer_redirect_invalid",
1676
- "The installer returned an invalid redirect"
1677
- );
1678
- }
1679
- let redirected;
1680
- try {
1681
- redirected = new URL(location, url2);
1682
- } catch (error61) {
1683
- throw new InstallerDownloadError(
1684
- "installer_redirect_invalid",
1685
- "The installer returned an invalid redirect",
1686
- { cause: error61 }
1687
- );
1688
- }
1689
- try {
1690
- validateUrl(redirected, options.allowedHosts);
1691
- } catch (error61) {
1692
- throw new InstallerDownloadError(
1693
- "installer_redirect_not_allowed",
1694
- "The installer redirect left the approved host allowlist",
1695
- { cause: error61 }
1696
- );
1697
- }
1698
- url2 = redirected;
1699
- }
1700
- throw new InstallerDownloadError(
1701
- "installer_redirect_invalid",
1702
- "The installer returned too many redirects"
1703
- );
1704
- }
1705
- async function writeCompleteChunk(handle, chunk) {
1706
- let offset = 0;
1707
- while (offset < chunk.byteLength) {
1708
- const written = await handle.write(
1709
- chunk,
1710
- offset,
1711
- chunk.byteLength - offset
1712
- );
1713
- if (written.bytesWritten < 1) {
1714
- throw new InstallerDownloadError(
1715
- "installer_write_failed",
1716
- "The verified installer could not be stored"
1717
- );
1718
- }
1719
- offset += written.bytesWritten;
1720
- }
1721
- }
1722
- async function downloadVerifiedFile(options, transport = new UndiciInstallerDownloadTransport()) {
1723
- options.signal.throwIfAborted();
1724
- const timeoutSignal = AbortSignal.timeout(options.timeoutMilliseconds);
1725
- const signal = AbortSignal.any([options.signal, timeoutSignal]);
1726
- let handle = null;
1727
- let responseBody = null;
1728
- try {
1729
- const fetched = await fetchInstaller(options, signal, transport);
1730
- responseBody = fetched.response.body;
1731
- if (!fetched.response.ok || fetched.response.body === null) {
1732
- throw new InstallerDownloadError(
1733
- "installer_download_failed",
1734
- "The approved installer could not be downloaded"
1735
- );
1736
- }
1737
- const contentLength = fetched.response.headers.get("content-length");
1738
- if (contentLength !== null) {
1739
- const declaredLength = Number(contentLength);
1740
- if (!Number.isSafeInteger(declaredLength) || declaredLength < 1 || declaredLength > options.maximumBytes) {
1741
- throw new InstallerDownloadError(
1742
- "installer_size_invalid",
1743
- "The installer size is outside the approved limit"
1744
- );
1745
- }
1746
- }
1747
- handle = await open2(options.destination, "wx", 384);
1748
- const digest = createHash("sha256");
1749
- const reader = fetched.response.body.getReader();
1750
- let bytes = 0;
1751
- try {
1752
- while (true) {
1753
- signal.throwIfAborted();
1754
- const chunk = await reader.read();
1755
- if (chunk.done) {
1756
- break;
1757
- }
1758
- bytes += chunk.value.byteLength;
1759
- if (bytes > options.maximumBytes) {
1760
- throw new InstallerDownloadError(
1761
- "installer_size_invalid",
1762
- "The installer exceeded the approved size limit"
1763
- );
1764
- }
1765
- digest.update(chunk.value);
1766
- await writeCompleteChunk(handle, chunk.value);
1767
- }
1768
- } finally {
1769
- await reader.cancel().catch(() => void 0);
1770
- reader.releaseLock();
1771
- }
1772
- if (bytes === 0) {
1773
- throw new InstallerDownloadError(
1774
- "installer_verification_failed",
1775
- "The downloaded installer is empty"
1776
- );
1777
- }
1778
- await handle.sync();
1779
- await handle.close();
1780
- handle = null;
1781
- return new VerifiedDownload(fetched.url, bytes, digest.digest("hex"));
1782
- } catch (error61) {
1783
- if (handle !== null) {
1784
- await handle.close().catch(() => void 0);
1785
- }
1786
- await unlink(options.destination).catch(() => void 0);
1787
- if (options.signal.aborted) {
1788
- options.signal.throwIfAborted();
1789
- }
1790
- if (timeoutSignal.aborted) {
1791
- throw new InstallerDownloadError(
1792
- "installer_download_timeout",
1793
- "The installer download timed out",
1794
- { cause: error61 }
1795
- );
1796
- }
1797
- if (error61 instanceof InstallerDownloadError) {
1798
- throw error61;
1799
- }
1800
- throw new InstallerDownloadError(
1801
- "installer_download_failed",
1802
- "The approved installer could not be downloaded",
1803
- { cause: error61 }
1804
- );
1805
- } finally {
1806
- await responseBody?.cancel().catch(() => void 0);
1807
- }
1808
- }
1809
-
1810
1646
  // src/agent-installation/managed-agent-archive.ts
1811
1647
  var ARCHIVE_DOWNLOAD_LIMIT_BYTES = 128 * 1024 * 1024;
1812
1648
  var ARCHIVE_DOWNLOAD_TIMEOUT_MILLISECONDS = 2 * 60 * 1e3;
1813
- var ARCHIVE_EXTRACTION_TIMEOUT_MILLISECONDS = 6e4;
1814
1649
  var MANIFEST_LIMIT_BYTES = 16 * 1024;
1815
- var MINIMAL_PATH = "/usr/bin:/bin";
1816
1650
  var ManagedAgentArchiveDefinition = class {
1817
1651
  archiveName;
1818
1652
  archiveSha256;
@@ -1851,9 +1685,6 @@ var ManagedAgentArchiveError = class extends Error {
1851
1685
  this.name = "ManagedAgentArchiveError";
1852
1686
  }
1853
1687
  };
1854
- var ManagedAgentArchiveDownloader = class {
1855
- download = async (options) => await downloadVerifiedFile(options);
1856
- };
1857
1688
  function isRecord2(value) {
1858
1689
  return typeof value === "object" && value !== null && !Array.isArray(value);
1859
1690
  }
@@ -1863,7 +1694,7 @@ function isContainedPath3(root, candidate) {
1863
1694
  }
1864
1695
  async function hashFile(path2, signal) {
1865
1696
  signal.throwIfAborted();
1866
- const digest = createHash2("sha256");
1697
+ const digest = createHash("sha256");
1867
1698
  const stream = createReadStream(path2, { signal });
1868
1699
  try {
1869
1700
  for await (const chunk of stream) {
@@ -1894,7 +1725,7 @@ async function hashFile(path2, signal) {
1894
1725
  async function readManifest(path2) {
1895
1726
  let handle;
1896
1727
  try {
1897
- handle = await open3(path2, "r");
1728
+ handle = await open2(path2, "r");
1898
1729
  } catch (error61) {
1899
1730
  throw new ManagedAgentArchiveError(
1900
1731
  "managed_archive_verification_failed",
@@ -1965,144 +1796,6 @@ async function validateManagedAgentArchive(root, definition, signal) {
1965
1796
  );
1966
1797
  }
1967
1798
  }
1968
- function validateArchiveEntries(output2, definition) {
1969
- const entries = output2.split(/\r?\n/).map((entry) => entry.trim()).filter((entry) => entry.length > 0);
1970
- if (entries.length !== 1 || entries[0] !== definition.executableName && entries[0] !== `./${definition.executableName}`) {
1971
- throw new ManagedAgentArchiveError(
1972
- "managed_archive_verification_failed",
1973
- "The managed Agent archive contains unexpected entries"
1974
- );
1975
- }
1976
- }
1977
- var ManagedAgentArchiveInstaller = class {
1978
- #downloader;
1979
- constructor(downloader = new ManagedAgentArchiveDownloader()) {
1980
- this.#downloader = downloader;
1981
- }
1982
- install = async (root, definition, signal) => {
1983
- signal.throwIfAborted();
1984
- try {
1985
- const metadata = await stat4(root);
1986
- if (metadata.isDirectory()) {
1987
- return await validateManagedAgentArchive(root, definition, signal);
1988
- }
1989
- } catch (error61) {
1990
- if (error61 instanceof ManagedAgentArchiveError || !(error61 instanceof Error) || !("code" in error61) || error61.code !== "ENOENT") {
1991
- throw error61;
1992
- }
1993
- }
1994
- const parent = dirname2(root);
1995
- await mkdir2(parent, { mode: 448, recursive: true });
1996
- const working = await mkdtemp2(
1997
- join7(parent, `.${definition.version}.archive-`)
1998
- );
1999
- const staging = await mkdtemp2(
2000
- join7(parent, `.${definition.version}.staging-`)
2001
- );
2002
- try {
2003
- const archivePath = join7(working, definition.archiveName);
2004
- const extractionRoot = join7(working, "extracted");
2005
- await mkdir2(extractionRoot, { mode: 448 });
2006
- const canonicalExtractionRoot = await realpath5(extractionRoot);
2007
- const download = await this.#downloader.download({
2008
- allowedHosts: /* @__PURE__ */ new Set([
2009
- "github.com",
2010
- "objects.githubusercontent.com",
2011
- "release-assets.githubusercontent.com"
2012
- ]),
2013
- destination: archivePath,
2014
- maximumBytes: ARCHIVE_DOWNLOAD_LIMIT_BYTES,
2015
- signal,
2016
- timeoutMilliseconds: ARCHIVE_DOWNLOAD_TIMEOUT_MILLISECONDS,
2017
- url: definition.archiveUrl
2018
- });
2019
- if (download.sha256 !== definition.archiveSha256) {
2020
- throw new ManagedAgentArchiveError(
2021
- "managed_archive_verification_failed",
2022
- "The managed Agent archive checksum is invalid"
2023
- );
2024
- }
2025
- const list = await runBoundedProcess({
2026
- arguments: definition.listArguments(archivePath),
2027
- command: definition.extractor,
2028
- cwd: working,
2029
- environment: { PATH: MINIMAL_PATH },
2030
- outputLimitBytes: 64 * 1024,
2031
- signal,
2032
- timeoutMilliseconds: ARCHIVE_EXTRACTION_TIMEOUT_MILLISECONDS
2033
- });
2034
- validateArchiveEntries(list.stdout, definition);
2035
- await runBoundedProcess({
2036
- arguments: definition.extractArguments(archivePath, extractionRoot),
2037
- command: definition.extractor,
2038
- cwd: working,
2039
- environment: { PATH: MINIMAL_PATH },
2040
- outputLimitBytes: 64 * 1024,
2041
- signal,
2042
- timeoutMilliseconds: ARCHIVE_EXTRACTION_TIMEOUT_MILLISECONDS
2043
- });
2044
- const extracted = await realpath5(
2045
- join7(canonicalExtractionRoot, definition.executableName)
2046
- );
2047
- const extractedMetadata = await stat4(extracted);
2048
- if (!isContainedPath3(canonicalExtractionRoot, extracted) || !extractedMetadata.isFile()) {
2049
- throw new ManagedAgentArchiveError(
2050
- "managed_archive_verification_failed",
2051
- "The managed Agent archive executable is invalid"
2052
- );
2053
- }
2054
- const binDirectory = join7(staging, "bin");
2055
- const executablePath = join7(binDirectory, definition.executableName);
2056
- await mkdir2(binDirectory, { mode: 448 });
2057
- await copyFile(extracted, executablePath);
2058
- await chmod(executablePath, 448);
2059
- const executableSha256 = await hashFile(executablePath, signal);
2060
- await writeFile(
2061
- join7(staging, "archive.json"),
2062
- `${JSON.stringify({
2063
- archiveSha256: definition.archiveSha256,
2064
- archiveUrl: definition.archiveUrl.toString(),
2065
- executableSha256,
2066
- version: definition.version
2067
- })}
2068
- `,
2069
- { mode: 384 }
2070
- );
2071
- await validateManagedAgentArchive(staging, definition, signal);
2072
- try {
2073
- await rename2(staging, root);
2074
- } catch (error61) {
2075
- try {
2076
- return await validateManagedAgentArchive(root, definition, signal);
2077
- } catch {
2078
- throw new ManagedAgentArchiveError(
2079
- "managed_archive_publish_failed",
2080
- "The managed Agent archive could not be published",
2081
- { cause: error61 }
2082
- );
2083
- }
2084
- }
2085
- return await validateManagedAgentArchive(root, definition, signal);
2086
- } catch (error61) {
2087
- if (signal.aborted) {
2088
- signal.throwIfAborted();
2089
- }
2090
- if (error61 instanceof ManagedAgentArchiveError) {
2091
- throw error61;
2092
- }
2093
- throw new ManagedAgentArchiveError(
2094
- "managed_archive_install_failed",
2095
- "The pinned Agent archive could not be installed",
2096
- { cause: error61 }
2097
- );
2098
- } finally {
2099
- await Promise.all([
2100
- rm2(working, { force: true, recursive: true }),
2101
- rm2(staging, { force: true, recursive: true })
2102
- ]);
2103
- }
2104
- };
2105
- };
2106
1799
 
2107
1800
  // src/agent-installation/opencode-managed-release.ts
2108
1801
  var OPENCODE_MANAGED_VERSION = "1.18.29";
@@ -2644,10 +2337,6 @@ async function resolveAdapterExecutables(specification, context) {
2644
2337
  context
2645
2338
  );
2646
2339
  }
2647
- async function resolveAgentExecutable(specification, context) {
2648
- const executables = await resolveAgentExecutables(specification, context);
2649
- return executables[0] ?? null;
2650
- }
2651
2340
  async function resolveAdapterExecutable(specification, context) {
2652
2341
  const executables = await resolveAdapterExecutables(specification, context);
2653
2342
  return executables[0] ?? null;
@@ -2713,41 +2402,41 @@ var DiscoveryAcpHandler = class {
2713
2402
  };
2714
2403
  function readableAcpStream(input2) {
2715
2404
  let byteLength = 0;
2716
- let open6 = true;
2405
+ let open5 = true;
2717
2406
  return new ReadableStream({
2718
2407
  start(controller) {
2719
2408
  input2.on("data", (chunk) => {
2720
- if (!open6) {
2409
+ if (!open5) {
2721
2410
  return;
2722
2411
  }
2723
2412
  if (!(chunk instanceof Uint8Array)) {
2724
- open6 = false;
2413
+ open5 = false;
2725
2414
  controller.error(new Error("ACP adapter produced invalid output"));
2726
2415
  return;
2727
2416
  }
2728
2417
  byteLength += chunk.byteLength;
2729
2418
  if (byteLength > ACP_OUTPUT_LIMIT_BYTES) {
2730
- open6 = false;
2419
+ open5 = false;
2731
2420
  controller.error(new Error("ACP adapter output limit exceeded"));
2732
2421
  return;
2733
2422
  }
2734
2423
  controller.enqueue(new Uint8Array(chunk));
2735
2424
  });
2736
2425
  input2.once("end", () => {
2737
- if (open6) {
2738
- open6 = false;
2426
+ if (open5) {
2427
+ open5 = false;
2739
2428
  controller.close();
2740
2429
  }
2741
2430
  });
2742
2431
  input2.once("error", (error61) => {
2743
- if (open6) {
2744
- open6 = false;
2432
+ if (open5) {
2433
+ open5 = false;
2745
2434
  controller.error(error61);
2746
2435
  }
2747
2436
  });
2748
2437
  },
2749
2438
  cancel() {
2750
- open6 = false;
2439
+ open5 = false;
2751
2440
  }
2752
2441
  });
2753
2442
  }
@@ -2876,25 +2565,50 @@ async function probeAcpReadiness(specification, agent, environment, defaultWorks
2876
2565
  }
2877
2566
 
2878
2567
  // src/agent-catalog/discover-agent.ts
2879
- function probeFailure(specification, executableKind, error61) {
2568
+ function agentProbeFailure(specification, error61) {
2569
+ if (error61 instanceof AgentProbeError) {
2570
+ return new AgentProbeFailed(specification, error61.code, error61.message);
2571
+ }
2572
+ if (error61 instanceof ProcessExecutionError) {
2573
+ const code = error61.code === "process_timeout" ? "agent_probe_timeout" : "agent_probe_failed";
2574
+ return new AgentProbeFailed(
2575
+ specification,
2576
+ code,
2577
+ "Agent version probe failed"
2578
+ );
2579
+ }
2580
+ return new AgentProbeFailed(
2581
+ specification,
2582
+ "agent_probe_failed",
2583
+ "Agent probe failed"
2584
+ );
2585
+ }
2586
+ function integrationProbeFailure(specification, agent, error61) {
2880
2587
  if (error61 instanceof AgentProbeError) {
2881
2588
  if (error61.code === "authentication_required") {
2882
- return new AuthenticationRequiredAgent(specification);
2589
+ return new AuthenticationRequiredAgent(specification, agent);
2883
2590
  }
2884
- return error61.code === "acp_incompatible" ? new IncompatibleAdapter(specification) : new ProbeFailed(specification, error61.code, error61.message);
2591
+ return error61.code === "acp_incompatible" ? new IncompatibleAdapter(specification, agent) : new IntegrationProbeFailed(
2592
+ specification,
2593
+ agent,
2594
+ error61.code,
2595
+ error61.message
2596
+ );
2885
2597
  }
2886
2598
  if (error61 instanceof ProcessExecutionError) {
2887
- const code = error61.code === "process_timeout" ? `${executableKind}_probe_timeout` : `${executableKind}_probe_failed`;
2888
- return new ProbeFailed(
2599
+ const code = error61.code === "process_timeout" ? "adapter_probe_timeout" : "adapter_probe_failed";
2600
+ return new IntegrationProbeFailed(
2889
2601
  specification,
2602
+ agent,
2890
2603
  code,
2891
- `${executableKind === "agent" ? "Agent" : "Adapter"} version probe failed`
2604
+ "Adapter version probe failed"
2892
2605
  );
2893
2606
  }
2894
- return new ProbeFailed(
2607
+ return new IntegrationProbeFailed(
2895
2608
  specification,
2896
- `${executableKind}_probe_failed`,
2897
- `${executableKind === "agent" ? "Agent" : "Adapter"} probe failed`
2609
+ agent,
2610
+ "adapter_probe_failed",
2611
+ "Adapter probe failed"
2898
2612
  );
2899
2613
  }
2900
2614
  async function discoverAgent(specification, context) {
@@ -2903,12 +2617,6 @@ async function discoverAgent(specification, context) {
2903
2617
  resolveAdapterExecutables(specification, context),
2904
2618
  resolveAgentExecutables(specification, context)
2905
2619
  ]);
2906
- if (specification instanceof DirectAcpAgentDefinition && agents.length === 0) {
2907
- return new MissingAgent(specification);
2908
- }
2909
- if (adapters.length === 0) {
2910
- return new MissingAdapter(specification);
2911
- }
2912
2620
  if (agents.length === 0) {
2913
2621
  return new MissingAgent(specification);
2914
2622
  }
@@ -2928,9 +2636,18 @@ async function discoverAgent(specification, context) {
2928
2636
  if (context.signal.aborted) {
2929
2637
  context.signal.throwIfAborted();
2930
2638
  }
2931
- lastFailure = probeFailure(specification, "agent", error61);
2639
+ lastFailure = agentProbeFailure(specification, error61);
2932
2640
  continue;
2933
2641
  }
2642
+ const installedAgent = new AgentIntegrationDefinition(
2643
+ specification.id,
2644
+ specification.label,
2645
+ agent.identity.requestedPath,
2646
+ agentVersion
2647
+ );
2648
+ if (adapters.length === 0) {
2649
+ return new MissingAdapter(specification, installedAgent);
2650
+ }
2934
2651
  for (const adapter of adapters) {
2935
2652
  if (specification instanceof DirectAcpAgentDefinition && adapter.path !== agent.path) {
2936
2653
  continue;
@@ -2959,7 +2676,11 @@ async function discoverAgent(specification, context) {
2959
2676
  if (context.signal.aborted) {
2960
2677
  context.signal.throwIfAborted();
2961
2678
  }
2962
- lastFailure = probeFailure(specification, "adapter", error61);
2679
+ lastFailure = integrationProbeFailure(
2680
+ specification,
2681
+ installedAgent,
2682
+ error61
2683
+ );
2963
2684
  continue;
2964
2685
  }
2965
2686
  const definition = new LocalAgentDefinition(
@@ -3008,7 +2729,11 @@ async function discoverAgent(specification, context) {
3008
2729
  if (context.signal.aborted) {
3009
2730
  context.signal.throwIfAborted();
3010
2731
  }
3011
- const failure = probeFailure(specification, "adapter", error61);
2732
+ const failure = integrationProbeFailure(
2733
+ specification,
2734
+ installedAgent,
2735
+ error61
2736
+ );
3012
2737
  if (failure instanceof AuthenticationRequiredAgent) {
3013
2738
  return failure;
3014
2739
  }
@@ -3016,7 +2741,7 @@ async function discoverAgent(specification, context) {
3016
2741
  }
3017
2742
  }
3018
2743
  }
3019
- return lastFailure ?? new IncompatibleAdapter(specification);
2744
+ return lastFailure ?? new MissingAgent(specification);
3020
2745
  }
3021
2746
 
3022
2747
  // src/agent-catalog/discover-local-agents.ts
@@ -3027,11 +2752,7 @@ async function discoverLocalAgentInventory(options) {
3027
2752
  async (specification) => await discoverAgent(specification, options)
3028
2753
  )
3029
2754
  );
3030
- return new LocalAgentInventory(
3031
- discoveries,
3032
- options.platform,
3033
- options.architecture
3034
- );
2755
+ return new LocalAgentInventory(discoveries);
3035
2756
  }
3036
2757
 
3037
2758
  // src/audit/audit-store.ts
@@ -5047,8 +4768,8 @@ function emoji() {
5047
4768
  }
5048
4769
  var ipv4 = /^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$/;
5049
4770
  var ipv6 = /^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:))$/;
5050
- var mac = (delimiter3) => {
5051
- const escapedDelim = escapeRegex(delimiter3 ?? ":");
4771
+ var mac = (delimiter2) => {
4772
+ const escapedDelim = escapeRegex(delimiter2 ?? ":");
5052
4773
  return new RegExp(`^(?:[0-9A-F]{2}${escapedDelim}){5}[0-9A-F]{2}$|^(?:[0-9a-f]{2}${escapedDelim}){5}[0-9a-f]{2}$`);
5053
4774
  };
5054
4775
  var cidrv4 = /^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\/([0-9]|[1-2][0-9]|3[0-2])$/;
@@ -8105,7 +7826,7 @@ function bucketFor(state, inst) {
8105
7826
  return bucket;
8106
7827
  }
8107
7828
  var handoff;
8108
- var open4 = [];
7829
+ var open3 = [];
8109
7830
  var memo = {
8110
7831
  alloc(_inst, payload, empty) {
8111
7832
  const bucket = handoff;
@@ -8114,7 +7835,7 @@ var memo = {
8114
7835
  handoff = void 0;
8115
7836
  const entry = { value: empty, issues: null };
8116
7837
  bucket.set(payload.value, entry);
8117
- open4.push(entry);
7838
+ open3.push(entry);
8118
7839
  return empty;
8119
7840
  },
8120
7841
  guard(inst) {
@@ -8180,10 +7901,10 @@ var memo = {
8180
7901
  return payload;
8181
7902
  }
8182
7903
  handoff = bucket;
8183
- const depth = open4.length;
7904
+ const depth = open3.length;
8184
7905
  const result = base(payload, ctx);
8185
7906
  handoff = void 0;
8186
- const entry = open4.length > depth ? open4.pop() : void 0;
7907
+ const entry = open3.length > depth ? open3.pop() : void 0;
8187
7908
  if (result instanceof Promise) {
8188
7909
  return result.then((r) => {
8189
7910
  if (entry)
@@ -22021,13 +21742,13 @@ var SESSION_ELICITATION_RESPOND_KIND = "session.elicitation.respond";
22021
21742
  var SESSION_ELICITATION_RESOLVED_KIND = "session.elicitation.resolved";
22022
21743
  var SESSION_OPERATION_FAILED_KIND = "session.operation.failed";
22023
21744
  var AGENT_CONTENT_KIND = "agent.content";
22024
- var AGENT_INSTALL_REQUEST_KIND = "agent.install.request";
22025
- var AGENT_INSTALL_CANCEL_KIND = "agent.install.cancel";
22026
- var AGENT_INSTALL_STARTED_KIND = "agent.install.started";
22027
- var AGENT_INSTALL_PROGRESS_KIND = "agent.install.progress";
22028
- var AGENT_INSTALL_COMPLETED_KIND = "agent.install.completed";
22029
- var AGENT_INSTALL_FAILED_KIND = "agent.install.failed";
22030
- var AGENT_INSTALL_CANCELLED_KIND = "agent.install.cancelled";
21745
+ var AGENT_INSTALL_REQUEST_KIND = "agent.integration.install.request";
21746
+ var AGENT_INSTALL_CANCEL_KIND = "agent.integration.install.cancel";
21747
+ var AGENT_INSTALL_STARTED_KIND = "agent.integration.install.started";
21748
+ var AGENT_INSTALL_PROGRESS_KIND = "agent.integration.install.progress";
21749
+ var AGENT_INSTALL_COMPLETED_KIND = "agent.integration.install.completed";
21750
+ var AGENT_INSTALL_FAILED_KIND = "agent.integration.install.failed";
21751
+ var AGENT_INSTALL_CANCELLED_KIND = "agent.integration.install.cancelled";
22031
21752
  var IDENTIFIER_PATTERN = /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/;
22032
21753
  var DIRECTORY_IDENTIFIER_PATTERN = /^[a-zA-Z0-9][a-zA-Z0-9_-]{0,2047}$/;
22033
21754
  var IDENTIFIER = external_exports.string().min(1).max(128).regex(IDENTIFIER_PATTERN);
@@ -23569,7 +23290,7 @@ function createDaemonConfig(connection, agents = [], installableAgents = []) {
23569
23290
  import { randomUUID } from "node:crypto";
23570
23291
  import {
23571
23292
  mkdir as mkdir3,
23572
- open as open5,
23293
+ open as open4,
23573
23294
  realpath as realpath6,
23574
23295
  rename as rename3,
23575
23296
  stat as stat5,
@@ -23790,6 +23511,8 @@ function decodeClaimResponse(value) {
23790
23511
  }
23791
23512
  async function claimPairing(options, defaultWorkspace, localAgents, installableAgents, signal) {
23792
23513
  const agents = localAgents.map((agent) => ({
23514
+ agentPath: agent.agentIdentity.requestedPath,
23515
+ agentVersion: agent.agentVersion,
23793
23516
  id: agent.id,
23794
23517
  label: agent.label
23795
23518
  }));
@@ -23799,10 +23522,7 @@ async function claimPairing(options, defaultWorkspace, localAgents, installableA
23799
23522
  response = await fetch2(endpoint, {
23800
23523
  body: JSON.stringify({
23801
23524
  agents,
23802
- installableAgents: installableAgents.map((agent) => ({
23803
- id: agent.id,
23804
- label: agent.label
23805
- })),
23525
+ installableAgents,
23806
23526
  machineName: hostname3(),
23807
23527
  pairingCode: options.code,
23808
23528
  workspaceName: basename(defaultWorkspace) || "Local workspace"
@@ -23885,7 +23605,7 @@ async function readSavedConnection(channelId) {
23885
23605
  `${channelId}.json`
23886
23606
  );
23887
23607
  let encoded = "";
23888
- const handle = await open5(connectionPath, "r");
23608
+ const handle = await open4(connectionPath, "r");
23889
23609
  try {
23890
23610
  const metadata = await handle.stat();
23891
23611
  if (!metadata.isFile() || metadata.size > MAX_CONNECTION_FILE_LENGTH) {
@@ -23922,7 +23642,7 @@ function assertInventoryUsable(inventory) {
23922
23642
  if (inventory.available.length + inventory.installable.length === 0) {
23923
23643
  throw new PairingClientError(
23924
23644
  "no_supported_agent",
23925
- "No supported Agent is ready or safely installable on this machine"
23645
+ "No supported Agent is available for local discovery"
23926
23646
  );
23927
23647
  }
23928
23648
  }
@@ -24010,12 +23730,12 @@ async function resumeLocalMachine(arguments_, signal = new AbortController().sig
24010
23730
  // src/run-daemon.ts
24011
23731
  import { basename as basename3 } from "node:path";
24012
23732
  import { styleText } from "node:util";
24013
- import { WebSocket as WebSocket2 } from "undici";
23733
+ import { fetch as fetch4, WebSocket as WebSocket2 } from "undici";
24014
23734
 
24015
23735
  // src/acp/session-manager.ts
24016
23736
  import { spawn as spawn3 } from "node:child_process";
24017
23737
  import {
24018
- methods as methods5,
23738
+ methods as methods6,
24019
23739
  ndJsonStream as ndJsonStream2,
24020
23740
  PROTOCOL_VERSION as PROTOCOL_VERSION2,
24021
23741
  RequestError as RequestError2
@@ -24529,39 +24249,524 @@ var nativeSessionPageSchema = external_exports.object({
24529
24249
  nextCursor: external_exports.string().min(1).max(4096).nullish()
24530
24250
  }).readonly();
24531
24251
 
24532
- // src/acp/session-history.ts
24533
- var AcpHistoryReplay = class {
24534
- #messages = [];
24535
- #lastMessageId = null;
24536
- #characters = 0;
24537
- #imageCharacters = 0;
24538
- #truncated = false;
24539
- record = (update) => {
24540
- if (update.sessionUpdate !== "user_message_chunk" && update.sessionUpdate !== "agent_message_chunk")
24541
- return;
24542
- if (update.sessionUpdate === "agent_message_chunk" && isProgressMessage(update))
24543
- return;
24544
- const role = update.sessionUpdate === "user_message_chunk" ? "user" : "assistant";
24545
- const content = update.content;
24546
- const parsed = parseNativeHistoryText(
24547
- content.type === "text" ? content.text : content.type === "image" ? `[@image](data:${content.mimeType};base64,${content.data})` : `[${content.type} attachment]`
24548
- );
24549
- const text = parsed.text;
24550
- if (text.length === 0 && parsed.images.length === 0) return;
24551
- const previous = this.#messages.at(-1);
24552
- const id = update.messageId ?? null;
24553
- const continuation = previous?.role === role && id === this.#lastMessageId;
24554
- const combined = continuation ? `${previous.text}${text}` : text;
24555
- const allImages = continuation ? [...previous.images ?? [], ...parsed.images] : parsed.images;
24556
- const images = allImages.slice(0, 8);
24557
- this.#truncated ||= images.length < allImages.length;
24558
- if (continuation) {
24559
- this.#messages.pop();
24560
- this.#characters -= previous.text.length;
24561
- this.#imageCharacters -= (previous.images ?? []).reduce(
24562
- (size, image) => size + image.data.length,
24563
- 0
24564
- );
24252
+ // src/acp/session-config/session-config-protocol.ts
24253
+ import { methods as methods5 } from "@agentclientprotocol/sdk";
24254
+ var AGENT_DEFAULT_REASONING_EFFORT = "agent_default";
24255
+ var MAXIMUM_CONFIG_OPTIONS = 100;
24256
+ var SessionConfigProtocolError = class extends Error {
24257
+ code = "invalid_session_configuration_response";
24258
+ constructor(message, options = {}) {
24259
+ super(message, options);
24260
+ this.name = "SessionConfigProtocolError";
24261
+ }
24262
+ };
24263
+ function isRecord6(value) {
24264
+ return typeof value === "object" && value !== null && !Array.isArray(value);
24265
+ }
24266
+ function readString2(value, fallback = "") {
24267
+ return typeof value === "string" ? value : fallback;
24268
+ }
24269
+ function truncate2(value, maximum) {
24270
+ return value.length <= maximum ? value : value.slice(0, maximum);
24271
+ }
24272
+ function readBoolean(value, fallback = false) {
24273
+ return typeof value === "boolean" ? value : fallback;
24274
+ }
24275
+ function normalizeConfigValue(option, groupId = "", groupName = "") {
24276
+ return {
24277
+ description: truncate2(readString2(option["description"]), 500),
24278
+ groupId: truncate2(groupId, 128),
24279
+ groupName: truncate2(groupName, 255),
24280
+ name: truncate2(
24281
+ readString2(option["name"], readString2(option["value"])),
24282
+ 255
24283
+ ),
24284
+ value: truncate2(readString2(option["value"]), 500)
24285
+ };
24286
+ }
24287
+ function normalizeConfigValues(value) {
24288
+ if (!Array.isArray(value)) {
24289
+ return [];
24290
+ }
24291
+ const normalized = [];
24292
+ for (const entry of value) {
24293
+ if (!isRecord6(entry)) {
24294
+ continue;
24295
+ }
24296
+ const groupedOptions = entry["options"];
24297
+ if (Array.isArray(groupedOptions)) {
24298
+ const groupId = readString2(entry["group"]);
24299
+ const groupName = readString2(entry["name"]);
24300
+ for (const groupedOption of groupedOptions) {
24301
+ if (isRecord6(groupedOption)) {
24302
+ normalized.push(
24303
+ normalizeConfigValue(groupedOption, groupId, groupName)
24304
+ );
24305
+ }
24306
+ }
24307
+ continue;
24308
+ }
24309
+ normalized.push(normalizeConfigValue(entry));
24310
+ }
24311
+ return normalized.filter((entry) => entry.value.length > 0).slice(0, 500);
24312
+ }
24313
+ function normalizeConfigOptions(value, modes) {
24314
+ const normalized = [];
24315
+ if (Array.isArray(value)) {
24316
+ for (const option of value) {
24317
+ if (!isRecord6(option)) {
24318
+ continue;
24319
+ }
24320
+ const id = truncate2(readString2(option["id"]), 128);
24321
+ const name = truncate2(readString2(option["name"], id), 255);
24322
+ if (id.length === 0 || name.length === 0) {
24323
+ continue;
24324
+ }
24325
+ if (option["type"] === "boolean") {
24326
+ normalized.push({
24327
+ booleanValue: readBoolean(option["currentValue"]),
24328
+ category: truncate2(readString2(option["category"]), 128),
24329
+ currentValue: "",
24330
+ description: truncate2(readString2(option["description"]), 500),
24331
+ id,
24332
+ name,
24333
+ type: "boolean",
24334
+ values: []
24335
+ });
24336
+ continue;
24337
+ }
24338
+ if (option["type"] === "select") {
24339
+ const values = normalizeConfigValues(option["options"]);
24340
+ const currentValue = truncate2(readString2(option["currentValue"]), 500);
24341
+ if (currentValue.length > 0 && values.some((entry) => entry.value === currentValue)) {
24342
+ normalized.push({
24343
+ booleanValue: false,
24344
+ category: truncate2(readString2(option["category"]), 128),
24345
+ currentValue,
24346
+ description: truncate2(readString2(option["description"]), 500),
24347
+ id,
24348
+ name,
24349
+ type: "select",
24350
+ values
24351
+ });
24352
+ }
24353
+ }
24354
+ }
24355
+ }
24356
+ if (isRecord6(modes)) {
24357
+ const values = [];
24358
+ const availableModes = modes["availableModes"];
24359
+ if (Array.isArray(availableModes)) {
24360
+ for (const mode of availableModes) {
24361
+ if (!isRecord6(mode)) {
24362
+ continue;
24363
+ }
24364
+ const id = truncate2(readString2(mode["id"]), 500);
24365
+ if (id.length === 0) {
24366
+ continue;
24367
+ }
24368
+ values.push({
24369
+ description: truncate2(readString2(mode["description"]), 500),
24370
+ groupId: "",
24371
+ groupName: "",
24372
+ name: truncate2(readString2(mode["name"], id), 255),
24373
+ value: id
24374
+ });
24375
+ }
24376
+ }
24377
+ const currentValue = truncate2(readString2(modes["currentModeId"]), 500);
24378
+ if (currentValue.length > 0 && values.some((entry) => entry.value === currentValue) && !normalized.some((entry) => entry.category === "mode")) {
24379
+ normalized.unshift({
24380
+ booleanValue: false,
24381
+ category: "mode",
24382
+ currentValue,
24383
+ description: "Agent session mode",
24384
+ id: "mode",
24385
+ name: "Mode",
24386
+ type: "select",
24387
+ values
24388
+ });
24389
+ }
24390
+ }
24391
+ return normalized.slice(0, 100);
24392
+ }
24393
+ function ensureReasoningEffortOption(current) {
24394
+ if (current.some((option) => option.category === "thought_level")) {
24395
+ return current;
24396
+ }
24397
+ const unavailable = {
24398
+ booleanValue: false,
24399
+ category: "thought_level",
24400
+ currentValue: AGENT_DEFAULT_REASONING_EFFORT,
24401
+ description: "This Agent does not expose adjustable reasoning effort for the selected model.",
24402
+ id: "reasoning_effort",
24403
+ name: "Reasoning effort",
24404
+ type: "select",
24405
+ values: [
24406
+ {
24407
+ description: "Selected by the Agent",
24408
+ groupId: "",
24409
+ groupName: "",
24410
+ name: "Agent default",
24411
+ value: AGENT_DEFAULT_REASONING_EFFORT
24412
+ }
24413
+ ]
24414
+ };
24415
+ const modelIndex = current.findIndex((option) => option.category === "model");
24416
+ if (current.length < MAXIMUM_CONFIG_OPTIONS) {
24417
+ if (modelIndex < 0) {
24418
+ return [...current, unavailable];
24419
+ }
24420
+ return [
24421
+ ...current.slice(0, modelIndex + 1),
24422
+ unavailable,
24423
+ ...current.slice(modelIndex + 1)
24424
+ ];
24425
+ }
24426
+ if (modelIndex < 0) {
24427
+ return [...current.slice(0, MAXIMUM_CONFIG_OPTIONS - 1), unavailable];
24428
+ }
24429
+ if (modelIndex < MAXIMUM_CONFIG_OPTIONS - 1) {
24430
+ return [
24431
+ ...current.slice(0, modelIndex + 1),
24432
+ unavailable,
24433
+ ...current.slice(modelIndex + 1, MAXIMUM_CONFIG_OPTIONS - 1)
24434
+ ];
24435
+ }
24436
+ const model = current[modelIndex];
24437
+ if (model === void 0) {
24438
+ return [...current.slice(0, MAXIMUM_CONFIG_OPTIONS - 1), unavailable];
24439
+ }
24440
+ return [...current.slice(0, MAXIMUM_CONFIG_OPTIONS - 2), model, unavailable];
24441
+ }
24442
+ function normalizeStandardLifecycle(response) {
24443
+ const lifecycle = isRecord6(response) ? response : {};
24444
+ return ensureReasoningEffortOption(
24445
+ normalizeConfigOptions(lifecycle["configOptions"], lifecycle["modes"])
24446
+ );
24447
+ }
24448
+ function replaceStandardConfigOptions(current, value) {
24449
+ const next = normalizeConfigOptions(value, void 0);
24450
+ const withMode = next.some((option) => option.category === "mode") ? next : [
24451
+ ...current.filter((option) => option.category === "mode"),
24452
+ ...next
24453
+ ].slice(0, 100);
24454
+ return ensureReasoningEffortOption(withMode);
24455
+ }
24456
+ function updateCurrentValue(current, configId, value) {
24457
+ return current.map(
24458
+ (option) => option.id === configId ? { ...option, currentValue: value } : option
24459
+ );
24460
+ }
24461
+ var StandardSessionConfigProtocol = class {
24462
+ configure = async (current, change, nativeSessionId, transport) => {
24463
+ const existing = current.find((option) => option.id === change.configId);
24464
+ if (existing === void 0) {
24465
+ return current;
24466
+ }
24467
+ if (existing.type === "select" && existing.category === "mode") {
24468
+ await transport.request(
24469
+ methods5.agent.session.setMode,
24470
+ { modeId: change.value, sessionId: nativeSessionId },
24471
+ "ACP agent exited while setting the session mode",
24472
+ change.signal
24473
+ );
24474
+ return updateCurrentValue(current, existing.id, change.value);
24475
+ }
24476
+ const params = existing.type === "boolean" ? {
24477
+ configId: existing.id,
24478
+ sessionId: nativeSessionId,
24479
+ type: "boolean",
24480
+ value: change.booleanValue
24481
+ } : {
24482
+ configId: existing.id,
24483
+ sessionId: nativeSessionId,
24484
+ value: change.value
24485
+ };
24486
+ const response = await transport.request(
24487
+ methods5.agent.session.setConfigOption,
24488
+ params,
24489
+ "ACP agent exited while changing session configuration",
24490
+ change.signal
24491
+ );
24492
+ if (!isRecord6(response) || !Array.isArray(response["configOptions"])) {
24493
+ throw new SessionConfigProtocolError(
24494
+ "The Agent returned an invalid session configuration response"
24495
+ );
24496
+ }
24497
+ return replaceStandardConfigOptions(current, response["configOptions"]);
24498
+ };
24499
+ normalizeLifecycle = (response) => normalizeStandardLifecycle(response);
24500
+ normalizeUpdate = (current, value) => replaceStandardConfigOptions(current, value);
24501
+ };
24502
+ var standardSessionConfigProtocol = new StandardSessionConfigProtocol();
24503
+
24504
+ // src/acp/session-config/grok-build-session-config.ts
24505
+ var LEGACY_MODEL_CONFIG_ID = "grok_build_legacy_model";
24506
+ var LEGACY_REASONING_EFFORT_CONFIG_ID = "grok_build_legacy_reasoning_effort";
24507
+ function legacyOptions(response) {
24508
+ if (!isRecord6(response)) {
24509
+ return [];
24510
+ }
24511
+ const metadata = response["_meta"];
24512
+ if (!isRecord6(metadata)) {
24513
+ return [];
24514
+ }
24515
+ const sessionConfig = metadata["x.ai/sessionConfig"];
24516
+ if (!isRecord6(sessionConfig) || !Array.isArray(sessionConfig["options"])) {
24517
+ return [];
24518
+ }
24519
+ return sessionConfig["options"].slice(0, 500).filter(isRecord6);
24520
+ }
24521
+ function legacyValue(option) {
24522
+ const value = readString2(option["id"]);
24523
+ return {
24524
+ description: readString2(option["description"]).slice(0, 500),
24525
+ groupId: "",
24526
+ groupName: "",
24527
+ name: readString2(option["label"], value).slice(0, 255),
24528
+ value: value.slice(0, 500)
24529
+ };
24530
+ }
24531
+ function modelsRecord(response) {
24532
+ if (!isRecord6(response) || !isRecord6(response["models"])) {
24533
+ return {};
24534
+ }
24535
+ return response["models"];
24536
+ }
24537
+ function legacyModelOptions(response) {
24538
+ const options = legacyOptions(response);
24539
+ const models = modelsRecord(response);
24540
+ const values = [];
24541
+ for (const option of options) {
24542
+ if (option["category"] === "model") {
24543
+ const value = legacyValue(option);
24544
+ if (value.value.length > 0 && !values.some((existing) => existing.value === value.value)) {
24545
+ values.push(value);
24546
+ }
24547
+ }
24548
+ }
24549
+ if (values.length === 0 && Array.isArray(models["availableModels"])) {
24550
+ for (const model of models["availableModels"]) {
24551
+ if (!isRecord6(model)) {
24552
+ continue;
24553
+ }
24554
+ const value = readString2(model["modelId"]).slice(0, 500);
24555
+ if (value.length === 0) {
24556
+ continue;
24557
+ }
24558
+ if (!values.some((existing) => existing.value === value)) {
24559
+ values.push({
24560
+ description: "",
24561
+ groupId: "",
24562
+ groupName: "",
24563
+ name: readString2(model["name"], value).slice(0, 255),
24564
+ value
24565
+ });
24566
+ }
24567
+ }
24568
+ }
24569
+ const selected = options.find(
24570
+ (option) => option["category"] === "model" && option["selected"] === true
24571
+ );
24572
+ const currentValue = readString2(
24573
+ models["currentModelId"],
24574
+ selected === void 0 ? "" : readString2(selected["id"])
24575
+ ).slice(0, 500);
24576
+ if (values.length === 0 || !values.some((value) => value.value === currentValue)) {
24577
+ return [];
24578
+ }
24579
+ const result = {
24580
+ booleanValue: false,
24581
+ category: "model",
24582
+ currentValue,
24583
+ description: "Model used by Grok Build",
24584
+ id: LEGACY_MODEL_CONFIG_ID,
24585
+ name: "Model",
24586
+ type: "select",
24587
+ values: values.slice(0, 500)
24588
+ };
24589
+ return [result];
24590
+ }
24591
+ function legacyReasoningEffortOptions(response) {
24592
+ const options = legacyOptions(response);
24593
+ const values = [];
24594
+ for (const option of options) {
24595
+ if (option["category"] !== "mode") {
24596
+ continue;
24597
+ }
24598
+ const value = legacyValue(option);
24599
+ if (value.value.length > 0 && !values.some((existing) => existing.value === value.value)) {
24600
+ values.push(value);
24601
+ }
24602
+ }
24603
+ if (values.length === 0) {
24604
+ return [];
24605
+ }
24606
+ const selected = options.find(
24607
+ (option) => option["category"] === "mode" && option["selected"] === true
24608
+ );
24609
+ if (selected === void 0) {
24610
+ values.unshift({
24611
+ description: "Use the selected model's default reasoning effort",
24612
+ groupId: "",
24613
+ groupName: "",
24614
+ name: "Agent default",
24615
+ value: AGENT_DEFAULT_REASONING_EFFORT
24616
+ });
24617
+ }
24618
+ const currentValue = selected === void 0 ? AGENT_DEFAULT_REASONING_EFFORT : readString2(selected["id"], AGENT_DEFAULT_REASONING_EFFORT);
24619
+ if (!values.some((value) => value.value === currentValue)) {
24620
+ return [];
24621
+ }
24622
+ const result = {
24623
+ booleanValue: false,
24624
+ category: "thought_level",
24625
+ currentValue,
24626
+ description: "Reasoning effort used by Grok Build",
24627
+ id: LEGACY_REASONING_EFFORT_CONFIG_ID,
24628
+ name: "Reasoning effort",
24629
+ type: "select",
24630
+ values: values.slice(0, 500)
24631
+ };
24632
+ return [result];
24633
+ }
24634
+ function normalizeGrokLifecycle(response) {
24635
+ const lifecycle = isRecord6(response) ? response : {};
24636
+ const standard = normalizeConfigOptions(
24637
+ lifecycle["configOptions"],
24638
+ lifecycle["modes"]
24639
+ );
24640
+ const normalized = [...standard];
24641
+ if (!normalized.some((option) => option.category === "model")) {
24642
+ normalized.push(...legacyModelOptions(response));
24643
+ }
24644
+ if (!normalized.some((option) => option.category === "thought_level")) {
24645
+ const efforts = legacyReasoningEffortOptions(response);
24646
+ if (efforts.length > 0) {
24647
+ const modelIndex = normalized.findIndex(
24648
+ (option) => option.category === "model"
24649
+ );
24650
+ normalized.splice(
24651
+ modelIndex < 0 ? normalized.length : modelIndex + 1,
24652
+ 0,
24653
+ ...efforts
24654
+ );
24655
+ }
24656
+ }
24657
+ return ensureReasoningEffortOption(normalized.slice(0, 100));
24658
+ }
24659
+ function updateCurrentValue2(current, category, value) {
24660
+ return current.map(
24661
+ (option) => option.category === category ? { ...option, currentValue: value } : option
24662
+ );
24663
+ }
24664
+ function validateGrokResponse(response, modelId) {
24665
+ if (!isRecord6(response) || !isRecord6(response["_meta"])) {
24666
+ throw new SessionConfigProtocolError(
24667
+ "Grok Build returned an invalid session configuration response"
24668
+ );
24669
+ }
24670
+ const model = response["_meta"]["model"];
24671
+ const appliedModel = isRecord6(model) ? model["Ok"] : model;
24672
+ if (appliedModel !== modelId) {
24673
+ throw new SessionConfigProtocolError(
24674
+ "Grok Build returned an invalid session configuration response"
24675
+ );
24676
+ }
24677
+ }
24678
+ var GrokBuildSessionConfigProtocol = class {
24679
+ configure = async (current, change, nativeSessionId, transport) => {
24680
+ const existing = current.find((option) => option.id === change.configId);
24681
+ if (existing === void 0 || existing.id !== LEGACY_MODEL_CONFIG_ID && existing.id !== LEGACY_REASONING_EFFORT_CONFIG_ID) {
24682
+ return await standardSessionConfigProtocol.configure(
24683
+ current,
24684
+ change,
24685
+ nativeSessionId,
24686
+ transport
24687
+ );
24688
+ }
24689
+ const model = current.find((option) => option.category === "model");
24690
+ if (model === void 0) {
24691
+ return current;
24692
+ }
24693
+ if (existing.category === "thought_level" && change.value === AGENT_DEFAULT_REASONING_EFFORT) {
24694
+ return current;
24695
+ }
24696
+ const modelId = existing.category === "model" ? change.value : model.currentValue;
24697
+ const params = {
24698
+ modelId,
24699
+ sessionId: nativeSessionId
24700
+ };
24701
+ if (existing.category === "thought_level") {
24702
+ params["_meta"] = {
24703
+ reasoningEffort: change.value
24704
+ };
24705
+ }
24706
+ const response = await transport.request(
24707
+ "session/set_model",
24708
+ params,
24709
+ existing.category === "model" ? "Grok Build exited while setting the session model" : "Grok Build exited while setting reasoning effort",
24710
+ change.signal
24711
+ );
24712
+ validateGrokResponse(response, modelId);
24713
+ const updated = updateCurrentValue2(
24714
+ current,
24715
+ existing.category,
24716
+ change.value
24717
+ );
24718
+ return existing.category === "thought_level" ? updated.map(
24719
+ (option) => option.category === "thought_level" ? {
24720
+ ...option,
24721
+ values: option.values.filter(
24722
+ (value) => value.value !== AGENT_DEFAULT_REASONING_EFFORT
24723
+ )
24724
+ } : option
24725
+ ) : updated;
24726
+ };
24727
+ normalizeLifecycle = (response) => normalizeGrokLifecycle(response);
24728
+ normalizeUpdate = (current, value) => standardSessionConfigProtocol.normalizeUpdate(current, value);
24729
+ };
24730
+ var grokBuildSessionConfigProtocol = new GrokBuildSessionConfigProtocol();
24731
+
24732
+ // src/acp/session-config/session-config-registry.ts
24733
+ function sessionConfigProtocolForAgent(agentId) {
24734
+ return agentId === "grok-build" ? grokBuildSessionConfigProtocol : standardSessionConfigProtocol;
24735
+ }
24736
+
24737
+ // src/acp/session-history.ts
24738
+ var AcpHistoryReplay = class {
24739
+ #messages = [];
24740
+ #lastMessageId = null;
24741
+ #characters = 0;
24742
+ #imageCharacters = 0;
24743
+ #truncated = false;
24744
+ record = (update) => {
24745
+ if (update.sessionUpdate !== "user_message_chunk" && update.sessionUpdate !== "agent_message_chunk")
24746
+ return;
24747
+ if (update.sessionUpdate === "agent_message_chunk" && isProgressMessage(update))
24748
+ return;
24749
+ const role = update.sessionUpdate === "user_message_chunk" ? "user" : "assistant";
24750
+ const content = update.content;
24751
+ const parsed = parseNativeHistoryText(
24752
+ content.type === "text" ? content.text : content.type === "image" ? `[@image](data:${content.mimeType};base64,${content.data})` : `[${content.type} attachment]`
24753
+ );
24754
+ const text = parsed.text;
24755
+ if (text.length === 0 && parsed.images.length === 0) return;
24756
+ const previous = this.#messages.at(-1);
24757
+ const id = update.messageId ?? null;
24758
+ const continuation = previous?.role === role && id === this.#lastMessageId;
24759
+ const combined = continuation ? `${previous.text}${text}` : text;
24760
+ const allImages = continuation ? [...previous.images ?? [], ...parsed.images] : parsed.images;
24761
+ const images = allImages.slice(0, 8);
24762
+ this.#truncated ||= images.length < allImages.length;
24763
+ if (continuation) {
24764
+ this.#messages.pop();
24765
+ this.#characters -= previous.text.length;
24766
+ this.#imageCharacters -= (previous.images ?? []).reduce(
24767
+ (size, image) => size + image.data.length,
24768
+ 0
24769
+ );
24565
24770
  }
24566
24771
  const bounded = combined.slice(-SESSION_HISTORY_CHARACTER_LIMIT);
24567
24772
  this.#truncated ||= bounded.length < combined.length;
@@ -24633,7 +24838,7 @@ var FoundAcpStoredSession = class extends AcpStoredSessionLookup {
24633
24838
  var DeletedAcpStoredSession = class extends AcpStoredSessionLookup {
24634
24839
  found = false;
24635
24840
  };
24636
- function readString2(value, field) {
24841
+ function readString3(value, field) {
24637
24842
  if (typeof value !== "string" || value.length === 0) {
24638
24843
  throw new Error(`Stored ACP session has an invalid ${field}`);
24639
24844
  }
@@ -24663,10 +24868,10 @@ function decodeSessionRow(row) {
24663
24868
  throw new Error("Stored ACP session is not an object");
24664
24869
  }
24665
24870
  return new AcpStoredSession(
24666
- readString2(Reflect.get(row, "session_id"), "session ID"),
24667
- readString2(Reflect.get(row, "agent_id"), "agent ID"),
24668
- readString2(Reflect.get(row, "native_session_id"), "native session ID"),
24669
- readString2(Reflect.get(row, "cwd"), "working directory"),
24871
+ readString3(Reflect.get(row, "session_id"), "session ID"),
24872
+ readString3(Reflect.get(row, "agent_id"), "agent ID"),
24873
+ readString3(Reflect.get(row, "native_session_id"), "native session ID"),
24874
+ readString3(Reflect.get(row, "cwd"), "working directory"),
24670
24875
  readAdditionalDirectories(Reflect.get(row, "additional_directories_json")),
24671
24876
  readPrompted(Reflect.get(row, "prompted"))
24672
24877
  );
@@ -24928,168 +25133,37 @@ function createWritableAcpStream(output2) {
24928
25133
  }
24929
25134
  });
24930
25135
  }
24931
- function truncate2(value, maximumLength) {
25136
+ function truncate3(value, maximumLength) {
24932
25137
  return value.length <= maximumLength ? value : `${value.slice(0, Math.max(0, maximumLength - 1))}\u2026`;
24933
25138
  }
24934
- function isRecord6(value) {
25139
+ function isRecord7(value) {
24935
25140
  return typeof value === "object" && value !== null && !Array.isArray(value);
24936
25141
  }
24937
- function readString3(value, fallback = "") {
25142
+ function readString4(value, fallback = "") {
24938
25143
  return typeof value === "string" ? value : fallback;
24939
25144
  }
24940
- function readBoolean(value, fallback = false) {
24941
- return typeof value === "boolean" ? value : fallback;
24942
- }
24943
25145
  function arraysEqual(left, right) {
24944
25146
  return left.length === right.length && left.every((value, index) => value === right[index]);
24945
25147
  }
24946
- function normalizeConfigValue(option, groupId = "", groupName = "") {
25148
+ function normalizeCapabilities(capabilities) {
25149
+ const session = capabilities.sessionCapabilities;
25150
+ const prompt = capabilities.promptCapabilities;
24947
25151
  return {
24948
- description: truncate2(readString3(option["description"]), 500),
24949
- groupId: truncate2(groupId, 128),
24950
- groupName: truncate2(groupName, 255),
24951
- name: truncate2(
24952
- readString3(option["name"], readString3(option["value"])),
24953
- 255
24954
- ),
24955
- value: truncate2(readString3(option["value"]), 500)
25152
+ additionalDirectories: session?.additionalDirectories != null,
25153
+ audioPrompt: prompt?.audio === true,
25154
+ closeSession: session?.close != null,
25155
+ deleteSession: session?.delete != null,
25156
+ embeddedContextPrompt: prompt?.embeddedContext === true,
25157
+ imagePrompt: prompt?.image === true,
25158
+ listSessions: session?.list != null,
25159
+ loadSession: capabilities.loadSession === true,
25160
+ resumeSession: session?.resume != null,
25161
+ unstableForkSession: session?.fork != null
24956
25162
  };
24957
25163
  }
24958
- function normalizeConfigValues(value) {
24959
- if (!Array.isArray(value)) {
24960
- return [];
24961
- }
24962
- const normalized = [];
24963
- for (const entry of value) {
24964
- if (!isRecord6(entry)) {
24965
- continue;
24966
- }
24967
- const groupedOptions = entry["options"];
24968
- if (Array.isArray(groupedOptions)) {
24969
- const groupId = readString3(entry["group"]);
24970
- const groupName = readString3(entry["name"]);
24971
- for (const groupedOption of groupedOptions) {
24972
- if (isRecord6(groupedOption)) {
24973
- normalized.push(
24974
- normalizeConfigValue(groupedOption, groupId, groupName)
24975
- );
24976
- }
24977
- }
24978
- continue;
24979
- }
24980
- normalized.push(normalizeConfigValue(entry));
24981
- }
24982
- return normalized.filter((entry) => entry.value.length > 0).slice(0, 500);
24983
- }
24984
- function normalizeConfigOptions(value, modes) {
24985
- const normalized = [];
24986
- if (Array.isArray(value)) {
24987
- for (const option of value) {
24988
- if (!isRecord6(option)) {
24989
- continue;
24990
- }
24991
- const id = truncate2(readString3(option["id"]), 128);
24992
- const name = truncate2(readString3(option["name"], id), 255);
24993
- if (id.length === 0 || name.length === 0) {
24994
- continue;
24995
- }
24996
- if (option["type"] === "boolean") {
24997
- normalized.push({
24998
- booleanValue: readBoolean(option["currentValue"]),
24999
- category: truncate2(readString3(option["category"]), 128),
25000
- currentValue: "",
25001
- description: truncate2(readString3(option["description"]), 500),
25002
- id,
25003
- name,
25004
- type: "boolean",
25005
- values: []
25006
- });
25007
- continue;
25008
- }
25009
- if (option["type"] === "select") {
25010
- const values = normalizeConfigValues(option["options"]);
25011
- const currentValue = truncate2(readString3(option["currentValue"]), 500);
25012
- if (currentValue.length > 0 && values.some((entry) => entry.value === currentValue)) {
25013
- normalized.push({
25014
- booleanValue: false,
25015
- category: truncate2(readString3(option["category"]), 128),
25016
- currentValue,
25017
- description: truncate2(readString3(option["description"]), 500),
25018
- id,
25019
- name,
25020
- type: "select",
25021
- values
25022
- });
25023
- }
25024
- }
25025
- }
25026
- }
25027
- if (isRecord6(modes)) {
25028
- const values = [];
25029
- const availableModes = modes["availableModes"];
25030
- if (Array.isArray(availableModes)) {
25031
- for (const mode of availableModes) {
25032
- if (!isRecord6(mode)) {
25033
- continue;
25034
- }
25035
- const id = truncate2(readString3(mode["id"]), 500);
25036
- if (id.length === 0) {
25037
- continue;
25038
- }
25039
- values.push({
25040
- description: truncate2(readString3(mode["description"]), 500),
25041
- groupId: "",
25042
- groupName: "",
25043
- name: truncate2(readString3(mode["name"], id), 255),
25044
- value: id
25045
- });
25046
- }
25047
- }
25048
- const currentValue = truncate2(readString3(modes["currentModeId"]), 500);
25049
- if (currentValue.length > 0 && values.some((entry) => entry.value === currentValue) && !normalized.some((entry) => entry.category === "mode")) {
25050
- normalized.unshift({
25051
- booleanValue: false,
25052
- category: "mode",
25053
- currentValue,
25054
- description: "Agent session mode",
25055
- id: "mode",
25056
- name: "Mode",
25057
- type: "select",
25058
- values
25059
- });
25060
- }
25061
- }
25062
- return normalized.slice(0, 100);
25063
- }
25064
- function replaceConfigOptionsKeepingMode(current, value) {
25065
- const next = normalizeConfigOptions(value, void 0);
25066
- if (next.some((option) => option.category === "mode")) {
25067
- return next;
25068
- }
25069
- return [
25070
- ...current.filter((option) => option.category === "mode"),
25071
- ...next
25072
- ].slice(0, 100);
25073
- }
25074
- function normalizeCapabilities(capabilities) {
25075
- const session = capabilities.sessionCapabilities;
25076
- const prompt = capabilities.promptCapabilities;
25077
- return {
25078
- additionalDirectories: session?.additionalDirectories != null,
25079
- audioPrompt: prompt?.audio === true,
25080
- closeSession: session?.close != null,
25081
- deleteSession: session?.delete != null,
25082
- embeddedContextPrompt: prompt?.embeddedContext === true,
25083
- imagePrompt: prompt?.image === true,
25084
- listSessions: session?.list != null,
25085
- loadSession: capabilities.loadSession === true,
25086
- resumeSession: session?.resume != null,
25087
- unstableForkSession: session?.fork != null
25088
- };
25089
- }
25090
- function elicitationFieldType(value) {
25091
- if (value === "boolean") {
25092
- return "boolean";
25164
+ function elicitationFieldType(value) {
25165
+ if (value === "boolean") {
25166
+ return "boolean";
25093
25167
  }
25094
25168
  if (value === "integer") {
25095
25169
  return "integer";
@@ -25107,11 +25181,11 @@ function normalizeElicitationOptions(schema) {
25107
25181
  const oneOf = schema["oneOf"];
25108
25182
  if (Array.isArray(oneOf)) {
25109
25183
  for (const option of oneOf) {
25110
- if (isRecord6(option) && typeof option["const"] === "string") {
25184
+ if (isRecord7(option) && typeof option["const"] === "string") {
25111
25185
  normalized.push({
25112
- description: truncate2(readString3(option["description"]), 500),
25113
- label: truncate2(readString3(option["title"], option["const"]), 255),
25114
- value: truncate2(option["const"], 500)
25186
+ description: truncate3(readString4(option["description"]), 500),
25187
+ label: truncate3(readString4(option["title"], option["const"]), 255),
25188
+ value: truncate3(option["const"], 500)
25115
25189
  });
25116
25190
  }
25117
25191
  }
@@ -25127,7 +25201,7 @@ function normalizeElicitationOptions(schema) {
25127
25201
  return normalized.slice(0, 200);
25128
25202
  }
25129
25203
  const items = schema["items"];
25130
- if (!isRecord6(items)) {
25204
+ if (!isRecord7(items)) {
25131
25205
  return normalized;
25132
25206
  }
25133
25207
  const anyOf = items["anyOf"];
@@ -25140,7 +25214,7 @@ function numericString(value) {
25140
25214
  return typeof value === "number" && Number.isFinite(value) ? value.toString() : "";
25141
25215
  }
25142
25216
  function normalizeElicitationFields(requestedSchema) {
25143
- if (!isRecord6(requestedSchema) || !isRecord6(requestedSchema["properties"])) {
25217
+ if (!isRecord7(requestedSchema) || !isRecord7(requestedSchema["properties"])) {
25144
25218
  return [];
25145
25219
  }
25146
25220
  const properties = requestedSchema["properties"];
@@ -25150,7 +25224,7 @@ function normalizeElicitationFields(requestedSchema) {
25150
25224
  );
25151
25225
  const normalized = [];
25152
25226
  for (const [name, property] of Object.entries(properties)) {
25153
- if (!isRecord6(property)) {
25227
+ if (!isRecord7(property)) {
25154
25228
  continue;
25155
25229
  }
25156
25230
  const type = elicitationFieldType(property["type"]);
@@ -25160,9 +25234,9 @@ function normalizeElicitationFields(requestedSchema) {
25160
25234
  normalized.push({
25161
25235
  defaultBooleanValue: typeof defaultValue === "boolean" ? defaultValue : false,
25162
25236
  defaultNumberValue: typeof defaultValue === "number" && Number.isFinite(defaultValue) ? defaultValue : 0,
25163
- defaultStringValue: typeof defaultValue === "string" ? truncate2(defaultValue, 1e4) : Array.isArray(defaultValue) ? truncate2(JSON.stringify(defaultValue), 1e4) : "",
25164
- description: truncate2(readString3(property["description"]), 500),
25165
- format: truncate2(readString3(property["format"]), 64),
25237
+ defaultStringValue: typeof defaultValue === "string" ? truncate3(defaultValue, 1e4) : Array.isArray(defaultValue) ? truncate3(JSON.stringify(defaultValue), 1e4) : "",
25238
+ description: truncate3(readString4(property["description"]), 500),
25239
+ format: truncate3(readString4(property["format"]), 64),
25166
25240
  hasDefaultValue: defaultValue !== void 0 && defaultValue !== null,
25167
25241
  maximum: numericString(property["maximum"]),
25168
25242
  maximumLength: numericString(
@@ -25172,11 +25246,11 @@ function normalizeElicitationFields(requestedSchema) {
25172
25246
  minimumLength: numericString(
25173
25247
  property["minLength"] ?? property["minItems"]
25174
25248
  ),
25175
- name: truncate2(name, 128),
25249
+ name: truncate3(name, 128),
25176
25250
  options,
25177
- pattern: truncate2(readString3(property["pattern"]), 500),
25251
+ pattern: truncate3(readString4(property["pattern"]), 500),
25178
25252
  required: required2.has(name),
25179
- title: truncate2(readString3(property["title"], name), 255),
25253
+ title: truncate3(readString4(property["title"], name), 255),
25180
25254
  type: normalizedType
25181
25255
  });
25182
25256
  }
@@ -25245,7 +25319,7 @@ function validateElicitationContent(encoded, requestedSchema) {
25245
25319
  "invalid_elicitation_response"
25246
25320
  );
25247
25321
  }
25248
- if (!isRecord6(decoded) || !isRecord6(requestedSchema) || !isRecord6(requestedSchema["properties"])) {
25322
+ if (!isRecord7(decoded) || !isRecord7(requestedSchema) || !isRecord7(requestedSchema["properties"])) {
25249
25323
  throw new AcpExecutionError(
25250
25324
  "Elicitation response does not match the requested form",
25251
25325
  {},
@@ -25269,7 +25343,7 @@ function validateElicitationContent(encoded, requestedSchema) {
25269
25343
  const validated = {};
25270
25344
  for (const [name, value] of Object.entries(decoded)) {
25271
25345
  const property = properties[name];
25272
- if (!isRecord6(property)) {
25346
+ if (!isRecord7(property)) {
25273
25347
  throw new AcpExecutionError(
25274
25348
  `Elicitation field ${name} was not requested`,
25275
25349
  {},
@@ -25421,6 +25495,7 @@ var AcpProcessSession = class _AcpProcessSession {
25421
25495
  #pendingPermissions = /* @__PURE__ */ new Map();
25422
25496
  #preSessionUpdates = [];
25423
25497
  #processExit;
25498
+ #sessionConfigProtocol;
25424
25499
  #store;
25425
25500
  #verifiedAgentVersion;
25426
25501
  #preSessionUpdateBytes = 0;
@@ -25439,6 +25514,7 @@ var AcpProcessSession = class _AcpProcessSession {
25439
25514
  unstableForkSession: false
25440
25515
  };
25441
25516
  #commands = [];
25517
+ #configRevision = 0;
25442
25518
  #configOptions = [];
25443
25519
  #nativeSessionId = "";
25444
25520
  #prompted = false;
@@ -25456,6 +25532,7 @@ var AcpProcessSession = class _AcpProcessSession {
25456
25532
  this.#cwd = cwd;
25457
25533
  this.#getObserver = getObserver;
25458
25534
  this.#mobiusSessionId = mobiusSessionId;
25535
+ this.#sessionConfigProtocol = sessionConfigProtocolForAgent(agent.id);
25459
25536
  this.#store = store;
25460
25537
  this.#verifiedAgentVersion = agent.agentVersion;
25461
25538
  this.#child = spawn3(agent.adapterPath, [...agent.arguments], {
@@ -25560,7 +25637,7 @@ var AcpProcessSession = class _AcpProcessSession {
25560
25637
  try {
25561
25638
  await this.race(
25562
25639
  this.#connection.agent.request(
25563
- methods5.agent.session.load,
25640
+ methods6.agent.session.load,
25564
25641
  {
25565
25642
  additionalDirectories: [...this.#additionalDirectories],
25566
25643
  cwd: this.#cwd,
@@ -25582,7 +25659,7 @@ var AcpProcessSession = class _AcpProcessSession {
25582
25659
  async #initializeAgent(signal) {
25583
25660
  const initialized = await this.race(
25584
25661
  this.#connection.agent.request(
25585
- methods5.agent.initialize,
25662
+ methods6.agent.initialize,
25586
25663
  {
25587
25664
  clientCapabilities: {
25588
25665
  elicitation: { form: {}, url: {} },
@@ -25609,11 +25686,11 @@ var AcpProcessSession = class _AcpProcessSession {
25609
25686
  }
25610
25687
  const capabilities = initialized.agentCapabilities ?? {};
25611
25688
  this.#capabilities = normalizeCapabilities(capabilities);
25612
- this.#agentName = truncate2(
25689
+ this.#agentName = truncate3(
25613
25690
  initialized.agentInfo?.title ?? initialized.agentInfo?.name ?? this.#agentId,
25614
25691
  255
25615
25692
  );
25616
- this.#agentVersion = truncate2(
25693
+ this.#agentVersion = truncate3(
25617
25694
  this.#verifiedAgentVersion.length > 0 ? this.#verifiedAgentVersion : initialized.agentInfo?.version ?? "",
25618
25695
  128
25619
25696
  );
@@ -25650,7 +25727,7 @@ var AcpProcessSession = class _AcpProcessSession {
25650
25727
  );
25651
25728
  const forked = await this.race(
25652
25729
  this.#connection.agent.request(
25653
- methods5.agent.session.fork,
25730
+ methods6.agent.session.fork,
25654
25731
  {
25655
25732
  sessionId: nativeSessionIdSchema.parse(origin.nativeSessionId),
25656
25733
  cwd: this.#cwd,
@@ -25683,7 +25760,7 @@ var AcpProcessSession = class _AcpProcessSession {
25683
25760
  if (this.#capabilities.resumeSession) {
25684
25761
  lifecycleResponse = await this.race(
25685
25762
  this.#connection.agent.request(
25686
- methods5.agent.session.resume,
25763
+ methods6.agent.session.resume,
25687
25764
  {
25688
25765
  additionalDirectories: [...this.#additionalDirectories],
25689
25766
  cwd: this.#cwd,
@@ -25700,7 +25777,7 @@ var AcpProcessSession = class _AcpProcessSession {
25700
25777
  try {
25701
25778
  lifecycleResponse = await this.race(
25702
25779
  this.#connection.agent.request(
25703
- methods5.agent.session.load,
25780
+ methods6.agent.session.load,
25704
25781
  {
25705
25782
  additionalDirectories: [...this.#additionalDirectories],
25706
25783
  cwd: this.#cwd,
@@ -25736,7 +25813,7 @@ var AcpProcessSession = class _AcpProcessSession {
25736
25813
  }
25737
25814
  const created = await this.race(
25738
25815
  this.#connection.agent.request(
25739
- methods5.agent.session.new,
25816
+ methods6.agent.session.new,
25740
25817
  {
25741
25818
  additionalDirectories: [...this.#additionalDirectories],
25742
25819
  cwd: this.#cwd,
@@ -25750,11 +25827,7 @@ var AcpProcessSession = class _AcpProcessSession {
25750
25827
  this.selectNativeSession(created.sessionId);
25751
25828
  lifecycleResponse = created;
25752
25829
  }
25753
- const lifecycleRecord = isRecord6(lifecycleResponse) ? lifecycleResponse : {};
25754
- this.#configOptions = normalizeConfigOptions(
25755
- lifecycleRecord["configOptions"],
25756
- lifecycleRecord["modes"]
25757
- );
25830
+ this.#configOptions = this.#sessionConfigProtocol.normalizeLifecycle(lifecycleResponse);
25758
25831
  await this.#updateTail;
25759
25832
  signal.throwIfAborted();
25760
25833
  if (this.#prompted) {
@@ -25779,7 +25852,7 @@ var AcpProcessSession = class _AcpProcessSession {
25779
25852
  );
25780
25853
  const response = await this.race(
25781
25854
  this.#connection.agent.request(
25782
- methods5.agent.session.list,
25855
+ methods6.agent.session.list,
25783
25856
  cursor === null ? {} : { cursor },
25784
25857
  { cancellationSignal: signal }
25785
25858
  ),
@@ -25804,7 +25877,7 @@ var AcpProcessSession = class _AcpProcessSession {
25804
25877
  );
25805
25878
  await this.race(
25806
25879
  this.#connection.agent.request(
25807
- methods5.agent.session.delete,
25880
+ methods6.agent.session.delete,
25808
25881
  { sessionId: nativeSessionIdSchema.parse(nativeSessionId) },
25809
25882
  { cancellationSignal: signal }
25810
25883
  ),
@@ -25825,64 +25898,50 @@ var AcpProcessSession = class _AcpProcessSession {
25825
25898
  );
25826
25899
  }
25827
25900
  if (existing.type === "select") {
25828
- if (!existing.values.some((entry) => entry.value === options.value)) {
25901
+ if (existing.values.length < 2) {
25829
25902
  throw new AcpExecutionError(
25830
- "The requested ACP configuration value is unavailable",
25903
+ "The requested ACP configuration option is unavailable",
25831
25904
  {},
25832
25905
  "invalid_session_configuration"
25833
25906
  );
25834
25907
  }
25835
- if (existing.category === "mode") {
25836
- await this.race(
25837
- this.#connection.agent.request(
25838
- methods5.agent.session.setMode,
25839
- { modeId: options.value, sessionId: this.#nativeSessionId },
25840
- { cancellationSignal: options.signal }
25841
- ),
25842
- "ACP agent exited while setting the session mode",
25843
- options.signal
25844
- );
25845
- this.#configOptions = this.#configOptions.map(
25846
- (option) => option.id === existing.id ? { ...option, currentValue: options.value } : option
25847
- );
25848
- } else {
25849
- const response = await this.race(
25850
- this.#connection.agent.request(
25851
- methods5.agent.session.setConfigOption,
25852
- {
25853
- configId: existing.id,
25854
- sessionId: this.#nativeSessionId,
25855
- value: options.value
25856
- },
25857
- { cancellationSignal: options.signal }
25858
- ),
25859
- "ACP agent exited while changing session configuration",
25860
- options.signal
25861
- );
25862
- this.#configOptions = replaceConfigOptionsKeepingMode(
25863
- this.#configOptions,
25864
- response.configOptions
25908
+ if (!existing.values.some((entry) => entry.value === options.value)) {
25909
+ throw new AcpExecutionError(
25910
+ "The requested ACP configuration value is unavailable",
25911
+ {},
25912
+ "invalid_session_configuration"
25865
25913
  );
25866
25914
  }
25867
- } else {
25868
- const response = await this.race(
25869
- this.#connection.agent.request(
25870
- methods5.agent.session.setConfigOption,
25871
- {
25872
- configId: existing.id,
25873
- sessionId: this.#nativeSessionId,
25874
- type: "boolean",
25875
- value: options.booleanValue
25876
- },
25877
- { cancellationSignal: options.signal }
25878
- ),
25879
- "ACP agent exited while changing session configuration",
25880
- options.signal
25881
- );
25882
- this.#configOptions = replaceConfigOptionsKeepingMode(
25915
+ }
25916
+ const configRevision = this.#configRevision;
25917
+ try {
25918
+ const configured = await this.#sessionConfigProtocol.configure(
25883
25919
  this.#configOptions,
25884
- response.configOptions
25920
+ options,
25921
+ this.#nativeSessionId,
25922
+ {
25923
+ request: async (method, params, failureMessage, signal) => await this.race(
25924
+ this.#connection.agent.request(method, params, {
25925
+ cancellationSignal: signal
25926
+ }),
25927
+ failureMessage,
25928
+ signal
25929
+ )
25930
+ }
25885
25931
  );
25932
+ await this.#updateTail;
25933
+ if (this.#configRevision === configRevision) {
25934
+ this.#configOptions = configured;
25935
+ }
25936
+ } catch (error61) {
25937
+ if (error61 instanceof SessionConfigProtocolError) {
25938
+ throw new AcpExecutionError(
25939
+ error61.message,
25940
+ { cause: error61 },
25941
+ error61.code
25942
+ );
25943
+ }
25944
+ throw error61;
25886
25945
  }
25887
25946
  return this.#configOptions;
25888
25947
  };
@@ -25966,7 +26025,7 @@ var AcpProcessSession = class _AcpProcessSession {
25966
26025
  try {
25967
26026
  const response = await this.race(
25968
26027
  this.#connection.agent.request(
25969
- methods5.agent.session.prompt,
26028
+ methods6.agent.session.prompt,
25970
26029
  { prompt, sessionId: this.#nativeSessionId },
25971
26030
  { cancellationSignal: options.signal }
25972
26031
  ),
@@ -26013,7 +26072,7 @@ var AcpProcessSession = class _AcpProcessSession {
26013
26072
  try {
26014
26073
  await this.cancelPendingInteractions();
26015
26074
  if (this.#turn.running) {
26016
- await this.#connection.agent.notify(methods5.agent.session.cancel, {
26075
+ await this.#connection.agent.notify(methods6.agent.session.cancel, {
26017
26076
  sessionId: this.#nativeSessionId
26018
26077
  });
26019
26078
  }
@@ -26103,8 +26162,8 @@ var AcpProcessSession = class _AcpProcessSession {
26103
26162
  const interactionId = `permission-${crypto.randomUUID()}`;
26104
26163
  const options = request.options.slice(0, 20).map((option) => ({
26105
26164
  kind: option.kind,
26106
- name: truncate2(option.name, 255),
26107
- optionId: truncate2(option.optionId, 255)
26165
+ name: truncate3(option.name, 255),
26166
+ optionId: truncate3(option.optionId, 255)
26108
26167
  }));
26109
26168
  if (options.length === 0) {
26110
26169
  throw new AcpExecutionError(
@@ -26129,9 +26188,9 @@ var AcpProcessSession = class _AcpProcessSession {
26129
26188
  kind: SESSION_PERMISSION_REQUESTED_KIND,
26130
26189
  options,
26131
26190
  sessionId: this.#mobiusSessionId,
26132
- title: truncate2(request.toolCall.title ?? "Permission required", 500),
26133
- toolCallId: truncate2(request.toolCall.toolCallId, 255),
26134
- toolKind: truncate2(request.toolCall.kind ?? "other", 64)
26191
+ title: truncate3(request.toolCall.title ?? "Permission required", 500),
26192
+ toolCallId: truncate3(request.toolCall.toolCallId, 255),
26193
+ toolKind: truncate3(request.toolCall.kind ?? "other", 64)
26135
26194
  });
26136
26195
  return await pending.completion.promise;
26137
26196
  } finally {
@@ -26160,7 +26219,7 @@ var AcpProcessSession = class _AcpProcessSession {
26160
26219
  const schemaValue = Reflect.get(request, "requestedSchema");
26161
26220
  const requestedSchema = request.mode === "form" ? schemaValue : {};
26162
26221
  const elicitationIdValue = Reflect.get(request, "elicitationId");
26163
- const elicitationId = request.mode === "url" && typeof elicitationIdValue === "string" ? truncate2(elicitationIdValue, 255) : "";
26222
+ const elicitationId = request.mode === "url" && typeof elicitationIdValue === "string" ? truncate3(elicitationIdValue, 255) : "";
26164
26223
  const pending = new PendingElicitation(
26165
26224
  interactionId,
26166
26225
  elicitationId,
@@ -26179,10 +26238,10 @@ var AcpProcessSession = class _AcpProcessSession {
26179
26238
  fields: normalizeElicitationFields(requestedSchema),
26180
26239
  interactionId,
26181
26240
  kind: SESSION_ELICITATION_REQUESTED_KIND,
26182
- message: truncate2(request.message, 2e3),
26241
+ message: truncate3(request.message, 2e3),
26183
26242
  mode: request.mode,
26184
26243
  sessionId: this.#mobiusSessionId,
26185
- url: request.mode === "url" && typeof Reflect.get(request, "url") === "string" ? truncate2(readString3(Reflect.get(request, "url")), 4096) : ""
26244
+ url: request.mode === "url" && typeof Reflect.get(request, "url") === "string" ? truncate3(readString4(Reflect.get(request, "url")), 4096) : ""
26186
26245
  });
26187
26246
  return await pending.completion.promise;
26188
26247
  } finally {
@@ -26271,7 +26330,7 @@ var AcpProcessSession = class _AcpProcessSession {
26271
26330
  content: normalizeContentBlock(update.content),
26272
26331
  contentId: `content-${crypto.randomUUID()}`,
26273
26332
  kind: AGENT_CONTENT_KIND,
26274
- messageId: truncate2(update.messageId ?? "", 255),
26333
+ messageId: truncate3(update.messageId ?? "", 255),
26275
26334
  sessionId: this.#mobiusSessionId
26276
26335
  });
26277
26336
  }
@@ -26309,9 +26368,9 @@ var AcpProcessSession = class _AcpProcessSession {
26309
26368
  }
26310
26369
  if (update.sessionUpdate === "available_commands_update") {
26311
26370
  const commands = update.availableCommands.slice(0, 500).map((command) => ({
26312
- description: truncate2(command.description, 500),
26313
- inputHint: truncate2(command.input?.hint ?? "", 255),
26314
- name: truncate2(command.name, 128)
26371
+ description: truncate3(command.description, 500),
26372
+ inputHint: truncate3(command.input?.hint ?? "", 255),
26373
+ name: truncate3(command.name, 128)
26315
26374
  })).filter((command) => command.name.length > 0);
26316
26375
  this.#commands = commands;
26317
26376
  await this.#getObserver().onCommands({
@@ -26322,10 +26381,11 @@ var AcpProcessSession = class _AcpProcessSession {
26322
26381
  return;
26323
26382
  }
26324
26383
  if (update.sessionUpdate === "config_option_update") {
26325
- this.#configOptions = replaceConfigOptionsKeepingMode(
26384
+ this.#configOptions = this.#sessionConfigProtocol.normalizeUpdate(
26326
26385
  this.#configOptions,
26327
26386
  update.configOptions
26328
26387
  );
26388
+ this.#configRevision += 1;
26329
26389
  await this.emitConfigUpdate();
26330
26390
  return;
26331
26391
  }
@@ -26333,15 +26393,16 @@ var AcpProcessSession = class _AcpProcessSession {
26333
26393
  this.#configOptions = this.#configOptions.map(
26334
26394
  (option) => option.category === "mode" ? { ...option, currentValue: update.currentModeId } : option
26335
26395
  );
26396
+ this.#configRevision += 1;
26336
26397
  await this.emitConfigUpdate();
26337
26398
  return;
26338
26399
  }
26339
26400
  if (update.sessionUpdate === "session_info_update") {
26340
26401
  if (Object.hasOwn(update, "title")) {
26341
- this.#sessionTitle = truncate2(update.title ?? "", 500);
26402
+ this.#sessionTitle = truncate3(update.title ?? "", 500);
26342
26403
  }
26343
26404
  if (Object.hasOwn(update, "updatedAt")) {
26344
- this.#sessionUpdatedAt = truncate2(update.updatedAt ?? "", 128);
26405
+ this.#sessionUpdatedAt = truncate3(update.updatedAt ?? "", 128);
26345
26406
  }
26346
26407
  await this.#getObserver().onInfo({
26347
26408
  kind: SESSION_INFO_UPDATED_KIND,
@@ -26354,7 +26415,7 @@ var AcpProcessSession = class _AcpProcessSession {
26354
26415
  if (update.sessionUpdate === "usage_update") {
26355
26416
  await this.#getObserver().onUsage({
26356
26417
  costAmount: update.cost?.amount ?? 0,
26357
- costCurrency: truncate2(update.cost?.currency ?? "", 16),
26418
+ costCurrency: truncate3(update.cost?.currency ?? "", 16),
26358
26419
  hasCost: update.cost !== void 0 && update.cost !== null,
26359
26420
  kind: SESSION_USAGE_UPDATED_KIND,
26360
26421
  sessionId: this.#mobiusSessionId,
@@ -26369,7 +26430,7 @@ var AcpProcessSession = class _AcpProcessSession {
26369
26430
  if (this.#capabilities.closeSession && this.#nativeSessionId.length > 0) {
26370
26431
  try {
26371
26432
  await this.#connection.agent.request(
26372
- methods5.agent.session.close,
26433
+ methods6.agent.session.close,
26373
26434
  { sessionId: this.#nativeSessionId },
26374
26435
  {
26375
26436
  cancellationSignal: AbortSignal.timeout(
@@ -27001,13 +27062,12 @@ async function publishAgentCatalog(config2, signal) {
27001
27062
  response = await fetch3(catalogEndpoint(config2.relayUrl), {
27002
27063
  body: JSON.stringify({
27003
27064
  agents: catalog.agents.map((agent) => ({
27065
+ agentPath: agent.agentIdentity.requestedPath,
27066
+ agentVersion: agent.agentVersion,
27004
27067
  id: agent.id,
27005
27068
  label: agent.label
27006
27069
  })),
27007
- installableAgents: catalog.installableAgents.map((agent) => ({
27008
- id: agent.id,
27009
- label: agent.label
27010
- }))
27070
+ installableAgents: catalog.installableAgents
27011
27071
  }),
27012
27072
  dispatcher: environmentProxyDispatcher,
27013
27073
  headers: { "content-type": "application/json" },
@@ -27103,7 +27163,7 @@ var InstallationJob = class {
27103
27163
  };
27104
27164
  function authorizedSpecificationFor(specifications, agentId) {
27105
27165
  for (const specification of specifications) {
27106
- if (specification.id === agentId && specification.supportsInstallation(process.platform, process.arch)) {
27166
+ if (specification.id === agentId) {
27107
27167
  return specification;
27108
27168
  }
27109
27169
  }
@@ -27115,7 +27175,7 @@ function executionFailure(error61) {
27115
27175
  }
27116
27176
  return new InstallationManagerError(
27117
27177
  "installation_failed",
27118
- "The local Agent installation failed",
27178
+ "The local Agent integration installation failed",
27119
27179
  { cause: error61 }
27120
27180
  );
27121
27181
  }
@@ -27186,7 +27246,7 @@ var AgentInstallationManager = class {
27186
27246
  command.requestId,
27187
27247
  command.agentId,
27188
27248
  "installation_in_progress",
27189
- "An installation for this Agent is already running"
27249
+ "An integration installation for this Agent is already running"
27190
27250
  );
27191
27251
  const job2 = new InstallationJob(command.requestId, command.agentId);
27192
27252
  job2.state = busy;
@@ -27223,7 +27283,7 @@ var AgentInstallationManager = class {
27223
27283
  job.requestId,
27224
27284
  job.agentId
27225
27285
  );
27226
- job.controller.abort(new Error("Agent installation cancelled"));
27286
+ job.controller.abort(new Error("Agent integration installation cancelled"));
27227
27287
  return await job.completion.promise;
27228
27288
  };
27229
27289
  close = async () => {
@@ -27233,7 +27293,7 @@ var AgentInstallationManager = class {
27233
27293
  if (job === void 0) {
27234
27294
  throw new InstallationManagerError(
27235
27295
  "installation_state_invalid",
27236
- "An active Agent installation is unavailable"
27296
+ "An active Agent integration installation is unavailable"
27237
27297
  );
27238
27298
  }
27239
27299
  job.controller.abort(new Error("Mobius daemon stopped"));
@@ -27246,919 +27306,108 @@ var AgentInstallationManager = class {
27246
27306
  await this.#observer.onState(state);
27247
27307
  };
27248
27308
  #run = async (job, specification, externalSignal) => {
27249
- const abort = () => job.controller.abort(externalSignal.reason);
27250
- externalSignal.addEventListener("abort", abort, { once: true });
27251
- if (externalSignal.aborted) {
27252
- abort();
27253
- }
27254
- const deadline = setTimeout(() => {
27255
- job.controller.abort(
27256
- new InstallationManagerError(
27257
- "installation_timeout",
27258
- "The local Agent installation exceeded its deadline"
27259
- )
27260
- );
27261
- }, INSTALLATION_DEADLINE_MILLISECONDS);
27262
- const signal = job.controller.signal;
27263
- try {
27264
- signal.throwIfAborted();
27265
- this.#audit.record(
27266
- "agent_installation_authorized",
27267
- job.requestId,
27268
- specification.id
27269
- );
27270
- await this.#executor.execute(
27271
- specification.id,
27272
- job.requestId,
27273
- async (stage) => {
27274
- signal.throwIfAborted();
27275
- await this.#transition(
27276
- job,
27277
- new RunningInstallation(job.requestId, job.agentId, stage)
27278
- );
27279
- this.#audit.record(
27280
- `agent_installation_${stage}`,
27281
- job.requestId,
27282
- job.agentId
27283
- );
27284
- },
27285
- signal
27286
- );
27287
- signal.throwIfAborted();
27288
- const succeeded = new SucceededInstallation(job.requestId, job.agentId);
27289
- await this.#transition(job, succeeded);
27290
- this.#audit.record(
27291
- "agent_installation_completed",
27292
- job.requestId,
27293
- job.agentId
27294
- );
27295
- job.completion.resolve(succeeded);
27296
- } catch (error61) {
27297
- if (signal.aborted) {
27298
- if (signal.reason instanceof InstallationManagerError && signal.reason.code === "installation_timeout") {
27299
- const timedOut = new FailedInstallation(
27300
- job.requestId,
27301
- job.agentId,
27302
- signal.reason.code,
27303
- signal.reason.message
27304
- );
27305
- await this.#transition(job, timedOut);
27306
- this.#audit.record(
27307
- "agent_installation_failed_installation_timeout",
27308
- job.requestId,
27309
- job.agentId
27310
- );
27311
- job.completion.resolve(timedOut);
27312
- return;
27313
- }
27314
- const cancelled = new CancelledInstallation(job.requestId, job.agentId);
27315
- await this.#transition(job, cancelled);
27316
- this.#audit.record(
27317
- "agent_installation_cancelled",
27318
- job.requestId,
27319
- job.agentId
27320
- );
27321
- job.completion.resolve(cancelled);
27322
- } else {
27323
- const failure = executionFailure(error61);
27324
- const failed = new FailedInstallation(
27325
- job.requestId,
27326
- job.agentId,
27327
- failure.code,
27328
- failure.message
27329
- );
27330
- await this.#transition(job, failed);
27331
- this.#audit.record(
27332
- `agent_installation_failed_${failure.code}`,
27333
- job.requestId,
27334
- job.agentId
27335
- );
27336
- job.completion.resolve(failed);
27337
- }
27338
- } finally {
27339
- clearTimeout(deadline);
27340
- externalSignal.removeEventListener("abort", abort);
27341
- if (this.#activeAgents.get(job.agentId) === job.requestId) {
27342
- this.#activeAgents.delete(job.agentId);
27343
- }
27344
- }
27345
- };
27346
- };
27347
-
27348
- // src/agent-installation/automatic-adapter-provisioner.ts
27349
- import { randomUUID as randomUUID2 } from "node:crypto";
27350
- var AUTOMATIC_ADAPTER_FAILURE_CODES = /* @__PURE__ */ new Set([
27351
- "adapter_not_found",
27352
- "adapter_probe_failed",
27353
- "adapter_probe_timeout",
27354
- "acp_incompatible"
27355
- ]);
27356
- var InstalledAutomaticAdapter = class {
27357
- executable;
27358
- requestId;
27359
- specification;
27360
- constructor(specification, requestId, executable) {
27361
- this.executable = executable;
27362
- this.requestId = requestId;
27363
- this.specification = specification;
27364
- }
27365
- };
27366
- function shouldProvisionAdapter(unavailable, options) {
27367
- return unavailable.specification instanceof BridgedAcpAgentDefinition && AUTOMATIC_ADAPTER_FAILURE_CODES.has(unavailable.code) && options.environment[unavailable.specification.adapterOverrideVariable] === void 0 && unavailable.specification.supportsInstallation(
27368
- options.platform ?? process.platform,
27369
- options.architecture ?? process.arch
27370
- );
27371
- }
27372
- function stableFailureCode(error61) {
27373
- return error61 instanceof ManagedAdapterInstallError ? error61.code : "adapter_install_failed";
27374
- }
27375
- function discoveryOptions(options, environment, signal, specifications) {
27376
- return {
27377
- ...options.architecture === void 0 ? {} : { architecture: options.architecture },
27378
- defaultWorkspace: options.defaultWorkspace,
27379
- environment,
27380
- ...options.platform === void 0 ? {} : { platform: options.platform },
27381
- signal,
27382
- specifications
27383
- };
27384
- }
27385
- var AutomaticAdapterProvisioner = class {
27386
- #adapterInstaller;
27387
- #options;
27388
- #specifications;
27389
- constructor(options, adapterInstaller, specifications = supportedLocalAgentSpecifications()) {
27390
- this.#adapterInstaller = adapterInstaller;
27391
- this.#options = options;
27392
- this.#specifications = Object.freeze([...specifications]);
27393
- }
27394
- prepare = async (signal) => {
27395
- signal.throwIfAborted();
27396
- let inventory = await discoverLocalAgentInventory(
27397
- discoveryOptions(
27398
- this.#options,
27399
- this.#options.environment,
27400
- signal,
27401
- this.#specifications
27402
- )
27403
- );
27404
- const candidates = inventory.unavailable.filter(
27405
- (unavailable) => shouldProvisionAdapter(unavailable, this.#options)
27406
- );
27407
- const attempts = [];
27408
- for (const unavailable of candidates) {
27409
- signal.throwIfAborted();
27410
- const specification = unavailable.specification;
27411
- if (!(specification instanceof BridgedAcpAgentDefinition)) {
27412
- attempts.push(null);
27413
- continue;
27414
- }
27415
- const verifiedAgent = await findVerifiedAgentExecutable(
27416
- specification,
27417
- discoveryOptions(
27418
- this.#options,
27419
- this.#options.environment,
27420
- signal,
27421
- this.#specifications
27422
- )
27423
- );
27424
- if (verifiedAgent === null) {
27425
- attempts.push(null);
27426
- continue;
27427
- }
27428
- const requestId = `automatic-adapter-${randomUUID2()}`;
27429
- this.#options.audit.record(
27430
- "agent_adapter_auto_install_started",
27431
- requestId,
27432
- specification.id,
27433
- {
27434
- agentVersion: verifiedAgent.version,
27435
- adapterVersion: specification.adapterVersion
27436
- }
27437
- );
27438
- process.stdout.write(
27439
- `Installing the pinned ACP adapter for ${specification.label}.
27440
- `
27441
- );
27442
- try {
27443
- const executable = await this.#adapterInstaller.install(
27444
- specification,
27445
- signal
27446
- );
27447
- this.#options.audit.record(
27448
- "agent_adapter_auto_install_completed",
27449
- requestId,
27450
- specification.id,
27451
- { adapterVersion: specification.adapterVersion }
27452
- );
27453
- attempts.push(
27454
- new InstalledAutomaticAdapter(specification, requestId, executable)
27455
- );
27456
- } catch (error61) {
27457
- if (signal.aborted) {
27458
- this.#options.audit.record(
27459
- "agent_adapter_auto_install_cancelled",
27460
- requestId,
27461
- specification.id
27462
- );
27463
- signal.throwIfAborted();
27464
- }
27465
- this.#options.audit.record(
27466
- "agent_adapter_auto_install_failed",
27467
- requestId,
27468
- specification.id,
27469
- { code: stableFailureCode(error61) }
27470
- );
27471
- process.stderr.write(
27472
- `The pinned ACP adapter for ${specification.label} could not be installed automatically; the daemon will continue.
27473
- `
27474
- );
27475
- attempts.push(null);
27476
- }
27477
- }
27478
- signal.throwIfAborted();
27479
- const installed = attempts.filter(
27480
- (attempt) => attempt !== null
27481
- );
27482
- if (installed.length > 0) {
27483
- const verificationEnvironment = {
27484
- ...this.#options.environment
27485
- };
27486
- for (const attempt of installed) {
27487
- verificationEnvironment[attempt.specification.adapterOverrideVariable] = attempt.executable.path;
27488
- }
27489
- inventory = await discoverLocalAgentInventory(
27490
- discoveryOptions(
27491
- this.#options,
27492
- verificationEnvironment,
27493
- signal,
27494
- this.#specifications
27495
- )
27496
- );
27497
- }
27498
- this.#options.catalog.transition(
27499
- inventory.readyAgents(),
27500
- inventory.installable
27501
- );
27502
- for (const attempt of installed) {
27503
- const available = inventory.available.find(
27504
- (candidate) => candidate instanceof AvailableAgent && candidate.specification.id === attempt.specification.id
27505
- );
27506
- if (available === void 0) {
27507
- const unavailable = inventory.unavailable.find(
27508
- (candidate) => candidate.specification.id === attempt.specification.id
27509
- );
27510
- this.#options.audit.record(
27511
- "agent_adapter_auto_install_verification_failed",
27512
- attempt.requestId,
27513
- attempt.specification.id,
27514
- { code: unavailable?.code ?? "agent_verification_failed" }
27515
- );
27516
- continue;
27517
- }
27518
- this.#options.audit.record(
27519
- "agent_adapter_auto_install_verified",
27520
- attempt.requestId,
27521
- attempt.specification.id,
27522
- {
27523
- adapterVersion: available.agent.adapterVersion,
27524
- agentVersion: available.agent.agentVersion
27525
- }
27526
- );
27527
- process.stdout.write(
27528
- `${attempt.specification.label} ACP integration is ready.
27529
- `
27530
- );
27531
- }
27532
- return inventory;
27533
- };
27534
- };
27535
-
27536
- // src/agent-installation/fixed-installation-executor.ts
27537
- import { realpathSync as realpathSync2, statSync as statSync2 } from "node:fs";
27538
- import { resolve as resolve4 } from "node:path";
27539
-
27540
- // src/agent-installation/fixed-agent-install-recipes.ts
27541
- import { mkdir as mkdir5, mkdtemp as mkdtemp3, rm as rm3 } from "node:fs/promises";
27542
- import { join as join17 } from "node:path";
27543
-
27544
- // src/agent-installation/fixed-agent-install-recipe.ts
27545
- var FixedAgentInstallRecipe = class {
27546
- assertSupportedPlatform = () => {
27547
- if (process.platform !== "darwin" && process.platform !== "linux" || process.arch !== "arm64" && process.arch !== "x64") {
27548
- throw new InstallationManagerError(
27549
- "unsupported_install_platform",
27550
- "This Agent installation recipe does not support the local platform"
27551
- );
27552
- }
27553
- };
27554
- requireInstalledExecutable = async (path2) => {
27555
- const executable = await resolveExecutablePath(path2);
27556
- if (executable === null) {
27557
- throw new InstallationManagerError(
27558
- "agent_verification_failed",
27559
- "The Agent installer did not produce a valid executable"
27560
- );
27561
- }
27562
- return executable;
27563
- };
27564
- };
27565
-
27566
- // src/agent-installation/grok-build-install-recipe.ts
27567
- import { mkdir as mkdir4, realpath as realpath7, stat as stat6 } from "node:fs/promises";
27568
- import { delimiter as delimiter2, dirname as dirname5, isAbsolute as isAbsolute7, join as join15, relative as relative4, sep as sep4 } from "node:path";
27569
- var INSTALL_TIMEOUT_MILLISECONDS2 = 5 * 60 * 1e3;
27570
- function isContainedPath4(root, candidate) {
27571
- const difference = relative4(root, candidate);
27572
- return difference.length > 0 && difference !== ".." && !difference.startsWith(`..${sep4}`) && !isAbsolute7(difference);
27573
- }
27574
- async function resolveLifecycleScript(packageRoot) {
27575
- try {
27576
- const canonicalPackageRoot = await realpath7(packageRoot);
27577
- const script = await realpath7(
27578
- join15(canonicalPackageRoot, "bin", "postinstall.js")
27579
- );
27580
- const metadata = await stat6(script);
27581
- if (!metadata.isFile() || !isContainedPath4(canonicalPackageRoot, script)) {
27582
- throw new Error("Invalid Grok Build lifecycle script");
27583
- }
27584
- return script;
27585
- } catch (error61) {
27586
- throw new InstallationManagerError(
27587
- "agent_verification_failed",
27588
- "The managed Grok Build lifecycle script is invalid",
27589
- { cause: error61 }
27590
- );
27591
- }
27592
- }
27593
- var GrokBuildInstallRecipe = class extends FixedAgentInstallRecipe {
27594
- #npmInstaller;
27595
- id = "grok-build";
27596
- label = "Grok Build";
27597
- releaseChannel = GROK_BUILD_MANAGED_VERSION;
27598
- constructor(npmInstaller = new ManagedNpmPackageInstaller()) {
27599
- super();
27600
- this.#npmInstaller = npmInstaller;
27601
- }
27602
- install = async (options) => {
27603
- this.assertSupportedPlatform();
27604
- const definition = grokBuildManagedPackage(process.platform, process.arch);
27605
- const versionRoot = join15(
27606
- options.stateDirectory,
27607
- "agents",
27608
- this.id,
27609
- GROK_BUILD_MANAGED_VERSION
27610
- );
27611
- const packageRoot = join15(versionRoot, "package");
27612
- const managedHome = join15(versionRoot, "home");
27613
- try {
27614
- await mkdir4(managedHome, { mode: 448, recursive: true });
27615
- const canonicalHome = await realpath7(managedHome);
27616
- await options.report("downloading");
27617
- await options.report("verifying");
27618
- await options.report("installing_agent");
27619
- await this.#npmInstaller.install(
27620
- packageRoot,
27621
- definition,
27622
- options.environment,
27623
- options.signal
27624
- );
27625
- options.audit.record(
27626
- "agent_npm_package_verified",
27627
- options.requestId,
27628
- this.id,
27629
- {
27630
- integrity: definition.integrity,
27631
- package: definition.packageName,
27632
- version: definition.version
27633
- }
27634
- );
27635
- const script = await resolveLifecycleScript(
27636
- join15(packageRoot, "node_modules", "@xai-official", "grok")
27637
- );
27638
- await runBoundedProcess({
27639
- arguments: [script],
27640
- command: process.execPath,
27641
- cwd: dirname5(script),
27642
- environment: {
27643
- GROK_HOME: canonicalHome,
27644
- GROK_INSTALL_COMPLETIONS: "0",
27645
- GROK_NPM_REGISTRY: "https://registry.npmjs.org/",
27646
- HOME: canonicalHome,
27647
- PATH: `${dirname5(process.execPath)}${delimiter2}/usr/bin${delimiter2}/bin`
27648
- },
27649
- outputLimitBytes: 64 * 1024,
27650
- signal: options.signal,
27651
- timeoutMilliseconds: INSTALL_TIMEOUT_MILLISECONDS2
27652
- });
27653
- options.audit.record(
27654
- "agent_lifecycle_step_completed",
27655
- options.requestId,
27656
- this.id,
27657
- {
27658
- lifecycle: "postinstall",
27659
- package: definition.packageName,
27660
- version: definition.version
27661
- }
27662
- );
27663
- return await this.requireInstalledExecutable(
27664
- join15(canonicalHome, "bin", "grok")
27665
- );
27666
- } catch (error61) {
27667
- if (options.signal.aborted) {
27668
- options.signal.throwIfAborted();
27669
- }
27670
- if (error61 instanceof ManagedNpmPackageError) {
27671
- if (error61.code === "managed_package_verification_failed") {
27672
- throw new InstallationManagerError(
27673
- "agent_verification_failed",
27674
- "The managed Grok Build packages did not match their pinned artifacts",
27675
- { cause: error61 }
27676
- );
27677
- }
27678
- if (error61.code === "managed_package_publish_failed") {
27679
- throw new InstallationManagerError(
27680
- "agent_publish_failed",
27681
- "The managed Grok Build package could not be published",
27682
- { cause: error61 }
27683
- );
27684
- }
27685
- throw new InstallationManagerError(error61.code, error61.message, {
27686
- cause: error61
27687
- });
27688
- }
27689
- if (error61 instanceof InstallationManagerError) {
27690
- throw error61;
27691
- }
27692
- throw new InstallationManagerError(
27693
- "agent_install_failed",
27694
- "The fixed Grok Build installation recipe failed",
27695
- { cause: error61 }
27696
- );
27697
- }
27698
- };
27699
- };
27700
-
27701
- // src/agent-installation/workbuddy-install-recipe.ts
27702
- import { join as join16 } from "node:path";
27703
- var WorkBuddyInstallRecipe = class extends FixedAgentInstallRecipe {
27704
- #npmInstaller;
27705
- id = "workbuddy";
27706
- label = "WorkBuddy";
27707
- releaseChannel = WORKBUDDY_MANAGED_VERSION;
27708
- constructor(npmInstaller = new ManagedNpmPackageInstaller()) {
27709
- super();
27710
- this.#npmInstaller = npmInstaller;
27711
- }
27712
- install = async (options) => {
27713
- this.assertSupportedPlatform();
27714
- try {
27715
- await options.report("downloading");
27716
- await options.report("verifying");
27717
- await options.report("installing_agent");
27718
- const executable = await this.#npmInstaller.install(
27719
- join16(
27720
- options.stateDirectory,
27721
- "agents",
27722
- this.id,
27723
- WORKBUDDY_MANAGED_VERSION
27724
- ),
27725
- WORKBUDDY_MANAGED_PACKAGE,
27726
- options.environment,
27727
- options.signal
27728
- );
27729
- options.audit.record(
27730
- "agent_npm_package_verified",
27731
- options.requestId,
27732
- this.id,
27733
- {
27734
- integrity: WORKBUDDY_MANAGED_PACKAGE.integrity,
27735
- package: WORKBUDDY_MANAGED_PACKAGE.packageName,
27736
- version: WORKBUDDY_MANAGED_PACKAGE.version
27737
- }
27738
- );
27739
- return executable;
27740
- } catch (error61) {
27741
- if (options.signal.aborted) {
27742
- options.signal.throwIfAborted();
27743
- }
27744
- if (error61 instanceof ManagedNpmPackageError) {
27745
- if (error61.code === "managed_package_verification_failed") {
27746
- throw new InstallationManagerError(
27747
- "agent_verification_failed",
27748
- "The managed WorkBuddy package did not match its pinned artifact",
27749
- { cause: error61 }
27750
- );
27751
- }
27752
- if (error61.code === "managed_package_publish_failed") {
27753
- throw new InstallationManagerError(
27754
- "agent_publish_failed",
27755
- "The managed WorkBuddy package could not be published",
27756
- { cause: error61 }
27757
- );
27758
- }
27759
- throw new InstallationManagerError(error61.code, error61.message, {
27760
- cause: error61
27761
- });
27762
- }
27763
- if (error61 instanceof InstallationManagerError) {
27764
- throw error61;
27765
- }
27766
- throw new InstallationManagerError(
27767
- "agent_install_failed",
27768
- "The fixed WorkBuddy installation recipe failed",
27769
- { cause: error61 }
27770
- );
27771
- }
27772
- };
27773
- };
27774
-
27775
- // src/agent-installation/fixed-agent-install-recipes.ts
27776
- var INSTALLER_DOWNLOAD_LIMIT_BYTES = 1024 * 1024;
27777
- var INSTALLER_DOWNLOAD_TIMEOUT_MILLISECONDS = 6e4;
27778
- var AGENT_INSTALL_TIMEOUT_MILLISECONDS = 5 * 60 * 1e3;
27779
- var MINIMAL_PATH2 = "/usr/bin:/bin";
27780
- var CodexInstallRecipe = class extends FixedAgentInstallRecipe {
27781
- id = "codex";
27782
- label = "Codex";
27783
- releaseChannel = "latest";
27784
- install = async (options) => {
27785
- this.assertSupportedPlatform();
27786
- const root = join17(options.stateDirectory, "agents", this.id);
27787
- const temporaryRoot = join17(options.stateDirectory, "temporary");
27788
- await Promise.all([
27789
- mkdir5(root, { mode: 448, recursive: true }),
27790
- mkdir5(temporaryRoot, { mode: 448, recursive: true })
27791
- ]);
27792
- const temporaryDirectory = await mkdtemp3(
27793
- join17(temporaryRoot, ".codex-install-")
27794
- );
27795
- const installerPath = join17(temporaryDirectory, "install.sh");
27796
- const installDirectory = join17(root, "bin");
27797
- const codexHome = join17(root, "home");
27798
- try {
27799
- await Promise.all([
27800
- mkdir5(installDirectory, { mode: 448, recursive: true }),
27801
- mkdir5(codexHome, { mode: 448, recursive: true })
27802
- ]);
27803
- await options.report("downloading");
27804
- const download = await downloadVerifiedFile({
27805
- allowedHosts: /* @__PURE__ */ new Set(["chatgpt.com", "releases.openai.com"]),
27806
- destination: installerPath,
27807
- maximumBytes: INSTALLER_DOWNLOAD_LIMIT_BYTES,
27808
- signal: options.signal,
27809
- timeoutMilliseconds: INSTALLER_DOWNLOAD_TIMEOUT_MILLISECONDS,
27810
- url: new URL("https://chatgpt.com/codex/install.sh")
27811
- });
27812
- options.audit.record(
27813
- "agent_installer_download_verified",
27814
- options.requestId,
27815
- this.id,
27816
- {
27817
- bytes: download.bytes.toString(),
27818
- releaseChannel: this.releaseChannel,
27819
- sha256: download.sha256
27820
- }
27821
- );
27822
- await options.report("verifying");
27823
- await options.report("installing_agent");
27824
- await runBoundedProcess({
27825
- arguments: [installerPath],
27826
- command: "/bin/sh",
27827
- cwd: temporaryDirectory,
27828
- environment: {
27829
- CODEX_HOME: codexHome,
27830
- CODEX_INSTALL_DIR: installDirectory,
27831
- CODEX_NON_INTERACTIVE: "1",
27832
- CODEX_RELEASE: this.releaseChannel,
27833
- HOME: codexHome,
27834
- PATH: MINIMAL_PATH2
27835
- },
27836
- outputLimitBytes: 64 * 1024,
27837
- signal: options.signal,
27838
- timeoutMilliseconds: AGENT_INSTALL_TIMEOUT_MILLISECONDS
27839
- });
27840
- return await this.requireInstalledExecutable(
27841
- join17(installDirectory, "codex")
27842
- );
27843
- } catch (error61) {
27844
- if (options.signal.aborted) {
27845
- options.signal.throwIfAborted();
27846
- }
27847
- if (error61 instanceof InstallationManagerError || error61 instanceof Error && "code" in error61) {
27848
- throw error61;
27849
- }
27850
- throw new InstallationManagerError(
27851
- "agent_install_failed",
27852
- "The fixed Codex installation recipe failed"
27853
- );
27854
- } finally {
27855
- await rm3(temporaryDirectory, { force: true, recursive: true });
27856
- }
27857
- };
27858
- };
27859
- var ClaudeCodeInstallRecipe = class extends FixedAgentInstallRecipe {
27860
- id = "claude";
27861
- label = "Claude Code";
27862
- releaseChannel = "stable";
27863
- install = async (options) => {
27864
- this.assertSupportedPlatform();
27865
- const root = join17(options.stateDirectory, "agents", this.id);
27866
- const managedHome = join17(root, "home");
27867
- const temporaryRoot = join17(options.stateDirectory, "temporary");
27868
- await Promise.all([
27869
- mkdir5(managedHome, { mode: 448, recursive: true }),
27870
- mkdir5(temporaryRoot, { mode: 448, recursive: true })
27871
- ]);
27872
- const temporaryDirectory = await mkdtemp3(
27873
- join17(temporaryRoot, ".claude-install-")
27874
- );
27875
- const installerPath = join17(temporaryDirectory, "install.sh");
27876
- try {
27877
- await options.report("downloading");
27878
- const download = await downloadVerifiedFile({
27879
- allowedHosts: /* @__PURE__ */ new Set(["claude.ai"]),
27880
- destination: installerPath,
27881
- maximumBytes: INSTALLER_DOWNLOAD_LIMIT_BYTES,
27882
- signal: options.signal,
27883
- timeoutMilliseconds: INSTALLER_DOWNLOAD_TIMEOUT_MILLISECONDS,
27884
- url: new URL("https://claude.ai/install.sh")
27885
- });
27886
- options.audit.record(
27887
- "agent_installer_download_verified",
27888
- options.requestId,
27889
- this.id,
27890
- {
27891
- bytes: download.bytes.toString(),
27892
- releaseChannel: this.releaseChannel,
27893
- sha256: download.sha256
27894
- }
27895
- );
27896
- await options.report("verifying");
27897
- await options.report("installing_agent");
27898
- await runBoundedProcess({
27899
- arguments: [installerPath, "stable"],
27900
- command: "/bin/bash",
27901
- cwd: temporaryDirectory,
27902
- environment: {
27903
- HOME: managedHome,
27904
- PATH: MINIMAL_PATH2,
27905
- SHELL: "/bin/bash"
27906
- },
27907
- outputLimitBytes: 64 * 1024,
27908
- signal: options.signal,
27909
- timeoutMilliseconds: AGENT_INSTALL_TIMEOUT_MILLISECONDS
27910
- });
27911
- return await this.requireInstalledExecutable(
27912
- join17(managedHome, ".local", "bin", "claude")
27913
- );
27914
- } catch (error61) {
27915
- if (options.signal.aborted) {
27916
- options.signal.throwIfAborted();
27917
- }
27918
- if (error61 instanceof InstallationManagerError || error61 instanceof Error && "code" in error61) {
27919
- throw error61;
27920
- }
27921
- throw new InstallationManagerError(
27922
- "agent_install_failed",
27923
- "The fixed Claude Code installation recipe failed"
27924
- );
27925
- } finally {
27926
- await rm3(temporaryDirectory, { force: true, recursive: true });
27927
- }
27928
- };
27929
- };
27930
- var PiInstallRecipe = class extends FixedAgentInstallRecipe {
27931
- #npmInstaller;
27932
- id = "pi";
27933
- label = "Pi";
27934
- releaseChannel = PI_AGENT_PACKAGE.version;
27935
- constructor(npmInstaller = new ManagedNpmPackageInstaller()) {
27936
- super();
27937
- this.#npmInstaller = npmInstaller;
27938
- }
27939
- install = async (options) => {
27940
- this.assertSupportedPlatform();
27941
- try {
27942
- await options.report("downloading");
27943
- await options.report("verifying");
27944
- await options.report("installing_agent");
27945
- const executable = await this.#npmInstaller.install(
27946
- join17(
27947
- options.stateDirectory,
27948
- "agents",
27949
- this.id,
27950
- PI_AGENT_PACKAGE.version
27951
- ),
27952
- PI_AGENT_PACKAGE,
27953
- options.environment,
27954
- options.signal
27955
- );
27956
- options.audit.record(
27957
- "agent_npm_package_verified",
27958
- options.requestId,
27959
- this.id,
27960
- {
27961
- integrity: PI_AGENT_PACKAGE.integrity,
27962
- package: PI_AGENT_PACKAGE.packageName,
27963
- version: PI_AGENT_PACKAGE.version
27964
- }
27965
- );
27966
- return executable;
27967
- } catch (error61) {
27968
- if (options.signal.aborted) {
27969
- options.signal.throwIfAborted();
27970
- }
27971
- if (error61 instanceof ManagedNpmPackageError) {
27972
- if (error61.code === "managed_package_verification_failed") {
27973
- throw new InstallationManagerError(
27974
- "agent_verification_failed",
27975
- "The managed Pi package did not match its pinned artifact",
27976
- { cause: error61 }
27977
- );
27978
- }
27979
- if (error61.code === "managed_package_publish_failed") {
27980
- throw new InstallationManagerError(
27981
- "agent_publish_failed",
27982
- "The managed Pi package could not be published",
27983
- { cause: error61 }
27984
- );
27985
- }
27986
- throw new InstallationManagerError(error61.code, error61.message, {
27987
- cause: error61
27988
- });
27989
- }
27990
- if (error61 instanceof InstallationManagerError) {
27991
- throw error61;
27992
- }
27993
- throw new InstallationManagerError(
27994
- "agent_install_failed",
27995
- "The fixed Pi installation recipe failed",
27996
- { cause: error61 }
27997
- );
27998
- }
27999
- };
28000
- };
28001
- var DeepSeekHarnessInstallRecipe = class extends FixedAgentInstallRecipe {
28002
- #npmInstaller;
28003
- id = "deepseek-harness";
28004
- label = "DeepSeek Harness";
28005
- releaseChannel = DEEPSEEK_HARNESS_PACKAGE.version;
28006
- constructor(npmInstaller = new ManagedNpmPackageInstaller()) {
28007
- super();
28008
- this.#npmInstaller = npmInstaller;
28009
- }
28010
- install = async (options) => {
28011
- this.assertSupportedPlatform();
28012
- try {
28013
- const managedHome = join17(
28014
- options.stateDirectory,
28015
- "agents",
28016
- this.id,
28017
- "home"
28018
- );
28019
- await mkdir5(managedHome, { mode: 448, recursive: true });
28020
- await options.report("downloading");
28021
- await options.report("verifying");
28022
- await options.report("installing_agent");
28023
- const executable = await this.#npmInstaller.install(
28024
- join17(
28025
- options.stateDirectory,
28026
- "agents",
28027
- this.id,
28028
- DEEPSEEK_HARNESS_PACKAGE.version
28029
- ),
28030
- DEEPSEEK_HARNESS_PACKAGE,
28031
- options.environment,
28032
- options.signal
28033
- );
28034
- options.audit.record(
28035
- "agent_npm_package_verified",
28036
- options.requestId,
28037
- this.id,
28038
- {
28039
- integrity: DEEPSEEK_HARNESS_PACKAGE.integrity,
28040
- package: DEEPSEEK_HARNESS_PACKAGE.packageName,
28041
- version: DEEPSEEK_HARNESS_PACKAGE.version
28042
- }
28043
- );
28044
- return executable;
28045
- } catch (error61) {
28046
- if (options.signal.aborted) {
28047
- options.signal.throwIfAborted();
28048
- }
28049
- if (error61 instanceof ManagedNpmPackageError) {
28050
- if (error61.code === "managed_package_verification_failed") {
28051
- throw new InstallationManagerError(
28052
- "agent_verification_failed",
28053
- "The managed DeepSeek Harness package did not match its pinned artifact",
28054
- { cause: error61 }
28055
- );
28056
- }
28057
- if (error61.code === "managed_package_publish_failed") {
28058
- throw new InstallationManagerError(
28059
- "agent_publish_failed",
28060
- "The managed DeepSeek Harness package could not be published",
28061
- { cause: error61 }
28062
- );
28063
- }
28064
- throw new InstallationManagerError(error61.code, error61.message, {
28065
- cause: error61
28066
- });
28067
- }
28068
- if (error61 instanceof InstallationManagerError) {
28069
- throw error61;
28070
- }
28071
- throw new InstallationManagerError(
28072
- "agent_install_failed",
28073
- "The fixed DeepSeek Harness installation recipe failed",
28074
- { cause: error61 }
28075
- );
27309
+ const abort = () => job.controller.abort(externalSignal.reason);
27310
+ externalSignal.addEventListener("abort", abort, { once: true });
27311
+ if (externalSignal.aborted) {
27312
+ abort();
28076
27313
  }
28077
- };
28078
- };
28079
- var OpenCodeInstallRecipe = class extends FixedAgentInstallRecipe {
28080
- #archiveInstaller;
28081
- id = "opencode";
28082
- label = "OpenCode";
28083
- releaseChannel = OPENCODE_MANAGED_VERSION;
28084
- constructor(archiveInstaller = new ManagedAgentArchiveInstaller()) {
28085
- super();
28086
- this.#archiveInstaller = archiveInstaller;
28087
- }
28088
- install = async (options) => {
28089
- this.assertSupportedPlatform();
28090
- const definition = openCodeManagedArchive(process.platform, process.arch);
27314
+ const deadline = setTimeout(() => {
27315
+ job.controller.abort(
27316
+ new InstallationManagerError(
27317
+ "installation_timeout",
27318
+ "The local Agent integration installation exceeded its deadline"
27319
+ )
27320
+ );
27321
+ }, INSTALLATION_DEADLINE_MILLISECONDS);
27322
+ const signal = job.controller.signal;
28091
27323
  try {
28092
- await options.report("downloading");
28093
- await options.report("verifying");
28094
- await options.report("installing_agent");
28095
- const executable = await this.#archiveInstaller.install(
28096
- join17(
28097
- options.stateDirectory,
28098
- "agents",
28099
- this.id,
28100
- OPENCODE_MANAGED_VERSION
28101
- ),
28102
- definition,
28103
- options.signal
27324
+ signal.throwIfAborted();
27325
+ this.#audit.record(
27326
+ "agent_installation_authorized",
27327
+ job.requestId,
27328
+ specification.id
28104
27329
  );
28105
- options.audit.record(
28106
- "agent_archive_verified",
28107
- options.requestId,
28108
- this.id,
28109
- {
28110
- sha256: definition.archiveSha256,
28111
- version: definition.version
28112
- }
27330
+ await this.#executor.execute(
27331
+ specification.id,
27332
+ job.requestId,
27333
+ async (stage) => {
27334
+ signal.throwIfAborted();
27335
+ await this.#transition(
27336
+ job,
27337
+ new RunningInstallation(job.requestId, job.agentId, stage)
27338
+ );
27339
+ this.#audit.record(
27340
+ `agent_installation_${stage}`,
27341
+ job.requestId,
27342
+ job.agentId
27343
+ );
27344
+ },
27345
+ signal
27346
+ );
27347
+ signal.throwIfAborted();
27348
+ const succeeded = new SucceededInstallation(job.requestId, job.agentId);
27349
+ await this.#transition(job, succeeded);
27350
+ this.#audit.record(
27351
+ "agent_installation_completed",
27352
+ job.requestId,
27353
+ job.agentId
28113
27354
  );
28114
- return executable;
27355
+ job.completion.resolve(succeeded);
28115
27356
  } catch (error61) {
28116
- if (options.signal.aborted) {
28117
- options.signal.throwIfAborted();
28118
- }
28119
- if (error61 instanceof ManagedAgentArchiveError) {
28120
- if (error61.code === "managed_archive_verification_failed") {
28121
- throw new InstallationManagerError(
28122
- "agent_verification_failed",
28123
- "The managed OpenCode archive did not match its pinned artifact",
28124
- { cause: error61 }
27357
+ if (signal.aborted) {
27358
+ if (signal.reason instanceof InstallationManagerError && signal.reason.code === "installation_timeout") {
27359
+ const timedOut = new FailedInstallation(
27360
+ job.requestId,
27361
+ job.agentId,
27362
+ signal.reason.code,
27363
+ signal.reason.message
28125
27364
  );
28126
- }
28127
- if (error61.code === "managed_archive_publish_failed") {
28128
- throw new InstallationManagerError(
28129
- "agent_publish_failed",
28130
- "The managed OpenCode archive could not be published",
28131
- { cause: error61 }
27365
+ await this.#transition(job, timedOut);
27366
+ this.#audit.record(
27367
+ "agent_installation_failed_installation_timeout",
27368
+ job.requestId,
27369
+ job.agentId
28132
27370
  );
27371
+ job.completion.resolve(timedOut);
27372
+ return;
28133
27373
  }
28134
- throw new InstallationManagerError(error61.code, error61.message, {
28135
- cause: error61
28136
- });
27374
+ const cancelled = new CancelledInstallation(job.requestId, job.agentId);
27375
+ await this.#transition(job, cancelled);
27376
+ this.#audit.record(
27377
+ "agent_installation_cancelled",
27378
+ job.requestId,
27379
+ job.agentId
27380
+ );
27381
+ job.completion.resolve(cancelled);
27382
+ } else {
27383
+ const failure = executionFailure(error61);
27384
+ const failed = new FailedInstallation(
27385
+ job.requestId,
27386
+ job.agentId,
27387
+ failure.code,
27388
+ failure.message
27389
+ );
27390
+ await this.#transition(job, failed);
27391
+ this.#audit.record(
27392
+ `agent_installation_failed_${failure.code}`,
27393
+ job.requestId,
27394
+ job.agentId
27395
+ );
27396
+ job.completion.resolve(failed);
28137
27397
  }
28138
- if (error61 instanceof InstallationManagerError) {
28139
- throw error61;
27398
+ } finally {
27399
+ clearTimeout(deadline);
27400
+ externalSignal.removeEventListener("abort", abort);
27401
+ if (this.#activeAgents.get(job.agentId) === job.requestId) {
27402
+ this.#activeAgents.delete(job.agentId);
28140
27403
  }
28141
- throw new InstallationManagerError(
28142
- "agent_install_failed",
28143
- "The fixed OpenCode installation recipe failed",
28144
- { cause: error61 }
28145
- );
28146
27404
  }
28147
27405
  };
28148
27406
  };
28149
- function fixedAgentInstallRecipes() {
28150
- return Object.freeze([
28151
- new CodexInstallRecipe(),
28152
- new ClaudeCodeInstallRecipe(),
28153
- new PiInstallRecipe(),
28154
- new DeepSeekHarnessInstallRecipe(),
28155
- new OpenCodeInstallRecipe(),
28156
- new GrokBuildInstallRecipe(),
28157
- new WorkBuddyInstallRecipe()
28158
- ]);
28159
- }
28160
27407
 
28161
27408
  // src/agent-installation/fixed-installation-executor.ts
27409
+ import { realpathSync as realpathSync2, statSync as statSync2 } from "node:fs";
27410
+ import { resolve as resolve4 } from "node:path";
28162
27411
  function findSpecification(specifications, agentId) {
28163
27412
  for (const specification of specifications) {
28164
27413
  if (specification.id === agentId) {
@@ -28170,17 +27419,6 @@ function findSpecification(specifications, agentId) {
28170
27419
  "The requested Agent is not supported"
28171
27420
  );
28172
27421
  }
28173
- function findRecipe(recipes, agentId) {
28174
- for (const recipe of recipes) {
28175
- if (recipe.id === agentId) {
28176
- return recipe;
28177
- }
28178
- }
28179
- throw new InstallationManagerError(
28180
- "agent_not_installable",
28181
- "The requested Agent does not have an approved installation recipe"
28182
- );
28183
- }
28184
27422
  function resolveDefaultWorkspace2(path2) {
28185
27423
  try {
28186
27424
  const directory = realpathSync2(resolve4(path2));
@@ -28196,7 +27434,7 @@ function resolveDefaultWorkspace2(path2) {
28196
27434
  );
28197
27435
  }
28198
27436
  }
28199
- function resolveUserInstallationDirectory(path2) {
27437
+ function resolveIntegrationStateDirectory(path2) {
28200
27438
  try {
28201
27439
  const directory = realpathSync2(resolve4(path2));
28202
27440
  const metadata = statSync2(directory);
@@ -28207,7 +27445,7 @@ function resolveUserInstallationDirectory(path2) {
28207
27445
  } catch (error61) {
28208
27446
  throw new InstallationManagerError(
28209
27447
  "unsafe_installation_root",
28210
- "The local Agent installation root is unavailable or unsafe",
27448
+ "The local integration state directory is unavailable or unsafe",
28211
27449
  { cause: error61 }
28212
27450
  );
28213
27451
  }
@@ -28216,20 +27454,17 @@ function translateExecutionError(error61) {
28216
27454
  if (error61 instanceof InstallationManagerError) {
28217
27455
  return error61;
28218
27456
  }
28219
- if (error61 instanceof ManagedAdapterInstallError || error61 instanceof InstallerDownloadError || error61 instanceof ProcessExecutionError) {
27457
+ if (error61 instanceof ManagedAdapterInstallError) {
28220
27458
  return new InstallationManagerError(error61.code, error61.message, {
28221
27459
  cause: error61
28222
27460
  });
28223
27461
  }
28224
27462
  return new InstallationManagerError(
28225
27463
  "installation_failed",
28226
- "The fixed local Agent installation failed",
27464
+ "The local Agent integration installation failed",
28227
27465
  { cause: error61 }
28228
27466
  );
28229
27467
  }
28230
- function requiresAgentReplacement(code) {
28231
- return code === "agent_not_found" || code === "agent_probe_failed" || code === "agent_probe_timeout";
28232
- }
28233
27468
  function requiresAdapterReplacement(code) {
28234
27469
  return code === "adapter_not_found" || code === "adapter_probe_failed" || code === "adapter_probe_timeout" || code === "acp_incompatible";
28235
27470
  }
@@ -28240,12 +27475,10 @@ var FixedInstallationExecutor = class {
28240
27475
  #catalog;
28241
27476
  #environment;
28242
27477
  #publishCatalog;
28243
- #recipes;
28244
27478
  #specifications;
28245
- #stateDirectory;
28246
- constructor(options, specifications = supportedLocalAgentSpecifications(), recipes = fixedAgentInstallRecipes(), adapterInstaller) {
27479
+ constructor(options, specifications = supportedLocalAgentSpecifications(), adapterInstaller) {
28247
27480
  const defaultWorkspace = resolveDefaultWorkspace2(options.defaultWorkspace);
28248
- const stateDirectory = resolveUserInstallationDirectory(
27481
+ const stateDirectory = resolveIntegrationStateDirectory(
28249
27482
  options.stateDirectory
28250
27483
  );
28251
27484
  this.#defaultWorkspace = defaultWorkspace;
@@ -28253,9 +27486,7 @@ var FixedInstallationExecutor = class {
28253
27486
  this.#catalog = options.catalog;
28254
27487
  this.#environment = Object.freeze({ ...options.environment });
28255
27488
  this.#publishCatalog = options.publishCatalog;
28256
- this.#recipes = Object.freeze([...recipes]);
28257
27489
  this.#specifications = Object.freeze([...specifications]);
28258
- this.#stateDirectory = stateDirectory;
28259
27490
  this.#adapterInstaller = adapterInstaller ?? new ManagedAdapterInstaller({
28260
27491
  environment: this.#environment,
28261
27492
  stateDirectory
@@ -28264,35 +27495,59 @@ var FixedInstallationExecutor = class {
28264
27495
  execute = async (agentId, requestId, report, signal) => {
28265
27496
  try {
28266
27497
  const specification = findSpecification(this.#specifications, agentId);
28267
- const recipe = findRecipe(this.#recipes, agentId);
28268
- this.#audit.record(
28269
- "agent_installation_recipe_resolved",
28270
- requestId,
28271
- agentId,
28272
- {
28273
- adapterVersion: specification.adapterVersion,
28274
- releaseChannel: recipe.releaseChannel
28275
- }
28276
- );
28277
- const discoveryOptions2 = {
27498
+ const discoveryOptions = {
28278
27499
  defaultWorkspace: this.#defaultWorkspace,
28279
27500
  environment: this.#environment,
28280
27501
  signal
28281
27502
  };
28282
- let agent = await resolveAgentExecutable(specification, discoveryOptions2);
28283
- let installedAgent = false;
28284
- if (agent === null) {
28285
- agent = await recipe.install({
28286
- audit: this.#audit,
28287
- environment: this.#environment,
28288
- report,
28289
- requestId,
28290
- signal,
28291
- stateDirectory: this.#stateDirectory
28292
- });
28293
- installedAgent = true;
27503
+ const initialInventory = await discoverLocalAgentInventory({
27504
+ ...discoveryOptions,
27505
+ specifications: this.#specifications
27506
+ });
27507
+ const previous = this.#catalog.read();
27508
+ this.#catalog.transition(
27509
+ initialInventory.readyAgents(),
27510
+ initialInventory.installable
27511
+ );
27512
+ try {
27513
+ await this.#publishCatalog(signal);
27514
+ } catch (error61) {
27515
+ this.#catalog.transition(previous.agents, previous.installableAgents);
27516
+ throw error61;
27517
+ }
27518
+ const alreadyReady = initialInventory.available.find(
27519
+ (candidate2) => candidate2.specification.id === agentId
27520
+ );
27521
+ if (alreadyReady instanceof AvailableAgent) {
27522
+ return;
27523
+ }
27524
+ const candidate = initialInventory.installable.find(
27525
+ (agent2) => agent2.id === agentId
27526
+ );
27527
+ if (candidate instanceof MissingAgentDefinition) {
27528
+ throw new InstallationManagerError(
27529
+ "agent_not_installed",
27530
+ `Install ${specification.label} on this machine, then try installing the integration again.`
27531
+ );
27532
+ }
27533
+ if (!(candidate instanceof AgentIntegrationDefinition)) {
27534
+ throw new InstallationManagerError(
27535
+ "agent_verification_failed",
27536
+ "The local Agent discovery result is unavailable"
27537
+ );
28294
27538
  }
28295
- let adapter = specification instanceof DirectAcpAgentDefinition ? agent : await resolveAdapterExecutable(specification, discoveryOptions2);
27539
+ const verifiedAgent = await findVerifiedAgentExecutable(
27540
+ specification,
27541
+ discoveryOptions
27542
+ );
27543
+ if (verifiedAgent === null) {
27544
+ throw new InstallationManagerError(
27545
+ "agent_not_installed",
27546
+ `Install ${specification.label} on this machine, then try installing the integration again.`
27547
+ );
27548
+ }
27549
+ const agent = verifiedAgent.executable;
27550
+ let adapter = specification instanceof DirectAcpAgentDefinition ? agent : await resolveAdapterExecutable(specification, discoveryOptions);
28296
27551
  let installedAdapter = false;
28297
27552
  if (adapter === null) {
28298
27553
  if (!(specification instanceof BridgedAcpAgentDefinition)) {
@@ -28301,6 +27556,12 @@ var FixedInstallationExecutor = class {
28301
27556
  "The direct Agent executable is unavailable"
28302
27557
  );
28303
27558
  }
27559
+ if (this.#environment[specification.adapterOverrideVariable] !== void 0) {
27560
+ throw new InstallationManagerError(
27561
+ "adapter_not_found",
27562
+ "The configured ACP adapter is unavailable"
27563
+ );
27564
+ }
28304
27565
  await report("installing_adapter");
28305
27566
  adapter = await this.#adapterInstaller.install(specification, signal);
28306
27567
  installedAdapter = true;
@@ -28311,8 +27572,8 @@ var FixedInstallationExecutor = class {
28311
27572
  while (true) {
28312
27573
  await report("checking_acp");
28313
27574
  const environment = { ...this.#environment };
28314
- environment[specification.agentOverrideVariable] = agent.path;
28315
- environment[specification.adapterOverrideVariable] = adapter.path;
27575
+ environment[specification.agentOverrideVariable] = agent.identity.requestedPath;
27576
+ environment[specification.adapterOverrideVariable] = adapter.identity.requestedPath;
28316
27577
  const inventory = await discoverLocalAgentInventory({
28317
27578
  defaultWorkspace: this.#defaultWorkspace,
28318
27579
  environment,
@@ -28320,7 +27581,7 @@ var FixedInstallationExecutor = class {
28320
27581
  specifications: this.#specifications
28321
27582
  });
28322
27583
  const verified = inventory.available.find(
28323
- (candidate) => candidate.specification.id === agentId
27584
+ (candidate2) => candidate2.specification.id === agentId
28324
27585
  );
28325
27586
  if (verified instanceof AvailableAgent) {
28326
27587
  this.#audit.record(
@@ -28332,7 +27593,7 @@ var FixedInstallationExecutor = class {
28332
27593
  agentVersion: verified.agent.agentVersion
28333
27594
  }
28334
27595
  );
28335
- const previous = this.#catalog.read();
27596
+ const previousCatalog = this.#catalog.read();
28336
27597
  this.#catalog.transition(
28337
27598
  inventory.readyAgents(),
28338
27599
  inventory.installable
@@ -28341,15 +27602,15 @@ var FixedInstallationExecutor = class {
28341
27602
  await this.#publishCatalog(signal);
28342
27603
  } catch (error61) {
28343
27604
  this.#catalog.transition(
28344
- previous.agents,
28345
- previous.installableAgents
27605
+ previousCatalog.agents,
27606
+ previousCatalog.installableAgents
28346
27607
  );
28347
27608
  throw error61;
28348
27609
  }
28349
27610
  return;
28350
27611
  }
28351
27612
  const unavailable = inventory.unavailable.find(
28352
- (candidate) => candidate.specification.id === agentId
27613
+ (candidate2) => candidate2.specification.id === agentId
28353
27614
  );
28354
27615
  if (unavailable === void 0) {
28355
27616
  throw new InstallationManagerError(
@@ -28357,7 +27618,7 @@ var FixedInstallationExecutor = class {
28357
27618
  "The complete Agent ACP path did not pass verification"
28358
27619
  );
28359
27620
  }
28360
- if (!installedAdapter && specification instanceof BridgedAcpAgentDefinition && requiresAdapterReplacement(unavailable.code)) {
27621
+ if (!installedAdapter && specification instanceof BridgedAcpAgentDefinition && this.#environment[specification.adapterOverrideVariable] === void 0 && requiresAdapterReplacement(unavailable.code)) {
28361
27622
  await report("installing_adapter");
28362
27623
  adapter = await this.#adapterInstaller.install(specification, signal);
28363
27624
  installedAdapter = true;
@@ -28366,21 +27627,6 @@ var FixedInstallationExecutor = class {
28366
27627
  });
28367
27628
  continue;
28368
27629
  }
28369
- if (!installedAgent && (requiresAgentReplacement(unavailable.code) || unavailable.code === "acp_incompatible")) {
28370
- agent = await recipe.install({
28371
- audit: this.#audit,
28372
- environment: this.#environment,
28373
- report,
28374
- requestId,
28375
- signal,
28376
- stateDirectory: this.#stateDirectory
28377
- });
28378
- installedAgent = true;
28379
- if (specification instanceof DirectAcpAgentDefinition) {
28380
- adapter = agent;
28381
- }
28382
- continue;
28383
- }
28384
27630
  throw new InstallationManagerError(
28385
27631
  unavailable.code,
28386
27632
  unavailable.message
@@ -28405,15 +27651,15 @@ var LocalAuthorizationError = class extends Error {
28405
27651
  };
28406
27652
 
28407
27653
  // src/authorization/workspace-directory.ts
28408
- import { readdir, realpath as realpath8, stat as stat7 } from "node:fs/promises";
27654
+ import { readdir, realpath as realpath7, stat as stat6 } from "node:fs/promises";
28409
27655
  import { homedir as homedir2 } from "node:os";
28410
27656
  import {
28411
27657
  basename as basename2,
28412
- dirname as dirname6,
28413
- isAbsolute as isAbsolute8,
28414
- join as join18,
27658
+ dirname as dirname5,
27659
+ isAbsolute as isAbsolute7,
27660
+ join as join15,
28415
27661
  normalize as normalize2,
28416
- relative as relative5
27662
+ relative as relative4
28417
27663
  } from "node:path";
28418
27664
  var WorkspaceDirectoryListing = class {
28419
27665
  directoryId;
@@ -28463,20 +27709,20 @@ var WorkspaceDirectoryService = class {
28463
27709
  if (id === "home") return homedir2();
28464
27710
  if (id.startsWith("path-")) {
28465
27711
  const path2 = decodePath(id, "path-");
28466
- if (isAbsolute8(path2)) return path2;
27712
+ if (isAbsolute7(path2)) return path2;
28467
27713
  }
28468
27714
  throw new LocalAuthorizationError("The directory identifier is invalid");
28469
27715
  };
28470
27716
  resolvePath = async (requested, signal) => {
28471
27717
  signal.throwIfAborted();
28472
- if (!isAbsolute8(requested) || requested.includes("\0") || normalize2(requested) !== requested)
27718
+ if (!isAbsolute7(requested) || requested.includes("\0") || normalize2(requested) !== requested)
28473
27719
  throw new LocalAuthorizationError("The local directory path is invalid");
28474
27720
  try {
28475
- const target = await realpath8(requested);
27721
+ const target = await realpath7(requested);
28476
27722
  signal.throwIfAborted();
28477
- const metadata = await stat7(target);
27723
+ const metadata = await stat6(target);
28478
27724
  signal.throwIfAborted();
28479
- if (!isAbsolute8(target) || normalize2(target) !== target || !metadata.isDirectory())
27725
+ if (!isAbsolute7(target) || normalize2(target) !== target || !metadata.isDirectory())
28480
27726
  throw new LocalAuthorizationError(
28481
27727
  "The selected location is not a directory"
28482
27728
  );
@@ -28491,8 +27737,8 @@ var WorkspaceDirectoryService = class {
28491
27737
  }
28492
27738
  };
28493
27739
  label = (path2) => {
28494
- const suffix = relative5(homedir2(), path2);
28495
- return suffix === "" ? "~" : !isAbsolute8(suffix) && suffix !== ".." && !suffix.startsWith(`..${process.platform === "win32" ? "\\" : "/"}`) ? `~/${suffix.replaceAll("\\", "/")}` : path2;
27740
+ const suffix = relative4(homedir2(), path2);
27741
+ return suffix === "" ? "~" : !isAbsolute7(suffix) && suffix !== ".." && !suffix.startsWith(`..${process.platform === "win32" ? "\\" : "/"}`) ? `~/${suffix.replaceAll("\\", "/")}` : path2;
28496
27742
  };
28497
27743
  identify = async (bindingId, requestedPath, signal) => {
28498
27744
  this.authorizeMachine(bindingId);
@@ -28520,7 +27766,7 @@ var WorkspaceDirectoryService = class {
28520
27766
  continue;
28521
27767
  }
28522
27768
  try {
28523
- const path2 = await this.resolvePath(join18(target, child.name), signal);
27769
+ const path2 = await this.resolvePath(join15(target, child.name), signal);
28524
27770
  entries.push({ directoryId: encodePath(path2), name: child.name });
28525
27771
  } catch (cause) {
28526
27772
  signal.throwIfAborted();
@@ -28528,7 +27774,7 @@ var WorkspaceDirectoryService = class {
28528
27774
  }
28529
27775
  }
28530
27776
  entries.sort((a, b) => a.name.localeCompare(b.name));
28531
- const parent = dirname6(target);
27777
+ const parent = dirname5(target);
28532
27778
  return new WorkspaceDirectoryListing(
28533
27779
  id,
28534
27780
  this.label(target),
@@ -28552,7 +27798,7 @@ var WorkspaceDirectoryService = class {
28552
27798
  };
28553
27799
 
28554
27800
  // src/native-sessions/service.ts
28555
- import { randomUUID as randomUUID3 } from "node:crypto";
27801
+ import { randomUUID as randomUUID2 } from "node:crypto";
28556
27802
 
28557
27803
  // src/native-sessions/codex-history.ts
28558
27804
  import { spawn as spawn4 } from "node:child_process";
@@ -28866,7 +28112,7 @@ var NativeSessionService = class {
28866
28112
  for (const info of page.sessions) {
28867
28113
  const authorized = await this.authorizeEntry(command, options, info);
28868
28114
  if (authorized === null) continue;
28869
- const entryId = randomUUID3();
28115
+ const entryId = randomUUID2();
28870
28116
  if (this.#entries.size >= 5e3) this.#entries.clear();
28871
28117
  this.#entries.set(entryId, {
28872
28118
  scope: entryScope,
@@ -28891,7 +28137,7 @@ var NativeSessionService = class {
28891
28137
  {},
28892
28138
  "invalid_native_session_response"
28893
28139
  );
28894
- nextCursor = randomUUID3();
28140
+ nextCursor = randomUUID2();
28895
28141
  if (this.#cursors.size >= 500) this.#cursors.clear();
28896
28142
  this.#cursors.set(nextCursor, {
28897
28143
  scope: cursorScope,
@@ -29211,7 +28457,7 @@ function connectRelay(url2, signal) {
29211
28457
  }
29212
28458
 
29213
28459
  // src/relay-connection/liveness.ts
29214
- import { randomUUID as randomUUID4 } from "node:crypto";
28460
+ import { randomUUID as randomUUID3 } from "node:crypto";
29215
28461
  var HEARTBEAT_ACK_TIMEOUT_MILLISECONDS = 1e4;
29216
28462
  var HEARTBEAT_INTERVAL_MILLISECONDS = 2e4;
29217
28463
  var RelayLivenessState = class {
@@ -29302,7 +28548,7 @@ var RelayConnectionLiveness = class {
29302
28548
  }
29303
28549
  throw new Error("Heartbeat was scheduled in an invalid state");
29304
28550
  }
29305
- const heartbeatId = randomUUID4();
28551
+ const heartbeatId = randomUUID3();
29306
28552
  this.#state = new AwaitingHeartbeatAckState(
29307
28553
  heartbeatId,
29308
28554
  this.#timer.schedule(
@@ -29321,7 +28567,7 @@ var RelayConnectionLiveness = class {
29321
28567
 
29322
28568
  // src/relay-connection/session-event-outbox.ts
29323
28569
  import { mkdirSync as mkdirSync3 } from "node:fs";
29324
- import { dirname as dirname7 } from "node:path";
28570
+ import { dirname as dirname6 } from "node:path";
29325
28571
  import { DatabaseSync as DatabaseSync3 } from "node:sqlite";
29326
28572
  function readPendingEnvelope(row) {
29327
28573
  if (typeof row !== "object" || row === null || Array.isArray(row)) {
@@ -29336,7 +28582,7 @@ function readPendingEnvelope(row) {
29336
28582
  var SessionEventOutbox = class {
29337
28583
  #database;
29338
28584
  constructor(path2) {
29339
- mkdirSync3(dirname7(path2), { recursive: true });
28585
+ mkdirSync3(dirname6(path2), { recursive: true });
29340
28586
  this.#database = new DatabaseSync3(path2);
29341
28587
  this.#database.exec(`
29342
28588
  CREATE TABLE IF NOT EXISTS relay_session_event_outbox (
@@ -29490,6 +28736,7 @@ var systemDaemonTimer = new SystemDaemonTimer();
29490
28736
  // src/run-daemon.ts
29491
28737
  var RELAY_RECONNECT_DELAY_MILLISECONDS = 500;
29492
28738
  var RELAY_CONNECTION_REFRESH_MILLISECONDS = 20 * 60 * 1e3;
28739
+ var ACTIVE_TURN_RECONCILIATION_TIMEOUT_MILLISECONDS = 2e4;
29493
28740
  var RelayConnectionRefreshState = class {
29494
28741
  };
29495
28742
  var ScheduledRelayConnectionRefreshState = class extends RelayConnectionRefreshState {
@@ -29687,7 +28934,7 @@ var DaemonInstallationObserver = class {
29687
28934
  );
29688
28935
  return Promise.resolve();
29689
28936
  }
29690
- throw new Error("Unsupported Agent installation state");
28937
+ throw new Error("Unsupported Agent integration installation state");
29691
28938
  };
29692
28939
  };
29693
28940
  var ResolvedSessionDirectories = class {
@@ -29701,16 +28948,20 @@ var ResolvedSessionDirectories = class {
29701
28948
  }
29702
28949
  };
29703
28950
  var ActiveDaemonTurn = class {
28951
+ attemptId;
29704
28952
  command;
29705
- #connectionController;
28953
+ #controller;
28954
+ #finished = Promise.withResolvers();
29706
28955
  #cancellationRequested = false;
29707
- constructor(command, connectionController) {
28956
+ constructor(command, attemptId) {
28957
+ this.attemptId = attemptId;
29708
28958
  this.command = command;
29709
- this.#connectionController = connectionController;
28959
+ this.#controller = new AbortController();
29710
28960
  }
29711
- abortConnection = () => {
29712
- this.#connectionController.abort();
28961
+ abortDaemon = () => {
28962
+ this.#controller.abort();
29713
28963
  };
28964
+ finish = () => this.#finished.resolve();
29714
28965
  matches = (cancellation) => cancellation.commandId === this.command.commandId && cancellation.sessionId === this.command.sessionId;
29715
28966
  requestCancellation = () => {
29716
28967
  if (this.#cancellationRequested) {
@@ -29720,25 +28971,118 @@ var ActiveDaemonTurn = class {
29720
28971
  return true;
29721
28972
  };
29722
28973
  get signal() {
29723
- return this.#connectionController.signal;
28974
+ return this.#controller.signal;
28975
+ }
28976
+ get completion() {
28977
+ return this.#finished.promise;
28978
+ }
28979
+ };
28980
+ var ActiveTurnReconciliationError = class extends Error {
28981
+ code = "active_turn_reconciliation_failed";
28982
+ constructor(message, options = {}) {
28983
+ super(message, options);
28984
+ this.name = "ActiveTurnReconciliationError";
29724
28985
  }
29725
28986
  };
28987
+ function activeTurnReconciliationEndpoint(config2, turn) {
28988
+ const endpoint = new URL(config2.relayUrl);
28989
+ endpoint.protocol = endpoint.protocol === "wss:" ? "https:" : "http:";
28990
+ if (!endpoint.pathname.endsWith("/daemon")) {
28991
+ throw new ActiveTurnReconciliationError("The Relay URL is invalid");
28992
+ }
28993
+ endpoint.pathname = `${endpoint.pathname.slice(0, -"/daemon".length)}/sessions/${encodeURIComponent(turn.command.sessionId)}/attempts/${encodeURIComponent(turn.attemptId)}/reconciliation`;
28994
+ endpoint.searchParams.delete("liveness");
28995
+ return endpoint;
28996
+ }
28997
+ async function reconcileActiveTurn(config2, turn, signal) {
28998
+ signal.throwIfAborted();
28999
+ const timeoutSignal = AbortSignal.timeout(
29000
+ ACTIVE_TURN_RECONCILIATION_TIMEOUT_MILLISECONDS
29001
+ );
29002
+ const requestSignal = AbortSignal.any([signal, timeoutSignal]);
29003
+ let response;
29004
+ try {
29005
+ response = await fetch4(activeTurnReconciliationEndpoint(config2, turn), {
29006
+ body: JSON.stringify({ outcome: { kind: "running" } }),
29007
+ dispatcher: environmentProxyDispatcher,
29008
+ headers: { "content-type": "application/json" },
29009
+ method: "POST",
29010
+ signal: requestSignal
29011
+ });
29012
+ } catch (error61) {
29013
+ if (signal.aborted) {
29014
+ signal.throwIfAborted();
29015
+ }
29016
+ throw new ActiveTurnReconciliationError(
29017
+ timeoutSignal.aborted ? "The active Agent turn reconciliation timed out" : "The active Agent turn could not be reconciled",
29018
+ { cause: error61 }
29019
+ );
29020
+ }
29021
+ await response.body?.cancel();
29022
+ if (!response.ok) {
29023
+ throw new ActiveTurnReconciliationError(
29024
+ "The Relay rejected the active Agent turn reconciliation"
29025
+ );
29026
+ }
29027
+ }
29028
+ async function reconcileActiveTurns(config2, turns, signal) {
29029
+ await Promise.all(
29030
+ turns.map(async (turn) => await reconcileActiveTurn(config2, turn, signal))
29031
+ );
29032
+ }
29726
29033
  function send(socket, message) {
29727
29034
  if (socket.readyState !== WebSocket2.OPEN) {
29728
29035
  throw new Error("Relay connection is not open");
29729
29036
  }
29730
29037
  socket.send(message);
29731
29038
  }
29732
- function recordSessionEvent(outbox, socket, sessionId, payload, attemptId = null) {
29733
- const envelope2 = outbox.enqueue(sessionId, payload, attemptId);
29734
- if (socket.readyState === WebSocket2.OPEN) {
29735
- socket.send(envelope2);
29039
+ var DaemonSessionEventConnectionState = class {
29040
+ };
29041
+ var DisconnectedDaemonSessionEventState = class extends DaemonSessionEventConnectionState {
29042
+ disconnect = () => this;
29043
+ send = () => void 0;
29044
+ };
29045
+ var ConnectedDaemonSessionEventState = class extends DaemonSessionEventConnectionState {
29046
+ #socket;
29047
+ constructor(socket) {
29048
+ super();
29049
+ this.#socket = socket;
29736
29050
  }
29737
- }
29738
- function reportFailure(outbox, socket, command, code, message, attemptId = null) {
29739
- recordSessionEvent(
29740
- outbox,
29741
- socket,
29051
+ disconnect = (socket) => socket === this.#socket ? new DisconnectedDaemonSessionEventState() : this;
29052
+ send = (message) => {
29053
+ if (this.#socket.readyState === WebSocket2.OPEN) {
29054
+ try {
29055
+ this.#socket.send(message);
29056
+ } catch {
29057
+ }
29058
+ }
29059
+ };
29060
+ };
29061
+ var DaemonSessionEventPublisher = class {
29062
+ #outbox;
29063
+ #connection = new DisconnectedDaemonSessionEventState();
29064
+ constructor(outbox) {
29065
+ this.#outbox = outbox;
29066
+ }
29067
+ connect = (socket) => {
29068
+ const connection = new ConnectedDaemonSessionEventState(socket);
29069
+ this.#connection = connection;
29070
+ for (const pending of this.#outbox.pending()) {
29071
+ connection.send(pending);
29072
+ }
29073
+ };
29074
+ disconnect = (socket) => {
29075
+ this.#connection = this.#connection.disconnect(socket);
29076
+ };
29077
+ recordAttempt = (sessionId, payload, attemptId) => {
29078
+ this.#connection.send(this.#outbox.enqueue(sessionId, payload, attemptId));
29079
+ };
29080
+ recordRuntime = (sessionId, payload) => {
29081
+ this.#connection.send(this.#outbox.enqueue(sessionId, payload));
29082
+ };
29083
+ };
29084
+ function reportFailure(publisher, command, code, message, attemptId) {
29085
+ publisher.recordAttempt(
29742
29086
  command.sessionId,
29743
29087
  encodeSessionFailedEvent({
29744
29088
  code,
@@ -29834,7 +29178,7 @@ async function executeWorkspaceList(socket, command, directories, audit, signal)
29834
29178
  reportOperationFailure(socket, command.requestId, "", error61);
29835
29179
  }
29836
29180
  }
29837
- async function executeSessionPrepare(outbox, socket, command, config2, directories, audit, sessions, signal) {
29181
+ async function executeSessionPrepare(publisher, socket, command, config2, directories, audit, sessions, signal) {
29838
29182
  try {
29839
29183
  const resolved = await resolveSessionDirectories(
29840
29184
  directories,
@@ -29861,9 +29205,7 @@ async function executeSessionPrepare(outbox, socket, command, config2, directori
29861
29205
  event: "session_prepared",
29862
29206
  sessionId: command.sessionId
29863
29207
  });
29864
- recordSessionEvent(
29865
- outbox,
29866
- socket,
29208
+ publisher.recordRuntime(
29867
29209
  command.sessionId,
29868
29210
  encodeSessionReadyEvent({
29869
29211
  additionalDirectories: resolved.additionalDirectoryEntries,
@@ -29894,7 +29236,7 @@ async function executeSessionPrepare(outbox, socket, command, config2, directori
29894
29236
  reportOperationFailure(socket, command.requestId, command.sessionId, error61);
29895
29237
  }
29896
29238
  }
29897
- async function executeSessionConfigure(outbox, socket, command, config2, directories, audit, sessions, signal) {
29239
+ async function executeSessionConfigure(publisher, socket, command, config2, directories, audit, sessions, signal) {
29898
29240
  try {
29899
29241
  const resolved = await resolveSessionDirectories(
29900
29242
  directories,
@@ -29920,9 +29262,7 @@ async function executeSessionConfigure(outbox, socket, command, config2, directo
29920
29262
  event: "session_configured",
29921
29263
  sessionId: command.sessionId
29922
29264
  });
29923
- recordSessionEvent(
29924
- outbox,
29925
- socket,
29265
+ publisher.recordRuntime(
29926
29266
  command.sessionId,
29927
29267
  encodeSessionConfigUpdatedEvent({
29928
29268
  configOptions,
@@ -29935,7 +29275,7 @@ async function executeSessionConfigure(outbox, socket, command, config2, directo
29935
29275
  reportOperationFailure(socket, command.requestId, command.sessionId, error61);
29936
29276
  }
29937
29277
  }
29938
- async function executePrompt(outbox, socket, command, config2, directories, audit, sessions, attemptId, signal) {
29278
+ async function executePrompt(outbox, publisher, command, config2, directories, audit, sessions, attemptId, signal) {
29939
29279
  try {
29940
29280
  const resolved = await resolveSessionDirectories(
29941
29281
  directories,
@@ -29951,9 +29291,7 @@ async function executePrompt(outbox, socket, command, config2, directories, audi
29951
29291
  sessionId: command.sessionId
29952
29292
  });
29953
29293
  outbox.transitionExecution(command.commandId, "running");
29954
- recordSessionEvent(
29955
- outbox,
29956
- socket,
29294
+ publisher.recordAttempt(
29957
29295
  command.sessionId,
29958
29296
  encodeSessionStartedEvent({
29959
29297
  commandId: command.commandId,
@@ -29970,9 +29308,7 @@ async function executePrompt(outbox, socket, command, config2, directories, audi
29970
29308
  cwd: resolved.cwd,
29971
29309
  images: command.images,
29972
29310
  onActivity: (activity) => {
29973
- recordSessionEvent(
29974
- outbox,
29975
- socket,
29311
+ publisher.recordAttempt(
29976
29312
  command.sessionId,
29977
29313
  encodeAgentActivityEvent({
29978
29314
  activityId: activity.activityId,
@@ -29996,9 +29332,7 @@ async function executePrompt(outbox, socket, command, config2, directories, audi
29996
29332
  return Promise.resolve();
29997
29333
  },
29998
29334
  onText: (text) => {
29999
- recordSessionEvent(
30000
- outbox,
30001
- socket,
29335
+ publisher.recordAttempt(
30002
29336
  command.sessionId,
30003
29337
  encodeAgentMessageDeltaEvent({
30004
29338
  commandId: command.commandId,
@@ -30015,9 +29349,7 @@ async function executePrompt(outbox, socket, command, config2, directories, audi
30015
29349
  sessionId: command.sessionId,
30016
29350
  signal
30017
29351
  });
30018
- recordSessionEvent(
30019
- outbox,
30020
- socket,
29352
+ publisher.recordAttempt(
30021
29353
  command.sessionId,
30022
29354
  encodeSessionCompletedEvent({
30023
29355
  commandId: command.commandId,
@@ -30044,8 +29376,7 @@ async function executePrompt(outbox, socket, command, config2, directories, audi
30044
29376
  });
30045
29377
  const code = operationErrorCode(error61);
30046
29378
  reportFailure(
30047
- outbox,
30048
- socket,
29379
+ publisher,
30049
29380
  command,
30050
29381
  code === "session_operation_failed" ? "agent_execution_failed" : code,
30051
29382
  code === "session_operation_failed" ? "The local agent could not complete the request" : operationErrorMessage(error61),
@@ -30091,29 +29422,15 @@ async function publishAgentCatalogUntilAvailable(config2, signal, timer) {
30091
29422
  }
30092
29423
  }
30093
29424
  }
30094
- async function runRelayConnection(config2, directories, audit, sessions, installations, installationObserver, nativeSessions, outbox, onConnected, signal, timer) {
29425
+ async function runRelayConnection(config2, directories, audit, sessions, installations, installationObserver, nativeSessions, outbox, publisher, activeTurns, activeAttemptIds, onConnected, signal, timer) {
30095
29426
  const relayUrl = new URL(config2.relayUrl);
30096
29427
  relayUrl.searchParams.set("liveness", "1");
30097
29428
  const socket = await connectRelay(relayUrl, signal);
29429
+ const reconnectingTurns = [...activeTurns.values()];
30098
29430
  onConnected();
30099
- const activeTurns = /* @__PURE__ */ new Map();
30100
- const activeAttemptIds = /* @__PURE__ */ new Map();
30101
29431
  const connectionController = new AbortController();
30102
29432
  const nativeRequests = /* @__PURE__ */ new Map();
30103
- const record2 = (sessionId, payload) => {
30104
- recordSessionEvent(
30105
- outbox,
30106
- socket,
30107
- sessionId,
30108
- payload,
30109
- activeAttemptIds.get(sessionId) ?? null
30110
- );
30111
- };
30112
- sessions.setObserver(new DaemonAcpObserver(record2));
30113
29433
  installationObserver.connect(socket);
30114
- for (const pending of outbox.pending()) {
30115
- send(socket, pending);
30116
- }
30117
29434
  try {
30118
29435
  await new Promise((resolve5, reject) => {
30119
29436
  let finished = false;
@@ -30125,11 +29442,8 @@ async function runRelayConnection(config2, directories, audit, sessions, install
30125
29442
  socket.removeEventListener("error", handleError);
30126
29443
  socket.removeEventListener("message", handleMessage);
30127
29444
  installationObserver.disconnect(socket);
29445
+ publisher.disconnect(socket);
30128
29446
  connectionController.abort();
30129
- for (const turn of activeTurns.values()) {
30130
- turn.abortConnection();
30131
- }
30132
- activeTurns.clear();
30133
29447
  };
30134
29448
  const resolveConnection = () => {
30135
29449
  if (finished) {
@@ -30348,7 +29662,7 @@ async function runRelayConnection(config2, directories, audit, sessions, install
30348
29662
  if (kind === SESSION_PREPARE_KIND) {
30349
29663
  const command2 = decodeSessionPrepareCommand(encoded);
30350
29664
  void executeSessionPrepare(
30351
- outbox,
29665
+ publisher,
30352
29666
  socket,
30353
29667
  command2,
30354
29668
  config2,
@@ -30362,7 +29676,7 @@ async function runRelayConnection(config2, directories, audit, sessions, install
30362
29676
  if (kind === SESSION_CONFIGURE_KIND) {
30363
29677
  const command2 = decodeSessionConfigureCommand(encoded);
30364
29678
  void executeSessionConfigure(
30365
- outbox,
29679
+ publisher,
30366
29680
  socket,
30367
29681
  command2,
30368
29682
  config2,
@@ -30412,7 +29726,10 @@ async function runRelayConnection(config2, directories, audit, sessions, install
30412
29726
  if (kind === AGENT_INSTALL_REQUEST_KIND) {
30413
29727
  const command2 = decodeAgentInstallRequestCommand(encoded);
30414
29728
  void installations.request(command2, signal).catch((error61) => {
30415
- console.error("Mobius Agent installation failed", error61);
29729
+ console.error(
29730
+ "Mobius Agent integration installation failed",
29731
+ error61
29732
+ );
30416
29733
  });
30417
29734
  return;
30418
29735
  }
@@ -30438,12 +29755,12 @@ async function runRelayConnection(config2, directories, audit, sessions, install
30438
29755
  if (receipt.kind === "duplicate") {
30439
29756
  return;
30440
29757
  }
30441
- const turn = new ActiveDaemonTurn(command, new AbortController());
29758
+ const turn = new ActiveDaemonTurn(command, receipt.attemptId);
30442
29759
  activeTurns.set(command.commandId, turn);
30443
29760
  activeAttemptIds.set(command.sessionId, receipt.attemptId);
30444
29761
  void executePrompt(
30445
29762
  outbox,
30446
- socket,
29763
+ publisher,
30447
29764
  command,
30448
29765
  config2,
30449
29766
  directories,
@@ -30458,6 +29775,7 @@ async function runRelayConnection(config2, directories, audit, sessions, install
30458
29775
  if (activeAttemptIds.get(command.sessionId) === receipt.attemptId) {
30459
29776
  activeAttemptIds.delete(command.sessionId);
30460
29777
  }
29778
+ turn.finish();
30461
29779
  connectionRefresh.afterTurnFinished();
30462
29780
  });
30463
29781
  } catch (error61) {
@@ -30469,6 +29787,28 @@ async function runRelayConnection(config2, directories, audit, sessions, install
30469
29787
  socket.addEventListener("close", handleClose);
30470
29788
  socket.addEventListener("error", handleError);
30471
29789
  socket.addEventListener("message", handleMessage);
29790
+ void reconcileActiveTurns(
29791
+ config2,
29792
+ reconnectingTurns,
29793
+ connectionController.signal
29794
+ ).then(
29795
+ () => {
29796
+ if (finished) {
29797
+ return;
29798
+ }
29799
+ publisher.connect(socket);
29800
+ void Promise.all(
29801
+ reconnectingTurns.map((turn) => turn.completion)
29802
+ ).then(connectionRefresh.afterTurnFinished);
29803
+ },
29804
+ () => {
29805
+ if (finished) {
29806
+ return;
29807
+ }
29808
+ socket.close(1011, "Active Agent turn reconciliation failed");
29809
+ rejectConnection();
29810
+ }
29811
+ );
30472
29812
  if (signal.aborted) {
30473
29813
  stop();
30474
29814
  }
@@ -30492,23 +29832,21 @@ async function runDaemon(config2, audit, signal, timer = systemDaemonTimer) {
30492
29832
  publishCatalog: async (installationSignal) => await publishAgentCatalog(config2, installationSignal),
30493
29833
  stateDirectory
30494
29834
  });
30495
- await new AutomaticAdapterProvisioner(
30496
- {
30497
- defaultWorkspace: config2.defaultWorkspace,
30498
- audit: installationAudit,
30499
- catalog: config2.catalog,
30500
- environment: process.env
30501
- },
30502
- new ManagedAdapterInstaller({
30503
- environment: process.env,
30504
- stateDirectory
30505
- }),
30506
- specifications
30507
- ).prepare(signal);
30508
29835
  const sessionStore = new SqliteAcpSessionStore(config2.auditDatabasePath);
30509
29836
  const outbox = new SessionEventOutbox(config2.auditDatabasePath);
29837
+ const publisher = new DaemonSessionEventPublisher(outbox);
29838
+ const activeTurns = /* @__PURE__ */ new Map();
29839
+ const activeAttemptIds = /* @__PURE__ */ new Map();
29840
+ const recordSessionEvent = (sessionId, payload) => {
29841
+ const attemptId = activeAttemptIds.get(sessionId);
29842
+ if (attemptId === void 0) {
29843
+ publisher.recordRuntime(sessionId, payload);
29844
+ return;
29845
+ }
29846
+ publisher.recordAttempt(sessionId, payload, attemptId);
29847
+ };
30510
29848
  const sessions = new AcpSessionManager(
30511
- new NullAcpSessionObserver(),
29849
+ new DaemonAcpObserver(recordSessionEvent),
30512
29850
  sessionStore
30513
29851
  );
30514
29852
  const directories = new WorkspaceDirectoryService(
@@ -30564,6 +29902,9 @@ async function runDaemon(config2, audit, signal, timer = systemDaemonTimer) {
30564
29902
  installationObserver,
30565
29903
  nativeSessions,
30566
29904
  outbox,
29905
+ publisher,
29906
+ activeTurns,
29907
+ activeAttemptIds,
30567
29908
  announceConnection,
30568
29909
  signal,
30569
29910
  timer
@@ -30581,6 +29922,11 @@ async function runDaemon(config2, audit, signal, timer = systemDaemonTimer) {
30581
29922
  await waitForRelayRetry(signal, timer);
30582
29923
  }
30583
29924
  } finally {
29925
+ const turns = [...activeTurns.values()];
29926
+ for (const turn of turns) {
29927
+ turn.abortDaemon();
29928
+ }
29929
+ await Promise.all(turns.map((turn) => turn.completion));
30584
29930
  try {
30585
29931
  await catalogPublication;
30586
29932
  } finally {
@@ -30615,7 +29961,7 @@ Usage:
30615
29961
  Commands:
30616
29962
  pair Pair this machine and start its local daemon
30617
29963
  start Start the local daemon for a saved channel
30618
- agents Show locally available and installable Agents
29964
+ agents Show detected, missing, and integration-ready Agents
30619
29965
 
30620
29966
  Pairing grants this browser access to the machine with your user account's permissions.
30621
29967
  New conversations default to ~/.mobius/workspace; choose other directories in the browser.
@@ -30631,7 +29977,7 @@ async function main() {
30631
29977
  if (arguments_.length > 1 || arguments_.length === 1 && arguments_[0] !== "--json") {
30632
29978
  throw new Error("Usage: mobius agents [--json]");
30633
29979
  }
30634
- await mkdir6(loadDefaultWorkspace(), { recursive: true, mode: 448 });
29980
+ await mkdir4(loadDefaultWorkspace(), { recursive: true, mode: 448 });
30635
29981
  const inventory = await discoverLocalAgentInventory({
30636
29982
  defaultWorkspace: loadDefaultWorkspace(),
30637
29983
  environment: process.env,