@moxt-ai/mobius 0.0.8 → 0.0.10

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 (38) hide show
  1. package/dist/acp/session-manager.d.ts.map +1 -1
  2. package/dist/acp/session-manager.js +19 -5
  3. package/dist/acp/session-manager.js.map +1 -1
  4. package/dist/agent-catalog/agent-diagnostics.d.ts.map +1 -1
  5. package/dist/agent-catalog/agent-diagnostics.js +6 -2
  6. package/dist/agent-catalog/agent-diagnostics.js.map +1 -1
  7. package/dist/agent-catalog/discover-local-agents.d.ts +35 -7
  8. package/dist/agent-catalog/discover-local-agents.d.ts.map +1 -1
  9. package/dist/agent-catalog/discover-local-agents.js +137 -26
  10. package/dist/agent-catalog/discover-local-agents.js.map +1 -1
  11. package/dist/agent-catalog/local-agent.d.ts +2 -1
  12. package/dist/agent-catalog/local-agent.d.ts.map +1 -1
  13. package/dist/agent-catalog/local-agent.js +7 -1
  14. package/dist/agent-catalog/local-agent.js.map +1 -1
  15. package/dist/agent-installation/fixed-agent-install-recipes.d.ts +1 -0
  16. package/dist/agent-installation/fixed-agent-install-recipes.d.ts.map +1 -1
  17. package/dist/agent-installation/fixed-agent-install-recipes.js +48 -0
  18. package/dist/agent-installation/fixed-agent-install-recipes.js.map +1 -1
  19. package/dist/agent-installation/fixed-installation-executor.d.ts.map +1 -1
  20. package/dist/agent-installation/fixed-installation-executor.js +2 -0
  21. package/dist/agent-installation/fixed-installation-executor.js.map +1 -1
  22. package/dist/agent-installation/managed-adapter-installer.d.ts +3 -2
  23. package/dist/agent-installation/managed-adapter-installer.d.ts.map +1 -1
  24. package/dist/agent-installation/managed-adapter-installer.js +25 -126
  25. package/dist/agent-installation/managed-adapter-installer.js.map +1 -1
  26. package/dist/agent-installation/managed-npm-package.d.ts +24 -0
  27. package/dist/agent-installation/managed-npm-package.d.ts.map +1 -0
  28. package/dist/agent-installation/managed-npm-package.js +227 -0
  29. package/dist/agent-installation/managed-npm-package.js.map +1 -0
  30. package/dist/agent-installation/pi-managed-packages.d.ts +4 -0
  31. package/dist/agent-installation/pi-managed-packages.d.ts.map +1 -0
  32. package/dist/agent-installation/pi-managed-packages.js +4 -0
  33. package/dist/agent-installation/pi-managed-packages.js.map +1 -0
  34. package/dist/cli.js +625 -178
  35. package/dist/cli.js.map +4 -4
  36. package/dist/index.js +616 -171
  37. package/dist/index.js.map +4 -4
  38. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -388,7 +388,11 @@ var LocalAgentDefinition = class {
388
388
  environment;
389
389
  id;
390
390
  label;
391
- constructor(id, label, command, arguments_, environment = {}, adapterVersion = "", agentVersion = "", adapterIdentity = readTrustedIdentity(command), agentIdentity = adapterIdentity) {
391
+ promptTimeoutMilliseconds;
392
+ constructor(id, label, command, arguments_, environment = {}, adapterVersion = "", agentVersion = "", adapterIdentity = readTrustedIdentity(command), agentIdentity = adapterIdentity, promptTimeoutMilliseconds = 30 * 60 * 1e3) {
393
+ if (!Number.isSafeInteger(promptTimeoutMilliseconds) || promptTimeoutMilliseconds < 1) {
394
+ throw new Error("The local Agent prompt deadline is invalid");
395
+ }
392
396
  this.adapterIdentity = adapterIdentity;
393
397
  this.adapterPath = adapterIdentity.realPath;
394
398
  this.adapterVersion = adapterVersion;
@@ -396,6 +400,7 @@ var LocalAgentDefinition = class {
396
400
  this.agentVersion = agentVersion;
397
401
  this.id = id;
398
402
  this.label = label;
403
+ this.promptTimeoutMilliseconds = promptTimeoutMilliseconds;
399
404
  this.command = adapterIdentity.realPath;
400
405
  this.arguments = Object.freeze([...arguments_]);
401
406
  this.environment = Object.freeze({ ...environment });
@@ -22559,7 +22564,7 @@ var AcpProcessSession = class _AcpProcessSession {
22559
22564
  }
22560
22565
  initialize = async (signal, origin) => {
22561
22566
  await this.#initializeAgent(signal);
22562
- const stored = origin?.kind === "import" ? new FoundAcpStoredSession(
22567
+ let stored = origin?.kind === "import" ? new FoundAcpStoredSession(
22563
22568
  new AcpStoredSession(
22564
22569
  this.#mobiusSessionId,
22565
22570
  this.#agentId,
@@ -22569,6 +22574,10 @@ var AcpProcessSession = class _AcpProcessSession {
22569
22574
  true
22570
22575
  )
22571
22576
  ) : this.#store.read(this.#mobiusSessionId);
22577
+ if (stored instanceof FoundAcpStoredSession && !stored.session.prompted) {
22578
+ this.#store.remove(this.#mobiusSessionId);
22579
+ stored = this.#store.read(this.#mobiusSessionId);
22580
+ }
22572
22581
  if (stored instanceof DeletedAcpStoredSession)
22573
22582
  throw new AcpExecutionError(
22574
22583
  "The native Agent session was deleted. Start a new chat.",
@@ -22684,6 +22693,15 @@ var AcpProcessSession = class _AcpProcessSession {
22684
22693
  );
22685
22694
  this.#nativeSessionId = created.sessionId;
22686
22695
  lifecycleResponse = created;
22696
+ }
22697
+ const lifecycleRecord = isRecord3(lifecycleResponse) ? lifecycleResponse : {};
22698
+ this.#configOptions = normalizeConfigOptions(
22699
+ lifecycleRecord["configOptions"],
22700
+ lifecycleRecord["modes"]
22701
+ );
22702
+ await this.#updateTail;
22703
+ signal.throwIfAborted();
22704
+ if (this.#prompted) {
22687
22705
  this.#store.write(
22688
22706
  new AcpStoredSession(
22689
22707
  this.#mobiusSessionId,
@@ -22691,27 +22709,10 @@ var AcpProcessSession = class _AcpProcessSession {
22691
22709
  this.#nativeSessionId,
22692
22710
  this.#cwd,
22693
22711
  this.#additionalDirectories,
22694
- false
22712
+ true
22695
22713
  )
22696
22714
  );
22697
22715
  }
22698
- const lifecycleRecord = isRecord3(lifecycleResponse) ? lifecycleResponse : {};
22699
- this.#configOptions = normalizeConfigOptions(
22700
- lifecycleRecord["configOptions"],
22701
- lifecycleRecord["modes"]
22702
- );
22703
- await this.#updateTail;
22704
- signal.throwIfAborted();
22705
- this.#store.write(
22706
- new AcpStoredSession(
22707
- this.#mobiusSessionId,
22708
- this.#agentId,
22709
- this.#nativeSessionId,
22710
- this.#cwd,
22711
- this.#additionalDirectories,
22712
- this.#prompted
22713
- )
22714
- );
22715
22716
  };
22716
22717
  listNativeSessions = async (cursor, signal) => {
22717
22718
  if (!this.#capabilities.listSessions)
@@ -23591,12 +23592,27 @@ var AcpSessionManager = class {
23591
23592
  "session_busy"
23592
23593
  );
23593
23594
  }
23595
+ const deadlineController = new AbortController();
23596
+ const deadlineError = new AcpExecutionError(
23597
+ "The local Agent prompt exceeded its deadline",
23598
+ {},
23599
+ "prompt_timeout"
23600
+ );
23601
+ const deadline = setTimeout(
23602
+ () => deadlineController.abort(deadlineError),
23603
+ options.agent.promptTimeoutMilliseconds
23604
+ );
23605
+ deadline.unref();
23606
+ const boundedOptions = {
23607
+ ...options,
23608
+ signal: AbortSignal.any([options.signal, deadlineController.signal])
23609
+ };
23594
23610
  this.#activeSessionIds.add(options.sessionId);
23595
23611
  try {
23596
23612
  if (this.#cancellationRequests.has(options.sessionId)) {
23597
23613
  return { stopReason: "cancelled" };
23598
23614
  }
23599
- const runtime = await this.ensureSession(options);
23615
+ const runtime = await this.ensureSession(boundedOptions);
23600
23616
  if (this.#nativeOperations.has(
23601
23617
  `${options.agent.id}:${runtime.nativeSessionId()}`
23602
23618
  ))
@@ -23608,7 +23624,7 @@ var AcpSessionManager = class {
23608
23624
  if (this.#cancellationRequests.has(options.sessionId)) {
23609
23625
  return { stopReason: "cancelled" };
23610
23626
  }
23611
- return await runtime.prompt(options);
23627
+ return await runtime.prompt(boundedOptions);
23612
23628
  } catch (error61) {
23613
23629
  const failedRuntime = this.#sessions.get(options.sessionId);
23614
23630
  if (failedRuntime !== void 0) {
@@ -23622,6 +23638,7 @@ var AcpSessionManager = class {
23622
23638
  cause: error61
23623
23639
  });
23624
23640
  } finally {
23641
+ clearTimeout(deadline);
23625
23642
  this.#activeSessionIds.delete(options.sessionId);
23626
23643
  this.#cancellationRequests.delete(options.sessionId);
23627
23644
  }
@@ -23923,16 +23940,17 @@ import {
23923
23940
  writeFile
23924
23941
  } from "node:fs/promises";
23925
23942
  import { hostname as hostname3 } from "node:os";
23926
- import { basename, join as join7, resolve as resolve3 } from "node:path";
23943
+ import { basename, join as join8, resolve as resolve3 } from "node:path";
23927
23944
  import { fetch } from "undici";
23928
23945
 
23929
23946
  // src/agent-catalog/discover-local-agents.ts
23930
23947
  import { spawn as spawn3 } from "node:child_process";
23931
- import { isAbsolute, join as join6 } from "node:path";
23948
+ import { isAbsolute as isAbsolute2, join as join7 } from "node:path";
23932
23949
  import {
23933
23950
  methods as methods3,
23934
23951
  ndJsonStream as ndJsonStream2,
23935
- PROTOCOL_VERSION as PROTOCOL_VERSION2
23952
+ PROTOCOL_VERSION as PROTOCOL_VERSION2,
23953
+ RequestError
23936
23954
  } from "@agentclientprotocol/sdk";
23937
23955
 
23938
23956
  // src/agent-installation/installation-grants.ts
@@ -23978,6 +23996,9 @@ async function readGrantedAgents(stateDirectory) {
23978
23996
  }
23979
23997
 
23980
23998
  // src/agent-installation/managed-adapter-installer.ts
23999
+ import { join as join6 } from "node:path";
24000
+
24001
+ // src/agent-installation/managed-npm-package.ts
23981
24002
  import {
23982
24003
  mkdir,
23983
24004
  mkdtemp,
@@ -23987,15 +24008,35 @@ import {
23987
24008
  rm,
23988
24009
  stat as stat2
23989
24010
  } from "node:fs/promises";
23990
- import { delimiter, dirname as dirname3, join as join5, relative } from "node:path";
23991
- var ADAPTER_INSTALL_TIMEOUT_MILLISECONDS = 2 * 60 * 1e3;
24011
+ import { delimiter, dirname as dirname3, isAbsolute, join as join5, relative, sep } from "node:path";
24012
+ var INSTALL_TIMEOUT_MILLISECONDS = 5 * 60 * 1e3;
23992
24013
  var PACKAGE_METADATA_LIMIT_BYTES = 64 * 1024;
23993
- var ManagedAdapterInstallError = class extends Error {
24014
+ var PACKAGE_LOCK_LIMIT_BYTES = 8 * 1024 * 1024;
24015
+ var ManagedNpmPackageDefinition = class {
24016
+ executableName;
24017
+ packageName;
24018
+ version;
24019
+ constructor(packageName, version2, executableName) {
24020
+ this.executableName = executableName;
24021
+ this.packageName = packageName;
24022
+ this.version = version2;
24023
+ }
24024
+ };
24025
+ var SriManagedNpmPackageDefinition = class extends ManagedNpmPackageDefinition {
24026
+ integrity;
24027
+ tarballUrl;
24028
+ constructor(packageName, version2, executableName, integrity, tarballUrl) {
24029
+ super(packageName, version2, executableName);
24030
+ this.integrity = integrity;
24031
+ this.tarballUrl = tarballUrl;
24032
+ }
24033
+ };
24034
+ var ManagedNpmPackageError = class extends Error {
23994
24035
  code;
23995
24036
  constructor(code, message, options = {}) {
23996
24037
  super(message, options);
23997
24038
  this.code = code;
23998
- this.name = "ManagedAdapterInstallError";
24039
+ this.name = "ManagedNpmPackageError";
23999
24040
  }
24000
24041
  };
24001
24042
  function isRecord5(value) {
@@ -24004,28 +24045,43 @@ function isRecord5(value) {
24004
24045
  function packagePath(root, packageName) {
24005
24046
  return join5(root, "node_modules", ...packageName.split("/"));
24006
24047
  }
24007
- async function readPackageJson(path2) {
24008
- const handle = await open3(path2, "r");
24048
+ function isContainedPath(root, candidate) {
24049
+ const difference = relative(root, candidate);
24050
+ return difference.length > 0 && difference !== ".." && !difference.startsWith(`..${sep}`) && !isAbsolute(difference);
24051
+ }
24052
+ async function readJsonRecord(path2, maximumBytes) {
24009
24053
  try {
24010
- const metadata = await handle.stat();
24011
- if (!metadata.isFile() || metadata.size > PACKAGE_METADATA_LIMIT_BYTES) {
24012
- throw new ManagedAdapterInstallError(
24013
- "adapter_verification_failed",
24014
- "The managed adapter package metadata is invalid"
24054
+ const handle = await open3(path2, "r");
24055
+ try {
24056
+ const metadata = await handle.stat();
24057
+ if (!metadata.isFile() || metadata.size > maximumBytes) {
24058
+ throw new ManagedNpmPackageError(
24059
+ "managed_package_verification_failed",
24060
+ "The managed npm package metadata is invalid"
24061
+ );
24062
+ }
24063
+ const value = JSON.parse(
24064
+ await handle.readFile({ encoding: "utf8" })
24015
24065
  );
24066
+ if (!isRecord5(value)) {
24067
+ throw new ManagedNpmPackageError(
24068
+ "managed_package_verification_failed",
24069
+ "The managed npm package metadata is invalid"
24070
+ );
24071
+ }
24072
+ return value;
24073
+ } finally {
24074
+ await handle.close();
24016
24075
  }
24017
- const value = JSON.parse(
24018
- await handle.readFile({ encoding: "utf8" })
24019
- );
24020
- if (!isRecord5(value)) {
24021
- throw new ManagedAdapterInstallError(
24022
- "adapter_verification_failed",
24023
- "The managed adapter package metadata is invalid"
24024
- );
24076
+ } catch (error61) {
24077
+ if (error61 instanceof ManagedNpmPackageError) {
24078
+ throw error61;
24025
24079
  }
24026
- return value;
24027
- } finally {
24028
- await handle.close();
24080
+ throw new ManagedNpmPackageError(
24081
+ "managed_package_verification_failed",
24082
+ "The managed npm package metadata is invalid",
24083
+ { cause: error61 }
24084
+ );
24029
24085
  }
24030
24086
  }
24031
24087
  function readBinPath(packageMetadata, executableName) {
@@ -24036,83 +24092,125 @@ function readBinPath(packageMetadata, executableName) {
24036
24092
  if (isRecord5(bin) && typeof bin[executableName] === "string") {
24037
24093
  return bin[executableName];
24038
24094
  }
24039
- throw new ManagedAdapterInstallError(
24040
- "adapter_verification_failed",
24041
- "The managed adapter executable declaration is invalid"
24095
+ throw new ManagedNpmPackageError(
24096
+ "managed_package_verification_failed",
24097
+ "The managed npm package executable declaration is invalid"
24042
24098
  );
24043
24099
  }
24044
- async function validateManagedAdapter(root, specification) {
24100
+ function verifyPackageLock(lock, definition) {
24101
+ if (lock["lockfileVersion"] !== 3) {
24102
+ throw new ManagedNpmPackageError(
24103
+ "managed_package_verification_failed",
24104
+ "The managed npm package lockfile is invalid"
24105
+ );
24106
+ }
24107
+ const packages = lock["packages"];
24108
+ if (!isRecord5(packages)) {
24109
+ throw new ManagedNpmPackageError(
24110
+ "managed_package_verification_failed",
24111
+ "The managed npm package lockfile is invalid"
24112
+ );
24113
+ }
24114
+ const suffix = `node_modules/${definition.packageName}`;
24115
+ let entry;
24116
+ let matches = 0;
24117
+ for (const [key, candidate] of Object.entries(packages)) {
24118
+ const normalizedKey = key.replaceAll("\\", "/");
24119
+ if (normalizedKey === suffix || normalizedKey.endsWith(`/${suffix}`)) {
24120
+ entry = candidate;
24121
+ matches += 1;
24122
+ }
24123
+ }
24124
+ if (matches !== 1 || !isRecord5(entry) || entry["integrity"] !== definition.integrity || entry["resolved"] !== definition.tarballUrl || entry["version"] !== definition.version) {
24125
+ throw new ManagedNpmPackageError(
24126
+ "managed_package_verification_failed",
24127
+ "The managed npm package lockfile does not match the pinned artifact"
24128
+ );
24129
+ }
24130
+ }
24131
+ async function validateManagedNpmPackage(root, definition) {
24132
+ try {
24133
+ return await validateManagedNpmPackageContents(root, definition);
24134
+ } catch (error61) {
24135
+ if (error61 instanceof ManagedNpmPackageError) {
24136
+ throw error61;
24137
+ }
24138
+ throw new ManagedNpmPackageError(
24139
+ "managed_package_verification_failed",
24140
+ "The managed npm package is invalid",
24141
+ { cause: error61 }
24142
+ );
24143
+ }
24144
+ }
24145
+ async function validateManagedNpmPackageContents(root, definition) {
24045
24146
  const rootPath = await realpath2(root);
24046
24147
  const packageRoot = await realpath2(
24047
- packagePath(rootPath, specification.adapterPackage)
24148
+ packagePath(rootPath, definition.packageName)
24149
+ );
24150
+ if (!isContainedPath(rootPath, packageRoot)) {
24151
+ throw new ManagedNpmPackageError(
24152
+ "managed_package_verification_failed",
24153
+ "The managed npm package escaped its private cache"
24154
+ );
24155
+ }
24156
+ const metadata = await readJsonRecord(
24157
+ join5(packageRoot, "package.json"),
24158
+ PACKAGE_METADATA_LIMIT_BYTES
24048
24159
  );
24049
- const packageDifference = relative(rootPath, packageRoot);
24050
- if (packageDifference.startsWith("..") || packageDifference.length === 0) {
24051
- throw new ManagedAdapterInstallError(
24052
- "adapter_verification_failed",
24053
- "The managed adapter package escaped its private cache"
24160
+ if (metadata["name"] !== definition.packageName || metadata["version"] !== definition.version) {
24161
+ throw new ManagedNpmPackageError(
24162
+ "managed_package_verification_failed",
24163
+ "The managed npm package identity is invalid"
24054
24164
  );
24055
24165
  }
24056
- const metadata = await readPackageJson(join5(packageRoot, "package.json"));
24057
- if (metadata["name"] !== specification.adapterPackage || metadata["version"] !== specification.adapterVersion) {
24058
- throw new ManagedAdapterInstallError(
24059
- "adapter_verification_failed",
24060
- "The managed adapter package identity is invalid"
24166
+ if (definition instanceof SriManagedNpmPackageDefinition) {
24167
+ verifyPackageLock(
24168
+ await readJsonRecord(
24169
+ join5(rootPath, "package-lock.json"),
24170
+ PACKAGE_LOCK_LIMIT_BYTES
24171
+ ),
24172
+ definition
24061
24173
  );
24062
24174
  }
24063
- const declaredBin = readBinPath(metadata, specification.adapterExecutable);
24175
+ const declaredBin = readBinPath(metadata, definition.executableName);
24064
24176
  const executable = await resolveExecutablePath(
24065
24177
  join5(packageRoot, declaredBin)
24066
24178
  );
24067
- if (executable === null) {
24068
- throw new ManagedAdapterInstallError(
24069
- "adapter_verification_failed",
24070
- "The managed adapter executable is invalid"
24071
- );
24072
- }
24073
- const executableDifference = relative(rootPath, executable.path);
24074
- if (executableDifference.startsWith("..") || executableDifference.length === 0) {
24075
- throw new ManagedAdapterInstallError(
24076
- "adapter_verification_failed",
24077
- "The managed adapter executable escaped its private cache"
24179
+ if (executable === null || !isContainedPath(rootPath, executable.path)) {
24180
+ throw new ManagedNpmPackageError(
24181
+ "managed_package_verification_failed",
24182
+ "The managed npm package executable is invalid"
24078
24183
  );
24079
24184
  }
24080
24185
  return executable;
24081
24186
  }
24082
- var ManagedAdapterInstaller = class {
24083
- #environment;
24084
- #stateDirectory;
24085
- constructor(options) {
24086
- this.#environment = options.environment;
24087
- this.#stateDirectory = options.stateDirectory;
24088
- }
24089
- install = async (specification, signal) => {
24187
+ var ManagedNpmPackageInstaller = class {
24188
+ install = async (root, definition, environment, signal) => {
24090
24189
  signal.throwIfAborted();
24091
- const agentCache = join5(this.#stateDirectory, "adapters", specification.id);
24092
- const published = join5(agentCache, specification.adapterVersion);
24093
24190
  try {
24094
- const metadata = await stat2(published);
24191
+ const metadata = await stat2(root);
24095
24192
  if (metadata.isDirectory()) {
24096
- return await validateManagedAdapter(published, specification);
24193
+ return await validateManagedNpmPackage(root, definition);
24097
24194
  }
24098
24195
  } catch (error61) {
24099
24196
  if (!(error61 instanceof Error) || !("code" in error61) || error61.code !== "ENOENT") {
24100
24197
  throw error61;
24101
24198
  }
24102
24199
  }
24103
- await mkdir(agentCache, { mode: 448, recursive: true });
24200
+ const parent = dirname3(root);
24201
+ await mkdir(parent, { mode: 448, recursive: true });
24104
24202
  const staging = await mkdtemp(
24105
- join5(agentCache, `.${specification.adapterVersion}.staging-`)
24203
+ join5(parent, `.${definition.version}.staging-`)
24106
24204
  );
24107
24205
  try {
24108
24206
  const npm = await findExecutableOnPath(
24109
24207
  process.platform === "win32" ? "npm.cmd" : "npm",
24110
- this.#environment
24208
+ environment
24111
24209
  );
24112
24210
  if (npm === null) {
24113
- throw new ManagedAdapterInstallError(
24211
+ throw new ManagedNpmPackageError(
24114
24212
  "package_manager_not_found",
24115
- "A supported npm executable is required to install the ACP adapter"
24213
+ "A supported npm executable is required to install the managed package"
24116
24214
  );
24117
24215
  }
24118
24216
  await runBoundedProcess({
@@ -24124,51 +24222,57 @@ var ManagedAdapterInstaller = class {
24124
24222
  "--ignore-scripts",
24125
24223
  "--no-audit",
24126
24224
  "--no-fund",
24127
- "--package-lock=false",
24128
- "--save=false",
24225
+ "--package-lock=true",
24226
+ "--save-exact",
24129
24227
  "--registry=https://registry.npmjs.org/",
24130
- `${specification.adapterPackage}@${specification.adapterVersion}`
24228
+ `${definition.packageName}@${definition.version}`
24131
24229
  ],
24132
24230
  command: npm.path,
24133
24231
  cwd: staging,
24134
24232
  environment: {
24135
24233
  HOME: join5(staging, "home"),
24136
24234
  NPM_CONFIG_AUDIT: "false",
24235
+ NPM_CONFIG_CACHE: join5(staging, ".npm-cache"),
24137
24236
  NPM_CONFIG_FUND: "false",
24138
24237
  NPM_CONFIG_IGNORE_SCRIPTS: "true",
24139
24238
  NPM_CONFIG_OMIT: "optional",
24239
+ NPM_CONFIG_PACKAGE_LOCK: "true",
24140
24240
  NPM_CONFIG_REGISTRY: "https://registry.npmjs.org/",
24141
24241
  PATH: `${dirname3(process.execPath)}${delimiter}/usr/bin${delimiter}/bin`
24142
24242
  },
24143
24243
  outputLimitBytes: 64 * 1024,
24144
24244
  signal,
24145
- timeoutMilliseconds: ADAPTER_INSTALL_TIMEOUT_MILLISECONDS
24245
+ timeoutMilliseconds: INSTALL_TIMEOUT_MILLISECONDS
24146
24246
  });
24147
- await validateManagedAdapter(staging, specification);
24247
+ await Promise.all([
24248
+ rm(join5(staging, ".npm-cache"), { force: true, recursive: true }),
24249
+ rm(join5(staging, "home"), { force: true, recursive: true })
24250
+ ]);
24251
+ await validateManagedNpmPackage(staging, definition);
24148
24252
  try {
24149
- await rename(staging, published);
24253
+ await rename(staging, root);
24150
24254
  } catch (error61) {
24151
24255
  try {
24152
- return await validateManagedAdapter(published, specification);
24256
+ return await validateManagedNpmPackage(root, definition);
24153
24257
  } catch {
24154
- throw new ManagedAdapterInstallError(
24155
- "adapter_publish_failed",
24156
- "The managed adapter could not be published",
24258
+ throw new ManagedNpmPackageError(
24259
+ "managed_package_publish_failed",
24260
+ "The managed npm package could not be published",
24157
24261
  { cause: error61 }
24158
24262
  );
24159
24263
  }
24160
24264
  }
24161
- return await validateManagedAdapter(published, specification);
24265
+ return await validateManagedNpmPackage(root, definition);
24162
24266
  } catch (error61) {
24163
24267
  if (signal.aborted) {
24164
24268
  signal.throwIfAborted();
24165
24269
  }
24166
- if (error61 instanceof ManagedAdapterInstallError) {
24270
+ if (error61 instanceof ManagedNpmPackageError) {
24167
24271
  throw error61;
24168
24272
  }
24169
- throw new ManagedAdapterInstallError(
24170
- "adapter_install_failed",
24171
- "The pinned ACP adapter could not be installed",
24273
+ throw new ManagedNpmPackageError(
24274
+ "managed_package_install_failed",
24275
+ "The pinned npm package could not be installed",
24172
24276
  { cause: error61 }
24173
24277
  );
24174
24278
  } finally {
@@ -24177,20 +24281,152 @@ var ManagedAdapterInstaller = class {
24177
24281
  };
24178
24282
  };
24179
24283
 
24284
+ // src/agent-installation/managed-adapter-installer.ts
24285
+ var ManagedAdapterInstallError = class extends Error {
24286
+ code;
24287
+ constructor(code, message, options = {}) {
24288
+ super(message, options);
24289
+ this.code = code;
24290
+ this.name = "ManagedAdapterInstallError";
24291
+ }
24292
+ };
24293
+ function translateError(error61) {
24294
+ if (error61 instanceof ManagedAdapterInstallError) {
24295
+ return error61;
24296
+ }
24297
+ if (error61 instanceof ManagedNpmPackageError) {
24298
+ if (error61.code === "package_manager_not_found") {
24299
+ return new ManagedAdapterInstallError(
24300
+ error61.code,
24301
+ "A supported npm executable is required to install the ACP adapter",
24302
+ { cause: error61 }
24303
+ );
24304
+ }
24305
+ if (error61.code === "managed_package_verification_failed") {
24306
+ return new ManagedAdapterInstallError(
24307
+ "adapter_verification_failed",
24308
+ "The managed adapter did not match its pinned artifact",
24309
+ { cause: error61 }
24310
+ );
24311
+ }
24312
+ if (error61.code === "managed_package_publish_failed") {
24313
+ return new ManagedAdapterInstallError(
24314
+ "adapter_publish_failed",
24315
+ "The managed adapter could not be published",
24316
+ { cause: error61 }
24317
+ );
24318
+ }
24319
+ }
24320
+ return new ManagedAdapterInstallError(
24321
+ "adapter_install_failed",
24322
+ "The pinned ACP adapter could not be installed",
24323
+ { cause: error61 }
24324
+ );
24325
+ }
24326
+ async function validateManagedAdapter(root, specification) {
24327
+ try {
24328
+ return await validateManagedNpmPackage(
24329
+ root,
24330
+ specification.adapterPackageDefinition
24331
+ );
24332
+ } catch (error61) {
24333
+ throw translateError(error61);
24334
+ }
24335
+ }
24336
+ var ManagedAdapterInstaller = class {
24337
+ #environment;
24338
+ #npmInstaller;
24339
+ #stateDirectory;
24340
+ constructor(options, npmInstaller = new ManagedNpmPackageInstaller()) {
24341
+ this.#environment = options.environment;
24342
+ this.#npmInstaller = npmInstaller;
24343
+ this.#stateDirectory = options.stateDirectory;
24344
+ }
24345
+ install = async (specification, signal) => {
24346
+ const root = join6(
24347
+ this.#stateDirectory,
24348
+ "adapters",
24349
+ specification.id,
24350
+ specification.adapterVersion
24351
+ );
24352
+ try {
24353
+ return await this.#npmInstaller.install(
24354
+ root,
24355
+ specification.adapterPackageDefinition,
24356
+ this.#environment,
24357
+ signal
24358
+ );
24359
+ } catch (error61) {
24360
+ if (signal.aborted) {
24361
+ signal.throwIfAborted();
24362
+ }
24363
+ throw translateError(error61);
24364
+ }
24365
+ };
24366
+ };
24367
+
24368
+ // src/agent-installation/pi-managed-packages.ts
24369
+ var PI_ACP_PACKAGE = new SriManagedNpmPackageDefinition(
24370
+ "pi-acp",
24371
+ "0.0.33",
24372
+ "pi-acp",
24373
+ "sha512-vX9kY1tK14E72G4dBAx+RGCk/k7XPjTHls6dLUxA8WSkBav6B6JHuSBv3eusp50LCR/GTRsR2kIKsG0Z5jANzw==",
24374
+ "https://registry.npmjs.org/pi-acp/-/pi-acp-0.0.33.tgz"
24375
+ );
24376
+ var PI_AGENT_PACKAGE = new SriManagedNpmPackageDefinition(
24377
+ "@earendil-works/pi-coding-agent",
24378
+ "0.85.0",
24379
+ "pi",
24380
+ "sha512-INxVkLAVfAMju5MojJpmyu/0bMP+r+ffZuS7UqVv32E2JwHBRbcHfELDfmFNvapEbgYfKN2r9OYO1p3TqDBR+g==",
24381
+ "https://registry.npmjs.org/@earendil-works/pi-coding-agent/-/pi-coding-agent-0.85.0.tgz"
24382
+ );
24383
+
24180
24384
  // src/agent-catalog/discover-local-agents.ts
24181
24385
  var VERSION_PROBE_TIMEOUT_MILLISECONDS = 3e3;
24182
24386
  var ACP_PROBE_TIMEOUT_MILLISECONDS = 5e3;
24183
24387
  var ACP_OUTPUT_LIMIT_BYTES = 1024 * 1024;
24388
+ var DEFAULT_PROMPT_TIMEOUT_MILLISECONDS = 30 * 60 * 1e3;
24389
+ var PI_ACP_PROBE_TIMEOUT_MILLISECONDS = 3e4;
24390
+ var PI_PROMPT_TIMEOUT_MILLISECONDS = 5 * 60 * 1e3;
24184
24391
  var LocalAgentSpecification = class {
24392
+ acpProbeTimeoutMilliseconds = ACP_PROBE_TIMEOUT_MILLISECONDS;
24393
+ authenticationCommand = () => "";
24394
+ adapterVersionArguments = ["--version"];
24395
+ agentVersionArguments = ["--version"];
24396
+ promptTimeoutMilliseconds = DEFAULT_PROMPT_TIMEOUT_MILLISECONDS;
24397
+ get adapterExecutable() {
24398
+ return this.adapterPackageDefinition.executableName;
24399
+ }
24400
+ get adapterPackage() {
24401
+ return this.adapterPackageDefinition.packageName;
24402
+ }
24403
+ get adapterVersion() {
24404
+ return this.adapterPackageDefinition.version;
24405
+ }
24406
+ resolveManagedAgent = async (stateDirectory, platform) => {
24407
+ const executable = await resolveExecutablePath(
24408
+ join7(stateDirectory, ...this.managedAgentExecutablePath),
24409
+ platform
24410
+ );
24411
+ if (executable === null) {
24412
+ throw new Error("The managed Agent executable is unavailable");
24413
+ }
24414
+ return executable;
24415
+ };
24185
24416
  recoveryCommand = () => `npm install -g --omit=optional ${this.adapterPackage}@${this.adapterVersion}`;
24186
24417
  supportsInstallation = (platform, architecture) => (platform === "darwin" || platform === "linux") && (architecture === "arm64" || architecture === "x64");
24418
+ verifyAcp = (_connection, _initialized, _defaultWorkspace, _signal) => Promise.resolve();
24419
+ };
24420
+ var BridgedAcpAgentDefinition = class extends LocalAgentSpecification {
24187
24421
  };
24188
- var CodexAgentSpecification = class extends LocalAgentSpecification {
24422
+ var CodexAgentSpecification = class extends BridgedAcpAgentDefinition {
24189
24423
  adapterEnvironmentVariable = "CODEX_PATH";
24190
- adapterExecutable = "codex-acp";
24191
24424
  adapterOverrideVariable = "MOBIUS_CODEX_ACP_PATH";
24192
- adapterPackage = "@agentclientprotocol/codex-acp";
24193
- adapterVersion = "1.8.0";
24425
+ adapterPackageDefinition = new ManagedNpmPackageDefinition(
24426
+ "@agentclientprotocol/codex-acp",
24427
+ "1.8.0",
24428
+ "codex-acp"
24429
+ );
24194
24430
  agentExecutable = "codex";
24195
24431
  agentOverrideVariable = "MOBIUS_CODEX_PATH";
24196
24432
  id = "codex";
@@ -24207,12 +24443,14 @@ var CodexAgentSpecification = class extends LocalAgentSpecification {
24207
24443
  ];
24208
24444
  managedAgentExecutablePath = ["agents", "codex", "bin", "codex"];
24209
24445
  };
24210
- var ClaudeCodeAgentSpecification = class extends LocalAgentSpecification {
24446
+ var ClaudeCodeAgentSpecification = class extends BridgedAcpAgentDefinition {
24211
24447
  adapterEnvironmentVariable = "CLAUDE_CODE_EXECUTABLE";
24212
- adapterExecutable = "claude-agent-acp";
24213
24448
  adapterOverrideVariable = "MOBIUS_CLAUDE_ACP_PATH";
24214
- adapterPackage = "@agentclientprotocol/claude-agent-acp";
24215
- adapterVersion = "0.73.0";
24449
+ adapterPackageDefinition = new ManagedNpmPackageDefinition(
24450
+ "@agentclientprotocol/claude-agent-acp",
24451
+ "0.73.0",
24452
+ "claude-agent-acp"
24453
+ );
24216
24454
  agentExecutable = "claude";
24217
24455
  agentOverrideVariable = "MOBIUS_CLAUDE_PATH";
24218
24456
  id = "claude";
@@ -24236,10 +24474,86 @@ var ClaudeCodeAgentSpecification = class extends LocalAgentSpecification {
24236
24474
  "claude"
24237
24475
  ];
24238
24476
  };
24477
+ var PiAgentSpecification = class extends BridgedAcpAgentDefinition {
24478
+ acpProbeTimeoutMilliseconds = PI_ACP_PROBE_TIMEOUT_MILLISECONDS;
24479
+ adapterEnvironmentVariable = "PI_ACP_PI_COMMAND";
24480
+ adapterOverrideVariable = "MOBIUS_PI_ACP_PATH";
24481
+ adapterPackageDefinition = PI_ACP_PACKAGE;
24482
+ adapterVersionArguments = [];
24483
+ authenticationCommand = () => "pi-acp --terminal-login";
24484
+ agentExecutable = "pi";
24485
+ agentOverrideVariable = "MOBIUS_PI_PATH";
24486
+ id = "pi";
24487
+ label = "Pi";
24488
+ managedAdapterExecutablePath = [
24489
+ "adapters",
24490
+ "pi",
24491
+ PI_ACP_PACKAGE.version,
24492
+ "node_modules",
24493
+ "pi-acp",
24494
+ "dist",
24495
+ "index.js"
24496
+ ];
24497
+ managedAgentExecutablePath = [
24498
+ "agents",
24499
+ "pi",
24500
+ PI_AGENT_PACKAGE.version,
24501
+ "node_modules",
24502
+ "@earendil-works",
24503
+ "pi-coding-agent",
24504
+ "dist",
24505
+ "bundle",
24506
+ "cli.js"
24507
+ ];
24508
+ promptTimeoutMilliseconds = PI_PROMPT_TIMEOUT_MILLISECONDS;
24509
+ resolveManagedAgent = async (stateDirectory, _platform) => await validateManagedNpmPackage(
24510
+ join7(stateDirectory, "agents", this.id, PI_AGENT_PACKAGE.version),
24511
+ PI_AGENT_PACKAGE
24512
+ );
24513
+ verifyAcp = async (connection, initialized, defaultWorkspace, signal) => {
24514
+ const capabilities = initialized.agentCapabilities ?? {};
24515
+ if (capabilities.loadSession !== true) {
24516
+ throw new AgentProbeError(
24517
+ "acp_incompatible",
24518
+ "Pi ACP adapter does not support session recovery"
24519
+ );
24520
+ }
24521
+ const session = await connection.agent.request(
24522
+ methods3.agent.session.new,
24523
+ {
24524
+ additionalDirectories: [],
24525
+ cwd: defaultWorkspace,
24526
+ mcpServers: []
24527
+ },
24528
+ { cancellationSignal: signal }
24529
+ );
24530
+ if (session.sessionId.length === 0) {
24531
+ throw new AgentProbeError(
24532
+ "acp_incompatible",
24533
+ "Pi ACP adapter returned an invalid session"
24534
+ );
24535
+ }
24536
+ const prompt = await connection.agent.request(
24537
+ methods3.agent.session.prompt,
24538
+ {
24539
+ prompt: [{ text: "/session", type: "text" }],
24540
+ sessionId: session.sessionId
24541
+ },
24542
+ { cancellationSignal: signal }
24543
+ );
24544
+ if (prompt.stopReason !== "end_turn") {
24545
+ throw new AgentProbeError(
24546
+ "acp_incompatible",
24547
+ "Pi ACP adapter did not complete its conformance prompt"
24548
+ );
24549
+ }
24550
+ };
24551
+ };
24239
24552
  function supportedLocalAgentSpecifications() {
24240
24553
  return Object.freeze([
24241
24554
  new CodexAgentSpecification(),
24242
- new ClaudeCodeAgentSpecification()
24555
+ new ClaudeCodeAgentSpecification(),
24556
+ new PiAgentSpecification()
24243
24557
  ]);
24244
24558
  }
24245
24559
  var AgentDiscovery = class {
@@ -24292,6 +24606,14 @@ var IncompatibleAdapter = class extends UnavailableAgent {
24292
24606
  super(specification);
24293
24607
  }
24294
24608
  };
24609
+ var AuthenticationRequiredAgent = class extends UnavailableAgent {
24610
+ code = "authentication_required";
24611
+ message = "Agent authentication is required";
24612
+ status = "authentication_required";
24613
+ constructor(specification) {
24614
+ super(specification);
24615
+ }
24616
+ };
24295
24617
  var LocalAgentInventory = class {
24296
24618
  available;
24297
24619
  discoveries;
@@ -24313,7 +24635,10 @@ var LocalAgentInventory = class {
24313
24635
  this.discoveries = Object.freeze([...discoveries]);
24314
24636
  this.installable = Object.freeze(
24315
24637
  unavailable.filter(
24316
- (discovery) => discovery.specification.supportsInstallation(platform, architecture)
24638
+ (discovery) => !(discovery instanceof AuthenticationRequiredAgent) && discovery.specification.supportsInstallation(
24639
+ platform,
24640
+ architecture
24641
+ )
24317
24642
  ).map(
24318
24643
  (discovery) => new InstallableAgentDefinition(
24319
24644
  discovery.specification.id,
@@ -24340,17 +24665,21 @@ var DiscoveryAcpHandler = class {
24340
24665
  onPermission = (_request, _signal) => Promise.reject(new Error("ACP probe does not grant permissions"));
24341
24666
  onUpdate = (_notification) => Promise.resolve();
24342
24667
  };
24343
- async function resolveManagedExecutable(managedExecutablePath, options) {
24344
- return await resolveExecutablePath(
24345
- join6(readStateDirectory(options.environment), ...managedExecutablePath),
24346
- options.platform
24347
- );
24668
+ async function resolveManagedExecutable(specification, options) {
24669
+ try {
24670
+ return await specification.resolveManagedAgent(
24671
+ readStateDirectory(options.environment),
24672
+ options.platform ?? process.platform
24673
+ );
24674
+ } catch {
24675
+ return null;
24676
+ }
24348
24677
  }
24349
24678
  async function resolveManagedAdapterExecutable(specification, options) {
24350
24679
  let managed;
24351
24680
  try {
24352
24681
  managed = await validateManagedAdapter(
24353
- join6(
24682
+ join7(
24354
24683
  readStateDirectory(options.environment),
24355
24684
  "adapters",
24356
24685
  specification.id,
@@ -24366,7 +24695,7 @@ async function resolveManagedAdapterExecutable(specification, options) {
24366
24695
  async function resolveSpecificationExecutables(executableName, overrideVariable, resolveManaged, options) {
24367
24696
  const override = options.environment[overrideVariable];
24368
24697
  if (override !== void 0) {
24369
- if (override.length === 0 || !isAbsolute(override)) {
24698
+ if (override.length === 0 || !isAbsolute2(override)) {
24370
24699
  return [];
24371
24700
  }
24372
24701
  const executable = await resolveExecutablePath(override, options.platform);
@@ -24390,10 +24719,7 @@ async function resolveAgentExecutables(specification, options) {
24390
24719
  return await resolveSpecificationExecutables(
24391
24720
  specification.agentExecutable,
24392
24721
  specification.agentOverrideVariable,
24393
- async () => await resolveManagedExecutable(
24394
- specification.managedAgentExecutablePath,
24395
- options
24396
- ),
24722
+ async () => await resolveManagedExecutable(specification, options),
24397
24723
  options
24398
24724
  );
24399
24725
  }
@@ -24416,9 +24742,9 @@ async function resolveAdapterExecutable(specification, options) {
24416
24742
  function normalizedVersion(output2) {
24417
24743
  return output2.trim().split(/\r?\n/, 1)[0]?.trim().slice(0, 128) ?? "";
24418
24744
  }
24419
- async function probeVersion(executable, environment, defaultWorkspace, signal) {
24745
+ async function probeVersion(executable, arguments_, environment, defaultWorkspace, signal) {
24420
24746
  const result = await runBoundedProcess({
24421
- arguments: ["--version"],
24747
+ arguments: arguments_,
24422
24748
  command: executable.path,
24423
24749
  cwd: defaultWorkspace,
24424
24750
  environment,
@@ -24448,6 +24774,7 @@ async function findVerifiedAgentExecutable(specification, options) {
24448
24774
  try {
24449
24775
  const version2 = await probeVersion(
24450
24776
  executable,
24777
+ specification.agentVersionArguments,
24451
24778
  options.environment,
24452
24779
  options.defaultWorkspace,
24453
24780
  options.signal
@@ -24516,14 +24843,14 @@ function writableAcpStream(output2) {
24516
24843
  }
24517
24844
  });
24518
24845
  }
24519
- async function probeAcp(agent, environment, defaultWorkspace, signal) {
24846
+ async function probeAcp(specification, agent, environment, defaultWorkspace, signal) {
24520
24847
  signal.throwIfAborted();
24521
24848
  const controller = new AbortController();
24522
24849
  let timedOut = false;
24523
24850
  const timeout = setTimeout(() => {
24524
24851
  timedOut = true;
24525
24852
  controller.abort(new Error("ACP probe timed out"));
24526
- }, ACP_PROBE_TIMEOUT_MILLISECONDS);
24853
+ }, specification.acpProbeTimeoutMilliseconds);
24527
24854
  const abort = () => controller.abort(signal.reason);
24528
24855
  signal.addEventListener("abort", abort, { once: true });
24529
24856
  if (signal.aborted) {
@@ -24582,6 +24909,13 @@ async function probeAcp(agent, environment, defaultWorkspace, signal) {
24582
24909
  "ACP adapter selected an unsupported protocol version"
24583
24910
  );
24584
24911
  }
24912
+ await specification.verifyAcp(
24913
+ connection,
24914
+ initialized,
24915
+ defaultWorkspace,
24916
+ controller.signal
24917
+ );
24918
+ return normalizedVersion(initialized.agentInfo?.version ?? "");
24585
24919
  } catch (error61) {
24586
24920
  if (signal.aborted) {
24587
24921
  signal.throwIfAborted();
@@ -24596,6 +24930,13 @@ async function probeAcp(agent, environment, defaultWorkspace, signal) {
24596
24930
  if (error61 instanceof AgentProbeError) {
24597
24931
  throw error61;
24598
24932
  }
24933
+ if (error61 instanceof RequestError && error61.code === -32e3 && specification.authenticationCommand().length > 0) {
24934
+ throw new AgentProbeError(
24935
+ "authentication_required",
24936
+ "Agent authentication is required",
24937
+ { cause: error61 }
24938
+ );
24939
+ }
24599
24940
  throw new AgentProbeError(
24600
24941
  "acp_incompatible",
24601
24942
  "ACP adapter initialization failed",
@@ -24612,6 +24953,9 @@ async function probeAcp(agent, environment, defaultWorkspace, signal) {
24612
24953
  }
24613
24954
  function probeFailure(specification, executableKind, error61) {
24614
24955
  if (error61 instanceof AgentProbeError) {
24956
+ if (error61.code === "authentication_required") {
24957
+ return new AuthenticationRequiredAgent(specification);
24958
+ }
24615
24959
  return error61.code === "acp_incompatible" ? new IncompatibleAdapter(specification) : new ProbeFailed(specification, error61.code, error61.message);
24616
24960
  }
24617
24961
  if (error61 instanceof ProcessExecutionError) {
@@ -24646,6 +24990,7 @@ async function discoverSpecification(specification, options) {
24646
24990
  try {
24647
24991
  agentVersion = await probeVersion(
24648
24992
  agent,
24993
+ specification.agentVersionArguments,
24649
24994
  options.environment,
24650
24995
  options.defaultWorkspace,
24651
24996
  options.signal
@@ -24660,15 +25005,18 @@ async function discoverSpecification(specification, options) {
24660
25005
  for (const adapter of adapters) {
24661
25006
  let adapterVersion = "";
24662
25007
  try {
24663
- adapterVersion = await probeVersion(
24664
- adapter,
24665
- {
24666
- ...options.environment,
24667
- [specification.adapterEnvironmentVariable]: agent.path
24668
- },
24669
- options.defaultWorkspace,
24670
- options.signal
24671
- );
25008
+ if (specification.adapterVersionArguments.length > 0) {
25009
+ adapterVersion = await probeVersion(
25010
+ adapter,
25011
+ specification.adapterVersionArguments,
25012
+ {
25013
+ ...options.environment,
25014
+ [specification.adapterEnvironmentVariable]: agent.path
25015
+ },
25016
+ options.defaultWorkspace,
25017
+ options.signal
25018
+ );
25019
+ }
24672
25020
  } catch (error61) {
24673
25021
  if (options.signal.aborted) {
24674
25022
  options.signal.throwIfAborted();
@@ -24685,16 +25033,39 @@ async function discoverSpecification(specification, options) {
24685
25033
  adapterVersion,
24686
25034
  agentVersion,
24687
25035
  adapter.identity,
24688
- agent.identity
25036
+ agent.identity,
25037
+ specification.promptTimeoutMilliseconds
24689
25038
  );
24690
25039
  try {
24691
- await probeAcp(
25040
+ const acpVersion = await probeAcp(
25041
+ specification,
24692
25042
  definition,
24693
25043
  options.environment,
24694
25044
  options.defaultWorkspace,
24695
25045
  options.signal
24696
25046
  );
24697
- return new AvailableAgent(specification, definition);
25047
+ const verifiedAdapterVersion = adapterVersion.length > 0 ? adapterVersion : acpVersion;
25048
+ if (verifiedAdapterVersion.length === 0) {
25049
+ throw new AgentProbeError(
25050
+ "acp_incompatible",
25051
+ "ACP adapter did not report a version"
25052
+ );
25053
+ }
25054
+ return new AvailableAgent(
25055
+ specification,
25056
+ new LocalAgentDefinition(
25057
+ specification.id,
25058
+ specification.label,
25059
+ adapter.path,
25060
+ [],
25061
+ { [specification.adapterEnvironmentVariable]: agent.path },
25062
+ verifiedAdapterVersion,
25063
+ agentVersion,
25064
+ adapter.identity,
25065
+ agent.identity,
25066
+ specification.promptTimeoutMilliseconds
25067
+ )
25068
+ );
24698
25069
  } catch (error61) {
24699
25070
  if (options.signal.aborted) {
24700
25071
  options.signal.throwIfAborted();
@@ -24984,10 +25355,10 @@ async function claimPairing(options, defaultWorkspace, localAgents, installableA
24984
25355
  return decodeClaimResponse(value);
24985
25356
  }
24986
25357
  async function persistConnection(channelId, relayOrigin, daemonToken, defaultWorkspace) {
24987
- const connectionsDirectory = join7(readStateDirectory(), "connections");
25358
+ const connectionsDirectory = join8(readStateDirectory(), "connections");
24988
25359
  await mkdir2(connectionsDirectory, { mode: 448, recursive: true });
24989
- const connectionPath = join7(connectionsDirectory, `${channelId}.json`);
24990
- const temporaryPath = join7(
25360
+ const connectionPath = join8(connectionsDirectory, `${channelId}.json`);
25361
+ const temporaryPath = join8(
24991
25362
  connectionsDirectory,
24992
25363
  `.${channelId}.${randomUUID()}.tmp`
24993
25364
  );
@@ -25034,7 +25405,7 @@ function decodeSavedConnection(value, expectedChannelId) {
25034
25405
  };
25035
25406
  }
25036
25407
  async function readSavedConnection(channelId) {
25037
- const connectionPath = join7(
25408
+ const connectionPath = join8(
25038
25409
  readStateDirectory(),
25039
25410
  "connections",
25040
25411
  `${channelId}.json`
@@ -25089,7 +25460,7 @@ function buildPairedDaemon(connection, connectionPath, inventory) {
25089
25460
  );
25090
25461
  relayUrl.protocol = relayUrl.protocol === "https:" ? "wss:" : "ws:";
25091
25462
  relayUrl.searchParams.set("token", connection.daemonToken);
25092
- const auditDatabasePath = join7(
25463
+ const auditDatabasePath = join8(
25093
25464
  readStateDirectory(),
25094
25465
  "audit",
25095
25466
  `${connection.channelId}.sqlite`
@@ -25148,7 +25519,7 @@ async function pairLocalMachine(arguments_, signal = new AbortController().signa
25148
25519
  }
25149
25520
  async function resumeLocalMachine(arguments_, signal = new AbortController().signal) {
25150
25521
  const channelId = parseChannelArgument(arguments_);
25151
- const connectionPath = join7(
25522
+ const connectionPath = join8(
25152
25523
  readStateDirectory(),
25153
25524
  "connections",
25154
25525
  `${channelId}.json`
@@ -25771,7 +26142,7 @@ import { resolve as resolve4 } from "node:path";
25771
26142
 
25772
26143
  // src/agent-installation/fixed-agent-install-recipes.ts
25773
26144
  import { mkdir as mkdir3, mkdtemp as mkdtemp2, rm as rm2 } from "node:fs/promises";
25774
- import { join as join8 } from "node:path";
26145
+ import { join as join9 } from "node:path";
25775
26146
 
25776
26147
  // src/agent-installation/verified-download.ts
25777
26148
  import { createHash } from "node:crypto";
@@ -25995,18 +26366,18 @@ var CodexInstallRecipe = class extends FixedAgentInstallRecipe {
25995
26366
  releaseChannel = "latest";
25996
26367
  install = async (options) => {
25997
26368
  this.assertSupportedPlatform();
25998
- const root = join8(options.stateDirectory, "agents", this.id);
25999
- const temporaryRoot = join8(options.stateDirectory, "temporary");
26369
+ const root = join9(options.stateDirectory, "agents", this.id);
26370
+ const temporaryRoot = join9(options.stateDirectory, "temporary");
26000
26371
  await Promise.all([
26001
26372
  mkdir3(root, { mode: 448, recursive: true }),
26002
26373
  mkdir3(temporaryRoot, { mode: 448, recursive: true })
26003
26374
  ]);
26004
26375
  const temporaryDirectory = await mkdtemp2(
26005
- join8(temporaryRoot, ".codex-install-")
26376
+ join9(temporaryRoot, ".codex-install-")
26006
26377
  );
26007
- const installerPath = join8(temporaryDirectory, "install.sh");
26008
- const installDirectory = join8(root, "bin");
26009
- const codexHome = join8(root, "home");
26378
+ const installerPath = join9(temporaryDirectory, "install.sh");
26379
+ const installDirectory = join9(root, "bin");
26380
+ const codexHome = join9(root, "home");
26010
26381
  try {
26011
26382
  await Promise.all([
26012
26383
  mkdir3(installDirectory, { mode: 448, recursive: true }),
@@ -26050,7 +26421,7 @@ var CodexInstallRecipe = class extends FixedAgentInstallRecipe {
26050
26421
  timeoutMilliseconds: AGENT_INSTALL_TIMEOUT_MILLISECONDS
26051
26422
  });
26052
26423
  return await this.requireInstalledExecutable(
26053
- join8(installDirectory, "codex")
26424
+ join9(installDirectory, "codex")
26054
26425
  );
26055
26426
  } catch (error61) {
26056
26427
  if (options.signal.aborted) {
@@ -26074,17 +26445,17 @@ var ClaudeCodeInstallRecipe = class extends FixedAgentInstallRecipe {
26074
26445
  releaseChannel = "stable";
26075
26446
  install = async (options) => {
26076
26447
  this.assertSupportedPlatform();
26077
- const root = join8(options.stateDirectory, "agents", this.id);
26078
- const managedHome = join8(root, "home");
26079
- const temporaryRoot = join8(options.stateDirectory, "temporary");
26448
+ const root = join9(options.stateDirectory, "agents", this.id);
26449
+ const managedHome = join9(root, "home");
26450
+ const temporaryRoot = join9(options.stateDirectory, "temporary");
26080
26451
  await Promise.all([
26081
26452
  mkdir3(managedHome, { mode: 448, recursive: true }),
26082
26453
  mkdir3(temporaryRoot, { mode: 448, recursive: true })
26083
26454
  ]);
26084
26455
  const temporaryDirectory = await mkdtemp2(
26085
- join8(temporaryRoot, ".claude-install-")
26456
+ join9(temporaryRoot, ".claude-install-")
26086
26457
  );
26087
- const installerPath = join8(temporaryDirectory, "install.sh");
26458
+ const installerPath = join9(temporaryDirectory, "install.sh");
26088
26459
  try {
26089
26460
  await options.report("downloading");
26090
26461
  const download = await downloadVerifiedFile({
@@ -26121,7 +26492,7 @@ var ClaudeCodeInstallRecipe = class extends FixedAgentInstallRecipe {
26121
26492
  timeoutMilliseconds: AGENT_INSTALL_TIMEOUT_MILLISECONDS
26122
26493
  });
26123
26494
  return await this.requireInstalledExecutable(
26124
- join8(managedHome, ".local", "bin", "claude")
26495
+ join9(managedHome, ".local", "bin", "claude")
26125
26496
  );
26126
26497
  } catch (error61) {
26127
26498
  if (options.signal.aborted) {
@@ -26139,10 +26510,82 @@ var ClaudeCodeInstallRecipe = class extends FixedAgentInstallRecipe {
26139
26510
  }
26140
26511
  };
26141
26512
  };
26513
+ var PiInstallRecipe = class extends FixedAgentInstallRecipe {
26514
+ #npmInstaller;
26515
+ id = "pi";
26516
+ label = "Pi";
26517
+ releaseChannel = PI_AGENT_PACKAGE.version;
26518
+ constructor(npmInstaller = new ManagedNpmPackageInstaller()) {
26519
+ super();
26520
+ this.#npmInstaller = npmInstaller;
26521
+ }
26522
+ install = async (options) => {
26523
+ this.assertSupportedPlatform();
26524
+ try {
26525
+ await options.report("downloading");
26526
+ await options.report("verifying");
26527
+ await options.report("installing_agent");
26528
+ const executable = await this.#npmInstaller.install(
26529
+ join9(
26530
+ options.stateDirectory,
26531
+ "agents",
26532
+ this.id,
26533
+ PI_AGENT_PACKAGE.version
26534
+ ),
26535
+ PI_AGENT_PACKAGE,
26536
+ options.environment,
26537
+ options.signal
26538
+ );
26539
+ options.audit.record(
26540
+ "agent_npm_package_verified",
26541
+ options.requestId,
26542
+ this.id,
26543
+ {
26544
+ integrity: PI_AGENT_PACKAGE.integrity,
26545
+ package: PI_AGENT_PACKAGE.packageName,
26546
+ version: PI_AGENT_PACKAGE.version
26547
+ }
26548
+ );
26549
+ return executable;
26550
+ } catch (error61) {
26551
+ if (options.signal.aborted) {
26552
+ options.signal.throwIfAborted();
26553
+ }
26554
+ if (error61 instanceof ManagedNpmPackageError) {
26555
+ if (error61.code === "managed_package_verification_failed") {
26556
+ throw new InstallationManagerError(
26557
+ "agent_verification_failed",
26558
+ "The managed Pi package did not match its pinned artifact",
26559
+ { cause: error61 }
26560
+ );
26561
+ }
26562
+ if (error61.code === "managed_package_publish_failed") {
26563
+ throw new InstallationManagerError(
26564
+ "agent_publish_failed",
26565
+ "The managed Pi package could not be published",
26566
+ { cause: error61 }
26567
+ );
26568
+ }
26569
+ throw new InstallationManagerError(error61.code, error61.message, {
26570
+ cause: error61
26571
+ });
26572
+ }
26573
+ if (error61 instanceof InstallationManagerError) {
26574
+ throw error61;
26575
+ }
26576
+ throw new InstallationManagerError(
26577
+ "agent_install_failed",
26578
+ "The fixed Pi installation recipe failed",
26579
+ { cause: error61 }
26580
+ );
26581
+ }
26582
+ };
26583
+ };
26142
26584
  function fixedAgentInstallRecipes() {
26143
26585
  return Object.freeze([
26144
26586
  new CodexInstallRecipe(),
26145
- new ClaudeCodeInstallRecipe()
26587
+ new ClaudeCodeInstallRecipe(),
26588
+ new PiInstallRecipe()
26146
26589
  ]);
26147
26590
  }
26148
26591
 
@@ -26272,6 +26715,7 @@ var FixedInstallationExecutor = class {
26272
26715
  if (agent === null) {
26273
26716
  agent = await recipe.install({
26274
26717
  audit: this.#audit,
26718
+ environment: this.#environment,
26275
26719
  report,
26276
26720
  requestId,
26277
26721
  signal,
@@ -26353,6 +26797,7 @@ var FixedInstallationExecutor = class {
26353
26797
  if (!installedAgent && (requiresAgentReplacement(unavailable.code) || unavailable.code === "acp_incompatible")) {
26354
26798
  agent = await recipe.install({
26355
26799
  audit: this.#audit,
26800
+ environment: this.#environment,
26356
26801
  report,
26357
26802
  requestId,
26358
26803
  signal,
@@ -26416,8 +26861,8 @@ import { homedir as homedir2 } from "node:os";
26416
26861
  import {
26417
26862
  basename as basename2,
26418
26863
  dirname as dirname4,
26419
- isAbsolute as isAbsolute2,
26420
- join as join9,
26864
+ isAbsolute as isAbsolute3,
26865
+ join as join10,
26421
26866
  normalize,
26422
26867
  relative as relative2
26423
26868
  } from "node:path";
@@ -26469,20 +26914,20 @@ var WorkspaceDirectoryService = class {
26469
26914
  if (id === "home") return homedir2();
26470
26915
  if (id.startsWith("path-")) {
26471
26916
  const path2 = decodePath(id, "path-");
26472
- if (isAbsolute2(path2)) return path2;
26917
+ if (isAbsolute3(path2)) return path2;
26473
26918
  }
26474
26919
  throw new LocalAuthorizationError("The directory identifier is invalid");
26475
26920
  };
26476
26921
  resolvePath = async (requested, signal) => {
26477
26922
  signal.throwIfAborted();
26478
- if (!isAbsolute2(requested) || requested.includes("\0") || normalize(requested) !== requested)
26923
+ if (!isAbsolute3(requested) || requested.includes("\0") || normalize(requested) !== requested)
26479
26924
  throw new LocalAuthorizationError("The local directory path is invalid");
26480
26925
  try {
26481
26926
  const target = await realpath4(requested);
26482
26927
  signal.throwIfAborted();
26483
26928
  const metadata = await stat4(target);
26484
26929
  signal.throwIfAborted();
26485
- if (!isAbsolute2(target) || normalize(target) !== target || !metadata.isDirectory())
26930
+ if (!isAbsolute3(target) || normalize(target) !== target || !metadata.isDirectory())
26486
26931
  throw new LocalAuthorizationError(
26487
26932
  "The selected location is not a directory"
26488
26933
  );
@@ -26498,7 +26943,7 @@ var WorkspaceDirectoryService = class {
26498
26943
  };
26499
26944
  label = (path2) => {
26500
26945
  const suffix = relative2(homedir2(), path2);
26501
- return suffix === "" ? "~" : !isAbsolute2(suffix) && suffix !== ".." && !suffix.startsWith(`..${process.platform === "win32" ? "\\" : "/"}`) ? `~/${suffix.replaceAll("\\", "/")}` : path2;
26946
+ return suffix === "" ? "~" : !isAbsolute3(suffix) && suffix !== ".." && !suffix.startsWith(`..${process.platform === "win32" ? "\\" : "/"}`) ? `~/${suffix.replaceAll("\\", "/")}` : path2;
26502
26947
  };
26503
26948
  identify = async (bindingId, requestedPath, signal) => {
26504
26949
  this.authorizeMachine(bindingId);
@@ -26526,7 +26971,7 @@ var WorkspaceDirectoryService = class {
26526
26971
  continue;
26527
26972
  }
26528
26973
  try {
26529
- const path2 = await this.resolvePath(join9(target, child.name), signal);
26974
+ const path2 = await this.resolvePath(join10(target, child.name), signal);
26530
26975
  entries.push({ directoryId: encodePath(path2), name: child.name });
26531
26976
  } catch (cause) {
26532
26977
  signal.throwIfAborted();