@moxt-ai/mobius 0.0.9 → 0.0.11

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 (121) hide show
  1. package/dist/acp/session-history.d.ts.map +1 -1
  2. package/dist/acp/session-history.js +1 -0
  3. package/dist/acp/session-history.js.map +1 -1
  4. package/dist/acp/session-manager.d.ts +4 -1
  5. package/dist/acp/session-manager.d.ts.map +1 -1
  6. package/dist/acp/session-manager.js +109 -25
  7. package/dist/acp/session-manager.js.map +1 -1
  8. package/dist/agent-catalog/acp-readiness-probe.d.ts +4 -0
  9. package/dist/agent-catalog/acp-readiness-probe.d.ts.map +1 -0
  10. package/dist/agent-catalog/acp-readiness-probe.js +153 -0
  11. package/dist/agent-catalog/acp-readiness-probe.js.map +1 -0
  12. package/dist/agent-catalog/agent-diagnostics.d.ts +1 -1
  13. package/dist/agent-catalog/agent-diagnostics.d.ts.map +1 -1
  14. package/dist/agent-catalog/agent-diagnostics.js +7 -3
  15. package/dist/agent-catalog/agent-diagnostics.js.map +1 -1
  16. package/dist/agent-catalog/agent-discovery-context.d.ts +8 -0
  17. package/dist/agent-catalog/agent-discovery-context.d.ts.map +1 -0
  18. package/dist/agent-catalog/agent-discovery-context.js +2 -0
  19. package/dist/agent-catalog/agent-discovery-context.js.map +1 -0
  20. package/dist/agent-catalog/agent-discovery.d.ts +55 -0
  21. package/dist/agent-catalog/agent-discovery.d.ts.map +1 -0
  22. package/dist/agent-catalog/agent-discovery.js +89 -0
  23. package/dist/agent-catalog/agent-discovery.js.map +1 -0
  24. package/dist/agent-catalog/agent-probe-error.d.ts +5 -0
  25. package/dist/agent-catalog/agent-probe-error.d.ts.map +1 -0
  26. package/dist/agent-catalog/agent-probe-error.js +9 -0
  27. package/dist/agent-catalog/agent-probe-error.js.map +1 -0
  28. package/dist/agent-catalog/agent-specification.d.ts +45 -0
  29. package/dist/agent-catalog/agent-specification.d.ts.map +1 -0
  30. package/dist/agent-catalog/agent-specification.js +59 -0
  31. package/dist/agent-catalog/agent-specification.js.map +1 -0
  32. package/dist/agent-catalog/agents/claude-code-agent.d.ts +14 -0
  33. package/dist/agent-catalog/agents/claude-code-agent.d.ts.map +1 -0
  34. package/dist/agent-catalog/agents/claude-code-agent.js +30 -0
  35. package/dist/agent-catalog/agents/claude-code-agent.js.map +1 -0
  36. package/dist/agent-catalog/agents/codex-agent.d.ts +14 -0
  37. package/dist/agent-catalog/agents/codex-agent.d.ts.map +1 -0
  38. package/dist/agent-catalog/agents/codex-agent.js +23 -0
  39. package/dist/agent-catalog/agents/codex-agent.js.map +1 -0
  40. package/dist/agent-catalog/agents/deepseek-harness-agent.d.ts +16 -0
  41. package/dist/agent-catalog/agents/deepseek-harness-agent.d.ts.map +1 -0
  42. package/dist/agent-catalog/agents/deepseek-harness-agent.js +94 -0
  43. package/dist/agent-catalog/agents/deepseek-harness-agent.js.map +1 -0
  44. package/dist/agent-catalog/agents/opencode-agent.d.ts +17 -0
  45. package/dist/agent-catalog/agents/opencode-agent.d.ts.map +1 -0
  46. package/dist/agent-catalog/agents/opencode-agent.js +36 -0
  47. package/dist/agent-catalog/agents/opencode-agent.js.map +1 -0
  48. package/dist/agent-catalog/agents/pi-agent.d.ts +21 -0
  49. package/dist/agent-catalog/agents/pi-agent.d.ts.map +1 -0
  50. package/dist/agent-catalog/agents/pi-agent.js +69 -0
  51. package/dist/agent-catalog/agents/pi-agent.js.map +1 -0
  52. package/dist/agent-catalog/agents/supported-agent-specifications.d.ts +3 -0
  53. package/dist/agent-catalog/agents/supported-agent-specifications.d.ts.map +1 -0
  54. package/dist/agent-catalog/agents/supported-agent-specifications.js +15 -0
  55. package/dist/agent-catalog/agents/supported-agent-specifications.js.map +1 -0
  56. package/dist/agent-catalog/discover-agent.d.ts +5 -0
  57. package/dist/agent-catalog/discover-agent.d.ts.map +1 -0
  58. package/dist/agent-catalog/discover-agent.js +100 -0
  59. package/dist/agent-catalog/discover-agent.js.map +1 -0
  60. package/dist/agent-catalog/discover-local-agents.d.ts +12 -73
  61. package/dist/agent-catalog/discover-local-agents.d.ts.map +1 -1
  62. package/dist/agent-catalog/discover-local-agents.js +11 -453
  63. package/dist/agent-catalog/discover-local-agents.js.map +1 -1
  64. package/dist/agent-catalog/executable-discovery.d.ts +16 -0
  65. package/dist/agent-catalog/executable-discovery.d.ts.map +1 -0
  66. package/dist/agent-catalog/executable-discovery.js +105 -0
  67. package/dist/agent-catalog/executable-discovery.js.map +1 -0
  68. package/dist/agent-catalog/local-agent.d.ts +2 -1
  69. package/dist/agent-catalog/local-agent.d.ts.map +1 -1
  70. package/dist/agent-catalog/local-agent.js +7 -1
  71. package/dist/agent-catalog/local-agent.js.map +1 -1
  72. package/dist/agent-installation/agent-installation-manager.d.ts +1 -1
  73. package/dist/agent-installation/agent-installation-manager.d.ts.map +1 -1
  74. package/dist/agent-installation/automatic-adapter-provisioner.d.ts +2 -1
  75. package/dist/agent-installation/automatic-adapter-provisioner.d.ts.map +1 -1
  76. package/dist/agent-installation/automatic-adapter-provisioner.js +11 -2
  77. package/dist/agent-installation/automatic-adapter-provisioner.js.map +1 -1
  78. package/dist/agent-installation/deepseek-managed-package.d.ts +9 -0
  79. package/dist/agent-installation/deepseek-managed-package.d.ts.map +1 -0
  80. package/dist/agent-installation/deepseek-managed-package.js +10 -0
  81. package/dist/agent-installation/deepseek-managed-package.js.map +1 -0
  82. package/dist/agent-installation/fixed-agent-install-recipes.d.ts +19 -0
  83. package/dist/agent-installation/fixed-agent-install-recipes.d.ts.map +1 -1
  84. package/dist/agent-installation/fixed-agent-install-recipes.js +145 -0
  85. package/dist/agent-installation/fixed-agent-install-recipes.js.map +1 -1
  86. package/dist/agent-installation/fixed-installation-executor.d.ts +1 -1
  87. package/dist/agent-installation/fixed-installation-executor.d.ts.map +1 -1
  88. package/dist/agent-installation/fixed-installation-executor.js +19 -3
  89. package/dist/agent-installation/fixed-installation-executor.js.map +1 -1
  90. package/dist/agent-installation/managed-adapter-installer.d.ts +7 -6
  91. package/dist/agent-installation/managed-adapter-installer.d.ts.map +1 -1
  92. package/dist/agent-installation/managed-adapter-installer.js +25 -126
  93. package/dist/agent-installation/managed-adapter-installer.js.map +1 -1
  94. package/dist/agent-installation/managed-agent-archive.d.ts +40 -0
  95. package/dist/agent-installation/managed-agent-archive.d.ts.map +1 -0
  96. package/dist/agent-installation/managed-agent-archive.js +274 -0
  97. package/dist/agent-installation/managed-agent-archive.js.map +1 -0
  98. package/dist/agent-installation/managed-npm-package.d.ts +27 -0
  99. package/dist/agent-installation/managed-npm-package.d.ts.map +1 -0
  100. package/dist/agent-installation/managed-npm-package.js +258 -0
  101. package/dist/agent-installation/managed-npm-package.js.map +1 -0
  102. package/dist/agent-installation/opencode-managed-release.d.ts +4 -0
  103. package/dist/agent-installation/opencode-managed-release.d.ts.map +1 -0
  104. package/dist/agent-installation/opencode-managed-release.js +25 -0
  105. package/dist/agent-installation/opencode-managed-release.js.map +1 -0
  106. package/dist/agent-installation/pi-managed-packages.d.ts +4 -0
  107. package/dist/agent-installation/pi-managed-packages.d.ts.map +1 -0
  108. package/dist/agent-installation/pi-managed-packages.js +4 -0
  109. package/dist/agent-installation/pi-managed-packages.js.map +1 -0
  110. package/dist/cli.js +2419 -950
  111. package/dist/cli.js.map +4 -4
  112. package/dist/index.js +2138 -669
  113. package/dist/index.js.map +4 -4
  114. package/dist/native-sessions/codex-history.d.ts.map +1 -1
  115. package/dist/native-sessions/codex-history.js +1 -0
  116. package/dist/native-sessions/codex-history.js.map +1 -1
  117. package/dist/process/executable.d.ts +6 -1
  118. package/dist/process/executable.d.ts.map +1 -1
  119. package/dist/process/executable.js +150 -7
  120. package/dist/process/executable.js.map +1 -1
  121. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -29,13 +29,18 @@ import { fileURLToPath } from "node:url";
29
29
  import { realpathSync, statSync } from "node:fs";
30
30
 
31
31
  // src/process/executable.ts
32
- import { spawn } from "node:child_process";
32
+ import { execFile, spawn } from "node:child_process";
33
33
  import { constants } from "node:fs";
34
34
  import { access, realpath, stat } from "node:fs/promises";
35
35
  import { join, resolve } from "node:path";
36
36
  var DEFAULT_OUTPUT_LIMIT_BYTES = 16 * 1024;
37
37
  var PROCESS_GRACEFUL_STOP_TIMEOUT_MILLISECONDS = 1e3;
38
38
  var PROCESS_FORCED_STOP_TIMEOUT_MILLISECONDS = 5e3;
39
+ var PROCESS_TABLE_TIMEOUT_MILLISECONDS = 1e3;
40
+ var PROCESS_TABLE_OUTPUT_LIMIT_BYTES = 1024 * 1024;
41
+ var PROCESS_EXIT_CHECK_ATTEMPTS = 8;
42
+ var GRACEFUL_STOP_SIGNAL = 15;
43
+ var FORCED_STOP_SIGNAL = 9;
39
44
  var ExecutableIdentity = class {
40
45
  changedAtMilliseconds;
41
46
  device;
@@ -154,6 +159,119 @@ function appendBounded(chunks, chunk, currentBytes, limitBytes) {
154
159
  chunks.push(chunk);
155
160
  return nextBytes;
156
161
  }
162
+ function parseProcessTable(output2) {
163
+ const entries = [];
164
+ for (const line of output2.split("\n")) {
165
+ const groups = /^\s*(?<pid>\d+)\s+(?<ppid>\d+)\s+(?<pgid>\d+)\s*$/.exec(
166
+ line
167
+ )?.groups;
168
+ if (groups === void 0) {
169
+ continue;
170
+ }
171
+ const processId = Number(groups["pid"]);
172
+ const parentProcessId = Number(groups["ppid"]);
173
+ const processGroupId = Number(groups["pgid"]);
174
+ if (!Number.isSafeInteger(processId) || processId <= 0 || !Number.isSafeInteger(parentProcessId) || parentProcessId < 0 || !Number.isSafeInteger(processGroupId) || processGroupId <= 0) {
175
+ continue;
176
+ }
177
+ entries.push({ parentProcessId, processGroupId, processId });
178
+ }
179
+ return entries;
180
+ }
181
+ function readProcessTable() {
182
+ if (process.platform === "win32") {
183
+ return Promise.resolve([]);
184
+ }
185
+ const executable = process.platform === "darwin" ? "/bin/ps" : "/usr/bin/ps";
186
+ return new Promise((resolveTable) => {
187
+ execFile(
188
+ executable,
189
+ ["-axo", "pid=,ppid=,pgid="],
190
+ {
191
+ encoding: "utf8",
192
+ maxBuffer: PROCESS_TABLE_OUTPUT_LIMIT_BYTES,
193
+ signal: AbortSignal.timeout(PROCESS_TABLE_TIMEOUT_MILLISECONDS),
194
+ timeout: PROCESS_TABLE_TIMEOUT_MILLISECONDS
195
+ },
196
+ (error61, stdout) => {
197
+ resolveTable(error61 === null ? parseProcessTable(stdout) : []);
198
+ }
199
+ );
200
+ });
201
+ }
202
+ function selectProcessTree(entries, rootProcessId) {
203
+ const processIds = /* @__PURE__ */ new Set([rootProcessId]);
204
+ let previousSize = 0;
205
+ while (previousSize !== processIds.size) {
206
+ previousSize = processIds.size;
207
+ for (const entry of entries) {
208
+ if (processIds.has(entry.parentProcessId)) {
209
+ processIds.add(entry.processId);
210
+ }
211
+ }
212
+ }
213
+ return entries.filter((entry) => processIds.has(entry.processId)).map((entry) => ({
214
+ processGroupId: entry.processGroupId,
215
+ processId: entry.processId
216
+ }));
217
+ }
218
+ function mergeProcessTrees(captured, current) {
219
+ const processes = /* @__PURE__ */ new Map();
220
+ for (const identity2 of captured) {
221
+ processes.set(identity2.processId, identity2);
222
+ }
223
+ for (const identity2 of current) {
224
+ processes.set(identity2.processId, identity2);
225
+ }
226
+ return [...processes.values()];
227
+ }
228
+ async function captureProcessTree(child) {
229
+ if (process.platform === "win32" || child.pid === void 0) {
230
+ return [];
231
+ }
232
+ return selectProcessTree(await readProcessTable(), child.pid);
233
+ }
234
+ function signalDetachedProcessGroups(processes, rootProcessId, signal) {
235
+ const processIds = new Set(processes.map((identity2) => identity2.processId));
236
+ const signalledGroups = /* @__PURE__ */ new Set();
237
+ for (const identity2 of processes) {
238
+ if (identity2.processGroupId === rootProcessId || !processIds.has(identity2.processGroupId) || signalledGroups.has(identity2.processGroupId)) {
239
+ continue;
240
+ }
241
+ try {
242
+ process.kill(-identity2.processGroupId, signal);
243
+ signalledGroups.add(identity2.processGroupId);
244
+ } catch {
245
+ }
246
+ }
247
+ for (const identity2 of processes) {
248
+ if (identity2.processId === rootProcessId || identity2.processGroupId === rootProcessId || signalledGroups.has(identity2.processGroupId)) {
249
+ continue;
250
+ }
251
+ try {
252
+ process.kill(identity2.processId, signal);
253
+ } catch {
254
+ }
255
+ }
256
+ }
257
+ function processExists(processId) {
258
+ try {
259
+ process.kill(processId, 0);
260
+ return true;
261
+ } catch {
262
+ return false;
263
+ }
264
+ }
265
+ async function waitForCapturedProcessesExit(processes, rootProcessId) {
266
+ const processIds = processes.map((identity2) => identity2.processId).filter((processId) => processId !== rootProcessId);
267
+ for (let attempt = 0; attempt < PROCESS_EXIT_CHECK_ATTEMPTS; attempt += 1) {
268
+ if (processIds.every((processId) => !processExists(processId))) {
269
+ return true;
270
+ }
271
+ await readProcessTable();
272
+ }
273
+ return processIds.every((processId) => !processExists(processId));
274
+ }
157
275
  function terminateProcess(child) {
158
276
  if (child.exitCode !== null || child.signalCode !== null || child.pid === void 0) {
159
277
  return;
@@ -180,24 +298,35 @@ function forceTerminateProcess(child) {
180
298
  }
181
299
  child.kill("SIGKILL");
182
300
  }
183
- async function stopProcessTree(child) {
184
- if (child.exitCode !== null || child.signalCode !== null) {
301
+ async function stopProcessTree(child, capturedProcesses = []) {
302
+ const childProcessId = child.pid;
303
+ if (childProcessId === void 0) {
185
304
  return;
186
305
  }
187
- terminateProcess(child);
188
- const exitedAfterTermination = await waitForProcessExit(
189
- child,
190
- PROCESS_GRACEFUL_STOP_TIMEOUT_MILLISECONDS
306
+ const childExited = child.exitCode !== null || child.signalCode !== null;
307
+ if (childExited && capturedProcesses.length === 0) {
308
+ return;
309
+ }
310
+ const processes = mergeProcessTrees(
311
+ capturedProcesses,
312
+ childExited ? [] : await captureProcessTree(child)
191
313
  );
192
- if (exitedAfterTermination) {
314
+ signalDetachedProcessGroups(processes, childProcessId, GRACEFUL_STOP_SIGNAL);
315
+ terminateProcess(child);
316
+ const [exitedAfterTermination, descendantsExitedAfterTermination] = await Promise.all([
317
+ waitForProcessExit(child, PROCESS_GRACEFUL_STOP_TIMEOUT_MILLISECONDS),
318
+ waitForCapturedProcessesExit(processes, childProcessId)
319
+ ]);
320
+ if (exitedAfterTermination && descendantsExitedAfterTermination) {
193
321
  return;
194
322
  }
323
+ signalDetachedProcessGroups(processes, childProcessId, FORCED_STOP_SIGNAL);
195
324
  forceTerminateProcess(child);
196
- const exitedAfterForce = await waitForProcessExit(
197
- child,
198
- PROCESS_FORCED_STOP_TIMEOUT_MILLISECONDS
199
- );
200
- if (!exitedAfterForce) {
325
+ const [exitedAfterForce, descendantsExitedAfterForce] = await Promise.all([
326
+ waitForProcessExit(child, PROCESS_FORCED_STOP_TIMEOUT_MILLISECONDS),
327
+ waitForCapturedProcessesExit(processes, childProcessId)
328
+ ]);
329
+ if (!exitedAfterForce || !descendantsExitedAfterForce) {
201
330
  throw new ProcessExecutionError(
202
331
  "process_termination_timeout",
203
332
  "The executable process could not be stopped"
@@ -388,7 +517,11 @@ var LocalAgentDefinition = class {
388
517
  environment;
389
518
  id;
390
519
  label;
391
- constructor(id, label, command, arguments_, environment = {}, adapterVersion = "", agentVersion = "", adapterIdentity = readTrustedIdentity(command), agentIdentity = adapterIdentity) {
520
+ promptTimeoutMilliseconds;
521
+ constructor(id, label, command, arguments_, environment = {}, adapterVersion = "", agentVersion = "", adapterIdentity = readTrustedIdentity(command), agentIdentity = adapterIdentity, promptTimeoutMilliseconds = 30 * 60 * 1e3) {
522
+ if (!Number.isSafeInteger(promptTimeoutMilliseconds) || promptTimeoutMilliseconds < 1) {
523
+ throw new Error("The local Agent prompt deadline is invalid");
524
+ }
392
525
  this.adapterIdentity = adapterIdentity;
393
526
  this.adapterPath = adapterIdentity.realPath;
394
527
  this.adapterVersion = adapterVersion;
@@ -396,6 +529,7 @@ var LocalAgentDefinition = class {
396
529
  this.agentVersion = agentVersion;
397
530
  this.id = id;
398
531
  this.label = label;
532
+ this.promptTimeoutMilliseconds = promptTimeoutMilliseconds;
399
533
  this.command = adapterIdentity.realPath;
400
534
  this.arguments = Object.freeze([...arguments_]);
401
535
  this.environment = Object.freeze({ ...environment });
@@ -527,7 +661,8 @@ import { spawn as spawn2 } from "node:child_process";
527
661
  import {
528
662
  methods as methods2,
529
663
  ndJsonStream,
530
- PROTOCOL_VERSION
664
+ PROTOCOL_VERSION,
665
+ RequestError
531
666
  } from "@agentclientprotocol/sdk";
532
667
 
533
668
  // ../../node_modules/.pnpm/zod@4.5.4/node_modules/zod/v4/classic/external.js
@@ -20302,7 +20437,10 @@ var sessionHistorySchema = external_exports.discriminatedUnion("status", [
20302
20437
  status: external_exports.literal("available"),
20303
20438
  messages: external_exports.array(historyMessage).max(SESSION_HISTORY_MESSAGE_LIMIT).readonly(),
20304
20439
  truncated: external_exports.boolean(),
20305
- coveredCommandIds: external_exports.array(external_exports.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/)).max(1e4).readonly()
20440
+ coveredCommandIds: external_exports.array(external_exports.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/)).max(1e4).readonly(),
20441
+ coveredMessageIds: external_exports.array(
20442
+ external_exports.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}:(?:user|agent)$/)
20443
+ ).max(2e4).readonly().default([])
20306
20444
  }).readonly(),
20307
20445
  external_exports.strictObject({ status: external_exports.literal("unavailable") }).readonly()
20308
20446
  ]).refine(
@@ -21541,7 +21679,8 @@ var AcpHistoryReplay = class {
21541
21679
  status: "available",
21542
21680
  messages: [...this.#messages],
21543
21681
  truncated: this.#truncated,
21544
- coveredCommandIds: []
21682
+ coveredCommandIds: [],
21683
+ coveredMessageIds: []
21545
21684
  });
21546
21685
  };
21547
21686
 
@@ -21757,6 +21896,8 @@ var SqliteAcpSessionStore = class {
21757
21896
 
21758
21897
  // src/acp/session-manager.ts
21759
21898
  var PROCESS_STOP_TIMEOUT_MILLISECONDS = 1e3;
21899
+ var MAX_PRE_SESSION_UPDATES = 100;
21900
+ var MAX_PRE_SESSION_UPDATE_BYTES = 1024 * 1024;
21760
21901
  var SESSION_CONTROL_COMMAND_ID = "session-control";
21761
21902
  var NullAcpSessionObserver = class {
21762
21903
  onCommands = () => Promise.resolve();
@@ -22365,8 +22506,11 @@ var AcpProcessSession = class _AcpProcessSession {
22365
22506
  #mobiusSessionId;
22366
22507
  #pendingElicitations = /* @__PURE__ */ new Map();
22367
22508
  #pendingPermissions = /* @__PURE__ */ new Map();
22509
+ #preSessionUpdates = [];
22368
22510
  #processExit;
22369
22511
  #store;
22512
+ #verifiedAgentVersion;
22513
+ #preSessionUpdateBytes = 0;
22370
22514
  #agentName = "";
22371
22515
  #agentVersion = "";
22372
22516
  #capabilities = {
@@ -22400,6 +22544,7 @@ var AcpProcessSession = class _AcpProcessSession {
22400
22544
  this.#getObserver = getObserver;
22401
22545
  this.#mobiusSessionId = mobiusSessionId;
22402
22546
  this.#store = store;
22547
+ this.#verifiedAgentVersion = agent.agentVersion;
22403
22548
  this.#child = spawn2(agent.adapterPath, [...agent.arguments], {
22404
22549
  cwd,
22405
22550
  detached: process.platform !== "win32",
@@ -22555,7 +22700,10 @@ var AcpProcessSession = class _AcpProcessSession {
22555
22700
  initialized.agentInfo?.title ?? initialized.agentInfo?.name ?? this.#agentId,
22556
22701
  255
22557
22702
  );
22558
- this.#agentVersion = truncate2(initialized.agentInfo?.version ?? "", 128);
22703
+ this.#agentVersion = truncate2(
22704
+ this.#verifiedAgentVersion.length > 0 ? this.#verifiedAgentVersion : initialized.agentInfo?.version ?? "",
22705
+ 128
22706
+ );
22559
22707
  }
22560
22708
  initialize = async (signal, origin) => {
22561
22709
  await this.#initializeAgent(signal);
@@ -22601,7 +22749,7 @@ var AcpProcessSession = class _AcpProcessSession {
22601
22749
  "ACP agent exited while forking a session",
22602
22750
  signal
22603
22751
  );
22604
- this.#nativeSessionId = nativeSessionIdSchema.parse(forked.sessionId);
22752
+ this.selectNativeSession(forked.sessionId);
22605
22753
  if (this.#nativeSessionId === origin.nativeSessionId || this.#store.findNative(this.#agentId, this.#nativeSessionId).length > 0) {
22606
22754
  throw new AcpExecutionError(
22607
22755
  "The Agent did not create an independent fork",
@@ -22616,7 +22764,7 @@ var AcpProcessSession = class _AcpProcessSession {
22616
22764
  stored.session.additionalDirectories,
22617
22765
  this.#additionalDirectories
22618
22766
  )) {
22619
- this.#nativeSessionId = stored.session.nativeSessionId;
22767
+ this.selectNativeSession(stored.session.nativeSessionId);
22620
22768
  this.#prompted = stored.session.prompted;
22621
22769
  this.#restored = true;
22622
22770
  if (this.#capabilities.resumeSession) {
@@ -22686,7 +22834,7 @@ var AcpProcessSession = class _AcpProcessSession {
22686
22834
  "ACP agent exited while starting a session",
22687
22835
  signal
22688
22836
  );
22689
- this.#nativeSessionId = created.sessionId;
22837
+ this.selectNativeSession(created.sessionId);
22690
22838
  lifecycleResponse = created;
22691
22839
  }
22692
22840
  const lifecycleRecord = isRecord3(lifecycleResponse) ? lifecycleResponse : {};
@@ -22948,13 +23096,17 @@ var AcpProcessSession = class _AcpProcessSession {
22948
23096
  }
22949
23097
  };
22950
23098
  cancel = async () => {
22951
- await this.cancelPendingInteractions();
22952
- if (!this.#turn.running) {
22953
- return;
23099
+ const capturedProcesses = await captureProcessTree(this.#child);
23100
+ try {
23101
+ await this.cancelPendingInteractions();
23102
+ if (this.#turn.running) {
23103
+ await this.#connection.agent.notify(methods2.agent.session.cancel, {
23104
+ sessionId: this.#nativeSessionId
23105
+ });
23106
+ }
23107
+ } finally {
23108
+ await this.closeProcess(capturedProcesses);
22954
23109
  }
22955
- await this.#connection.agent.notify(methods2.agent.session.cancel, {
22956
- sessionId: this.#nativeSessionId
22957
- });
22958
23110
  };
22959
23111
  respondPermission = async (options) => {
22960
23112
  const pending = this.#pendingPermissions.get(options.interactionId);
@@ -23141,11 +23293,45 @@ var AcpProcessSession = class _AcpProcessSession {
23141
23293
  });
23142
23294
  };
23143
23295
  onUpdate = (notification) => {
23296
+ if (this.#nativeSessionId.length === 0) {
23297
+ const notificationBytes = Buffer.byteLength(JSON.stringify(notification));
23298
+ if (this.#preSessionUpdates.length >= MAX_PRE_SESSION_UPDATES || this.#preSessionUpdateBytes + notificationBytes > MAX_PRE_SESSION_UPDATE_BYTES) {
23299
+ return Promise.reject(
23300
+ new AcpExecutionError(
23301
+ "ACP agent sent too many updates before creating its session",
23302
+ {},
23303
+ "agent_update_limit"
23304
+ )
23305
+ );
23306
+ }
23307
+ this.#preSessionUpdates.push(notification);
23308
+ this.#preSessionUpdateBytes += notificationBytes;
23309
+ return Promise.resolve();
23310
+ }
23311
+ return this.enqueueUpdate(notification);
23312
+ };
23313
+ enqueueUpdate = (notification) => {
23144
23314
  this.#updateTail = this.#updateTail.then(
23145
23315
  async () => await this.processUpdate(notification)
23146
23316
  );
23147
23317
  return this.#updateTail;
23148
23318
  };
23319
+ selectNativeSession = (sessionId) => {
23320
+ const selected = nativeSessionIdSchema.parse(sessionId);
23321
+ if (this.#nativeSessionId.length > 0 && this.#nativeSessionId !== selected) {
23322
+ throw new AcpExecutionError(
23323
+ "ACP agent attempted to replace the selected session",
23324
+ {},
23325
+ "invalid_agent_session"
23326
+ );
23327
+ }
23328
+ this.#nativeSessionId = selected;
23329
+ const pending = this.#preSessionUpdates.splice(0);
23330
+ this.#preSessionUpdateBytes = 0;
23331
+ for (const notification of pending) {
23332
+ void this.enqueueUpdate(notification);
23333
+ }
23334
+ };
23149
23335
  processUpdate = async (notification) => {
23150
23336
  this.assertNativeSession(notification.sessionId);
23151
23337
  const update = notification.update;
@@ -23283,9 +23469,12 @@ var AcpProcessSession = class _AcpProcessSession {
23283
23469
  }
23284
23470
  await this.closeProcess();
23285
23471
  };
23286
- closeProcess = async () => {
23287
- this.#connection.close();
23288
- await stopProcessTree(this.#child);
23472
+ closeProcess = async (capturedProcesses = []) => {
23473
+ try {
23474
+ await stopProcessTree(this.#child, capturedProcesses);
23475
+ } finally {
23476
+ this.#connection.close();
23477
+ }
23289
23478
  };
23290
23479
  race = async (operation, exitMessage, signal) => {
23291
23480
  signal.throwIfAborted();
@@ -23301,13 +23490,25 @@ var AcpProcessSession = class _AcpProcessSession {
23301
23490
  };
23302
23491
  });
23303
23492
  try {
23304
- return await Promise.race([
23305
- operation,
23306
- this.#processExit.then(() => {
23307
- throw new AcpExecutionError(exitMessage);
23308
- }),
23309
- aborted2
23310
- ]);
23493
+ try {
23494
+ return await Promise.race([
23495
+ operation,
23496
+ this.#processExit.then(() => {
23497
+ throw new AcpExecutionError(exitMessage);
23498
+ }),
23499
+ aborted2
23500
+ ]);
23501
+ } catch (error61) {
23502
+ signal.throwIfAborted();
23503
+ if (error61 instanceof RequestError && error61.code === -32e3) {
23504
+ throw new AcpExecutionError(
23505
+ "Agent authentication is required",
23506
+ { cause: error61 },
23507
+ "authentication_required"
23508
+ );
23509
+ }
23510
+ throw error61;
23511
+ }
23311
23512
  } finally {
23312
23513
  removeAbortListener();
23313
23514
  }
@@ -23566,7 +23767,13 @@ var AcpSessionManager = class {
23566
23767
  this.#cancellationRequests.add(sessionId);
23567
23768
  const runtime = this.#sessions.get(sessionId);
23568
23769
  if (runtime !== void 0) {
23569
- await runtime.cancel();
23770
+ try {
23771
+ await runtime.cancel();
23772
+ } finally {
23773
+ if (this.#sessions.get(sessionId) === runtime) {
23774
+ this.#sessions.delete(sessionId);
23775
+ }
23776
+ }
23570
23777
  }
23571
23778
  };
23572
23779
  runPrompt = async (options) => {
@@ -23587,12 +23794,27 @@ var AcpSessionManager = class {
23587
23794
  "session_busy"
23588
23795
  );
23589
23796
  }
23797
+ const deadlineController = new AbortController();
23798
+ const deadlineError = new AcpExecutionError(
23799
+ "The local Agent prompt exceeded its deadline",
23800
+ {},
23801
+ "prompt_timeout"
23802
+ );
23803
+ const deadline = setTimeout(
23804
+ () => deadlineController.abort(deadlineError),
23805
+ options.agent.promptTimeoutMilliseconds
23806
+ );
23807
+ deadline.unref();
23808
+ const boundedOptions = {
23809
+ ...options,
23810
+ signal: AbortSignal.any([options.signal, deadlineController.signal])
23811
+ };
23590
23812
  this.#activeSessionIds.add(options.sessionId);
23591
23813
  try {
23592
23814
  if (this.#cancellationRequests.has(options.sessionId)) {
23593
23815
  return { stopReason: "cancelled" };
23594
23816
  }
23595
- const runtime = await this.ensureSession(options);
23817
+ const runtime = await this.ensureSession(boundedOptions);
23596
23818
  if (this.#nativeOperations.has(
23597
23819
  `${options.agent.id}:${runtime.nativeSessionId()}`
23598
23820
  ))
@@ -23604,7 +23826,19 @@ var AcpSessionManager = class {
23604
23826
  if (this.#cancellationRequests.has(options.sessionId)) {
23605
23827
  return { stopReason: "cancelled" };
23606
23828
  }
23607
- return await runtime.prompt(options);
23829
+ try {
23830
+ const result = await runtime.prompt(boundedOptions);
23831
+ return this.#cancellationRequests.has(options.sessionId) ? { stopReason: "cancelled" } : result;
23832
+ } catch (error61) {
23833
+ if (this.#cancellationRequests.has(options.sessionId)) {
23834
+ if (this.#sessions.get(options.sessionId) === runtime) {
23835
+ this.#sessions.delete(options.sessionId);
23836
+ }
23837
+ await runtime.closeProcess();
23838
+ return { stopReason: "cancelled" };
23839
+ }
23840
+ throw error61;
23841
+ }
23608
23842
  } catch (error61) {
23609
23843
  const failedRuntime = this.#sessions.get(options.sessionId);
23610
23844
  if (failedRuntime !== void 0) {
@@ -23618,6 +23852,7 @@ var AcpSessionManager = class {
23618
23852
  cause: error61
23619
23853
  });
23620
23854
  } finally {
23855
+ clearTimeout(deadline);
23621
23856
  this.#activeSessionIds.delete(options.sessionId);
23622
23857
  this.#cancellationRequests.delete(options.sessionId);
23623
23858
  }
@@ -23911,25 +24146,16 @@ var LocalAuthorizationError = class extends Error {
23911
24146
  // src/pairing/pair-local-machine.ts
23912
24147
  import { randomUUID } from "node:crypto";
23913
24148
  import {
23914
- mkdir as mkdir2,
23915
- open as open4,
23916
- realpath as realpath3,
23917
- rename as rename2,
23918
- stat as stat3,
23919
- writeFile
24149
+ mkdir as mkdir3,
24150
+ open as open6,
24151
+ realpath as realpath5,
24152
+ rename as rename3,
24153
+ stat as stat5,
24154
+ writeFile as writeFile2
23920
24155
  } from "node:fs/promises";
23921
24156
  import { hostname as hostname3 } from "node:os";
23922
- import { basename, join as join7, resolve as resolve3 } from "node:path";
23923
- import { fetch } from "undici";
23924
-
23925
- // src/agent-catalog/discover-local-agents.ts
23926
- import { spawn as spawn3 } from "node:child_process";
23927
- import { isAbsolute, join as join6 } from "node:path";
23928
- import {
23929
- methods as methods3,
23930
- ndJsonStream as ndJsonStream2,
23931
- PROTOCOL_VERSION as PROTOCOL_VERSION2
23932
- } from "@agentclientprotocol/sdk";
24157
+ import { basename, join as join13, resolve as resolve3 } from "node:path";
24158
+ import { fetch as fetch2 } from "undici";
23933
24159
 
23934
24160
  // src/agent-installation/installation-grants.ts
23935
24161
  import { open as open2 } from "node:fs/promises";
@@ -23973,7 +24199,104 @@ async function readGrantedAgents(stateDirectory) {
23973
24199
  }
23974
24200
  }
23975
24201
 
23976
- // src/agent-installation/managed-adapter-installer.ts
24202
+ // src/agent-catalog/agent-discovery.ts
24203
+ var AgentDiscovery = class {
24204
+ specification;
24205
+ constructor(specification) {
24206
+ this.specification = specification;
24207
+ }
24208
+ };
24209
+ var AvailableAgent = class extends AgentDiscovery {
24210
+ agent;
24211
+ status = "ready";
24212
+ constructor(specification, agent) {
24213
+ super(specification);
24214
+ this.agent = agent;
24215
+ }
24216
+ };
24217
+ var UnavailableAgent = class extends AgentDiscovery {
24218
+ };
24219
+ var MissingAdapter = class extends UnavailableAgent {
24220
+ code = "adapter_not_found";
24221
+ message = "ACP adapter not found";
24222
+ status = "missing_adapter";
24223
+ constructor(specification) {
24224
+ super(specification);
24225
+ }
24226
+ };
24227
+ var MissingAgent = class extends UnavailableAgent {
24228
+ code = "agent_not_found";
24229
+ message = "Agent executable not found";
24230
+ status = "missing_agent";
24231
+ constructor(specification) {
24232
+ super(specification);
24233
+ }
24234
+ };
24235
+ var ProbeFailed = class extends UnavailableAgent {
24236
+ code;
24237
+ message;
24238
+ status = "probe_failed";
24239
+ constructor(specification, code, message) {
24240
+ super(specification);
24241
+ this.code = code;
24242
+ this.message = message;
24243
+ }
24244
+ };
24245
+ var IncompatibleAdapter = class extends UnavailableAgent {
24246
+ code = "acp_incompatible";
24247
+ message = "ACP adapter is incompatible";
24248
+ status = "incompatible_adapter";
24249
+ constructor(specification) {
24250
+ super(specification);
24251
+ }
24252
+ };
24253
+ var AuthenticationRequiredAgent = class extends UnavailableAgent {
24254
+ code = "authentication_required";
24255
+ message = "Agent authentication is required";
24256
+ status = "authentication_required";
24257
+ constructor(specification) {
24258
+ super(specification);
24259
+ }
24260
+ };
24261
+ var LocalAgentInventory = class {
24262
+ available;
24263
+ discoveries;
24264
+ installable;
24265
+ unavailable;
24266
+ constructor(discoveries, grantedAgents = /* @__PURE__ */ new Set(), platform = process.platform, architecture = process.arch) {
24267
+ const available = [];
24268
+ const unavailable = [];
24269
+ for (const discovery of discoveries) {
24270
+ if (discovery instanceof AvailableAgent) {
24271
+ available.push(discovery);
24272
+ } else if (discovery instanceof UnavailableAgent) {
24273
+ unavailable.push(discovery);
24274
+ } else {
24275
+ throw new Error("Unsupported Agent discovery outcome");
24276
+ }
24277
+ }
24278
+ this.available = Object.freeze(available);
24279
+ this.discoveries = Object.freeze([...discoveries]);
24280
+ this.installable = Object.freeze(
24281
+ unavailable.filter(
24282
+ (discovery) => !(discovery instanceof AuthenticationRequiredAgent) && discovery.specification.supportsInstallation(
24283
+ platform,
24284
+ architecture
24285
+ )
24286
+ ).map(
24287
+ (discovery) => new InstallableAgentDefinition(
24288
+ discovery.specification.id,
24289
+ discovery.specification.label,
24290
+ !grantedAgents.has(discovery.specification.id)
24291
+ )
24292
+ )
24293
+ );
24294
+ this.unavailable = Object.freeze(unavailable);
24295
+ }
24296
+ readyAgents = () => this.available.map((discovery) => discovery.agent);
24297
+ };
24298
+
24299
+ // src/agent-installation/managed-npm-package.ts
23977
24300
  import {
23978
24301
  mkdir,
23979
24302
  mkdtemp,
@@ -23983,15 +24306,38 @@ import {
23983
24306
  rm,
23984
24307
  stat as stat2
23985
24308
  } from "node:fs/promises";
23986
- import { delimiter, dirname as dirname3, join as join5, relative } from "node:path";
23987
- var ADAPTER_INSTALL_TIMEOUT_MILLISECONDS = 2 * 60 * 1e3;
24309
+ import { delimiter, dirname as dirname3, isAbsolute, join as join5, relative, sep } from "node:path";
24310
+ var INSTALL_TIMEOUT_MILLISECONDS = 5 * 60 * 1e3;
23988
24311
  var PACKAGE_METADATA_LIMIT_BYTES = 64 * 1024;
23989
- var ManagedAdapterInstallError = class extends Error {
24312
+ var PACKAGE_LOCK_LIMIT_BYTES = 8 * 1024 * 1024;
24313
+ var ManagedNpmPackageDefinition = class {
24314
+ dependencyResolutionArguments = Object.freeze([]);
24315
+ executableName;
24316
+ includeOptionalDependencies = false;
24317
+ packageName;
24318
+ version;
24319
+ verifyDependencyClosure = false;
24320
+ constructor(packageName, version2, executableName) {
24321
+ this.executableName = executableName;
24322
+ this.packageName = packageName;
24323
+ this.version = version2;
24324
+ }
24325
+ };
24326
+ var SriManagedNpmPackageDefinition = class extends ManagedNpmPackageDefinition {
24327
+ integrity;
24328
+ tarballUrl;
24329
+ constructor(packageName, version2, executableName, integrity, tarballUrl) {
24330
+ super(packageName, version2, executableName);
24331
+ this.integrity = integrity;
24332
+ this.tarballUrl = tarballUrl;
24333
+ }
24334
+ };
24335
+ var ManagedNpmPackageError = class extends Error {
23990
24336
  code;
23991
24337
  constructor(code, message, options = {}) {
23992
24338
  super(message, options);
23993
24339
  this.code = code;
23994
- this.name = "ManagedAdapterInstallError";
24340
+ this.name = "ManagedNpmPackageError";
23995
24341
  }
23996
24342
  };
23997
24343
  function isRecord5(value) {
@@ -24000,28 +24346,43 @@ function isRecord5(value) {
24000
24346
  function packagePath(root, packageName) {
24001
24347
  return join5(root, "node_modules", ...packageName.split("/"));
24002
24348
  }
24003
- async function readPackageJson(path2) {
24004
- const handle = await open3(path2, "r");
24349
+ function isContainedPath(root, candidate) {
24350
+ const difference = relative(root, candidate);
24351
+ return difference.length > 0 && difference !== ".." && !difference.startsWith(`..${sep}`) && !isAbsolute(difference);
24352
+ }
24353
+ async function readJsonRecord(path2, maximumBytes) {
24005
24354
  try {
24006
- const metadata = await handle.stat();
24007
- if (!metadata.isFile() || metadata.size > PACKAGE_METADATA_LIMIT_BYTES) {
24008
- throw new ManagedAdapterInstallError(
24009
- "adapter_verification_failed",
24010
- "The managed adapter package metadata is invalid"
24355
+ const handle = await open3(path2, "r");
24356
+ try {
24357
+ const metadata = await handle.stat();
24358
+ if (!metadata.isFile() || metadata.size > maximumBytes) {
24359
+ throw new ManagedNpmPackageError(
24360
+ "managed_package_verification_failed",
24361
+ "The managed npm package metadata is invalid"
24362
+ );
24363
+ }
24364
+ const value = JSON.parse(
24365
+ await handle.readFile({ encoding: "utf8" })
24011
24366
  );
24367
+ if (!isRecord5(value)) {
24368
+ throw new ManagedNpmPackageError(
24369
+ "managed_package_verification_failed",
24370
+ "The managed npm package metadata is invalid"
24371
+ );
24372
+ }
24373
+ return value;
24374
+ } finally {
24375
+ await handle.close();
24012
24376
  }
24013
- const value = JSON.parse(
24014
- await handle.readFile({ encoding: "utf8" })
24015
- );
24016
- if (!isRecord5(value)) {
24017
- throw new ManagedAdapterInstallError(
24018
- "adapter_verification_failed",
24019
- "The managed adapter package metadata is invalid"
24020
- );
24377
+ } catch (error61) {
24378
+ if (error61 instanceof ManagedNpmPackageError) {
24379
+ throw error61;
24021
24380
  }
24022
- return value;
24023
- } finally {
24024
- await handle.close();
24381
+ throw new ManagedNpmPackageError(
24382
+ "managed_package_verification_failed",
24383
+ "The managed npm package metadata is invalid",
24384
+ { cause: error61 }
24385
+ );
24025
24386
  }
24026
24387
  }
24027
24388
  function readBinPath(packageMetadata, executableName) {
@@ -24032,139 +24393,217 @@ function readBinPath(packageMetadata, executableName) {
24032
24393
  if (isRecord5(bin) && typeof bin[executableName] === "string") {
24033
24394
  return bin[executableName];
24034
24395
  }
24035
- throw new ManagedAdapterInstallError(
24036
- "adapter_verification_failed",
24037
- "The managed adapter executable declaration is invalid"
24396
+ throw new ManagedNpmPackageError(
24397
+ "managed_package_verification_failed",
24398
+ "The managed npm package executable declaration is invalid"
24038
24399
  );
24039
24400
  }
24040
- async function validateManagedAdapter(root, specification) {
24041
- const rootPath = await realpath2(root);
24042
- const packageRoot = await realpath2(
24043
- packagePath(rootPath, specification.adapterPackage)
24044
- );
24045
- const packageDifference = relative(rootPath, packageRoot);
24046
- if (packageDifference.startsWith("..") || packageDifference.length === 0) {
24047
- throw new ManagedAdapterInstallError(
24048
- "adapter_verification_failed",
24049
- "The managed adapter package escaped its private cache"
24401
+ function verifyPackageLock(lock, definition) {
24402
+ if (lock["lockfileVersion"] !== 3) {
24403
+ throw new ManagedNpmPackageError(
24404
+ "managed_package_verification_failed",
24405
+ "The managed npm package lockfile is invalid"
24050
24406
  );
24051
24407
  }
24052
- const metadata = await readPackageJson(join5(packageRoot, "package.json"));
24053
- if (metadata["name"] !== specification.adapterPackage || metadata["version"] !== specification.adapterVersion) {
24054
- throw new ManagedAdapterInstallError(
24055
- "adapter_verification_failed",
24056
- "The managed adapter package identity is invalid"
24408
+ const packages = lock["packages"];
24409
+ if (!isRecord5(packages)) {
24410
+ throw new ManagedNpmPackageError(
24411
+ "managed_package_verification_failed",
24412
+ "The managed npm package lockfile is invalid"
24057
24413
  );
24058
24414
  }
24059
- const declaredBin = readBinPath(metadata, specification.adapterExecutable);
24060
- const executable = await resolveExecutablePath(
24061
- join5(packageRoot, declaredBin)
24062
- );
24063
- if (executable === null) {
24064
- throw new ManagedAdapterInstallError(
24065
- "adapter_verification_failed",
24066
- "The managed adapter executable is invalid"
24067
- );
24415
+ const suffix = `node_modules/${definition.packageName}`;
24416
+ let entry;
24417
+ let matches = 0;
24418
+ for (const [key, candidate] of Object.entries(packages)) {
24419
+ const normalizedKey = key.replaceAll("\\", "/");
24420
+ if (definition.verifyDependencyClosure && normalizedKey.length > 0) {
24421
+ let resolved;
24422
+ try {
24423
+ if (!normalizedKey.split("/").includes("node_modules") || !isRecord5(candidate) || typeof candidate["version"] !== "string" || candidate["version"].length === 0 || typeof candidate["integrity"] !== "string" || !/^sha512-[A-Za-z0-9+/]{86}==$/.test(candidate["integrity"]) || typeof candidate["resolved"] !== "string") {
24424
+ throw new Error("Invalid locked dependency");
24425
+ }
24426
+ resolved = new URL(candidate["resolved"]);
24427
+ } catch (error61) {
24428
+ throw new ManagedNpmPackageError(
24429
+ "managed_package_verification_failed",
24430
+ "The managed npm dependency closure is invalid",
24431
+ { cause: error61 }
24432
+ );
24433
+ }
24434
+ if (resolved.protocol !== "https:" || resolved.hostname !== "registry.npmjs.org" || resolved.port.length > 0 || resolved.username.length > 0 || resolved.password.length > 0) {
24435
+ throw new ManagedNpmPackageError(
24436
+ "managed_package_verification_failed",
24437
+ "The managed npm dependency closure is invalid"
24438
+ );
24439
+ }
24440
+ }
24441
+ if (normalizedKey === suffix || normalizedKey.endsWith(`/${suffix}`)) {
24442
+ entry = candidate;
24443
+ matches += 1;
24444
+ }
24068
24445
  }
24069
- const executableDifference = relative(rootPath, executable.path);
24070
- if (executableDifference.startsWith("..") || executableDifference.length === 0) {
24071
- throw new ManagedAdapterInstallError(
24072
- "adapter_verification_failed",
24073
- "The managed adapter executable escaped its private cache"
24446
+ if (matches !== 1 || !isRecord5(entry) || entry["integrity"] !== definition.integrity || entry["resolved"] !== definition.tarballUrl || entry["version"] !== definition.version) {
24447
+ throw new ManagedNpmPackageError(
24448
+ "managed_package_verification_failed",
24449
+ "The managed npm package lockfile does not match the pinned artifact"
24074
24450
  );
24075
24451
  }
24076
- return executable;
24077
24452
  }
24078
- var ManagedAdapterInstaller = class {
24079
- #environment;
24080
- #stateDirectory;
24081
- constructor(options) {
24082
- this.#environment = options.environment;
24083
- this.#stateDirectory = options.stateDirectory;
24453
+ async function validateManagedNpmPackage(root, definition) {
24454
+ try {
24455
+ return await validateManagedNpmPackageContents(root, definition);
24456
+ } catch (error61) {
24457
+ if (error61 instanceof ManagedNpmPackageError) {
24458
+ throw error61;
24459
+ }
24460
+ throw new ManagedNpmPackageError(
24461
+ "managed_package_verification_failed",
24462
+ "The managed npm package is invalid",
24463
+ { cause: error61 }
24464
+ );
24084
24465
  }
24085
- install = async (specification, signal) => {
24466
+ }
24467
+ async function validateManagedNpmPackageContents(root, definition) {
24468
+ const rootPath = await realpath2(root);
24469
+ const packageRoot = await realpath2(
24470
+ packagePath(rootPath, definition.packageName)
24471
+ );
24472
+ if (!isContainedPath(rootPath, packageRoot)) {
24473
+ throw new ManagedNpmPackageError(
24474
+ "managed_package_verification_failed",
24475
+ "The managed npm package escaped its private cache"
24476
+ );
24477
+ }
24478
+ const metadata = await readJsonRecord(
24479
+ join5(packageRoot, "package.json"),
24480
+ PACKAGE_METADATA_LIMIT_BYTES
24481
+ );
24482
+ if (metadata["name"] !== definition.packageName || metadata["version"] !== definition.version) {
24483
+ throw new ManagedNpmPackageError(
24484
+ "managed_package_verification_failed",
24485
+ "The managed npm package identity is invalid"
24486
+ );
24487
+ }
24488
+ if (definition instanceof SriManagedNpmPackageDefinition) {
24489
+ verifyPackageLock(
24490
+ await readJsonRecord(
24491
+ join5(rootPath, "package-lock.json"),
24492
+ PACKAGE_LOCK_LIMIT_BYTES
24493
+ ),
24494
+ definition
24495
+ );
24496
+ }
24497
+ const declaredBin = readBinPath(metadata, definition.executableName);
24498
+ const executable = await resolveExecutablePath(
24499
+ join5(packageRoot, declaredBin)
24500
+ );
24501
+ if (executable === null || !isContainedPath(rootPath, executable.path)) {
24502
+ throw new ManagedNpmPackageError(
24503
+ "managed_package_verification_failed",
24504
+ "The managed npm package executable is invalid"
24505
+ );
24506
+ }
24507
+ return executable;
24508
+ }
24509
+ var ManagedNpmPackageInstaller = class {
24510
+ install = async (root, definition, environment, signal) => {
24086
24511
  signal.throwIfAborted();
24087
- const agentCache = join5(this.#stateDirectory, "adapters", specification.id);
24088
- const published = join5(agentCache, specification.adapterVersion);
24089
24512
  try {
24090
- const metadata = await stat2(published);
24513
+ const metadata = await stat2(root);
24091
24514
  if (metadata.isDirectory()) {
24092
- return await validateManagedAdapter(published, specification);
24515
+ return await validateManagedNpmPackage(root, definition);
24093
24516
  }
24094
24517
  } catch (error61) {
24095
24518
  if (!(error61 instanceof Error) || !("code" in error61) || error61.code !== "ENOENT") {
24096
24519
  throw error61;
24097
24520
  }
24098
24521
  }
24099
- await mkdir(agentCache, { mode: 448, recursive: true });
24522
+ const parent = dirname3(root);
24523
+ await mkdir(parent, { mode: 448, recursive: true });
24100
24524
  const staging = await mkdtemp(
24101
- join5(agentCache, `.${specification.adapterVersion}.staging-`)
24525
+ join5(parent, `.${definition.version}.staging-`)
24102
24526
  );
24103
24527
  try {
24104
24528
  const npm = await findExecutableOnPath(
24105
24529
  process.platform === "win32" ? "npm.cmd" : "npm",
24106
- this.#environment
24530
+ environment
24107
24531
  );
24108
24532
  if (npm === null) {
24109
- throw new ManagedAdapterInstallError(
24533
+ throw new ManagedNpmPackageError(
24110
24534
  "package_manager_not_found",
24111
- "A supported npm executable is required to install the ACP adapter"
24535
+ "A supported npm executable is required to install the managed package"
24112
24536
  );
24113
24537
  }
24538
+ const installArguments = ["install", "--prefix", staging];
24539
+ installArguments.push(...definition.dependencyResolutionArguments);
24540
+ if (definition.includeOptionalDependencies) {
24541
+ installArguments.push("--include=optional");
24542
+ } else {
24543
+ installArguments.push("--omit=optional");
24544
+ }
24545
+ installArguments.push(
24546
+ "--ignore-scripts",
24547
+ "--no-audit",
24548
+ "--no-fund",
24549
+ "--package-lock=true",
24550
+ "--save-exact",
24551
+ "--registry=https://registry.npmjs.org/",
24552
+ `${definition.packageName}@${definition.version}`
24553
+ );
24554
+ const installEnvironment = {
24555
+ HOME: join5(staging, "home"),
24556
+ NPM_CONFIG_AUDIT: "false",
24557
+ NPM_CONFIG_CACHE: join5(staging, ".npm-cache"),
24558
+ NPM_CONFIG_FUND: "false",
24559
+ NPM_CONFIG_IGNORE_SCRIPTS: "true",
24560
+ NPM_CONFIG_PACKAGE_LOCK: "true",
24561
+ NPM_CONFIG_REGISTRY: "https://registry.npmjs.org/",
24562
+ PATH: `${dirname3(process.execPath)}${delimiter}/usr/bin${delimiter}/bin`
24563
+ };
24564
+ if (definition.includeOptionalDependencies) {
24565
+ installEnvironment["NPM_CONFIG_INCLUDE"] = "optional";
24566
+ } else {
24567
+ installEnvironment["NPM_CONFIG_OMIT"] = "optional";
24568
+ }
24114
24569
  await runBoundedProcess({
24115
- arguments: [
24116
- "install",
24117
- "--prefix",
24118
- staging,
24119
- "--omit=optional",
24120
- "--ignore-scripts",
24121
- "--no-audit",
24122
- "--no-fund",
24123
- "--package-lock=false",
24124
- "--save=false",
24125
- "--registry=https://registry.npmjs.org/",
24126
- `${specification.adapterPackage}@${specification.adapterVersion}`
24127
- ],
24570
+ arguments: installArguments,
24128
24571
  command: npm.path,
24129
24572
  cwd: staging,
24130
- environment: {
24131
- HOME: join5(staging, "home"),
24132
- NPM_CONFIG_AUDIT: "false",
24133
- NPM_CONFIG_FUND: "false",
24134
- NPM_CONFIG_IGNORE_SCRIPTS: "true",
24135
- NPM_CONFIG_OMIT: "optional",
24136
- NPM_CONFIG_REGISTRY: "https://registry.npmjs.org/",
24137
- PATH: `${dirname3(process.execPath)}${delimiter}/usr/bin${delimiter}/bin`
24138
- },
24573
+ environment: installEnvironment,
24139
24574
  outputLimitBytes: 64 * 1024,
24140
24575
  signal,
24141
- timeoutMilliseconds: ADAPTER_INSTALL_TIMEOUT_MILLISECONDS
24576
+ timeoutMilliseconds: INSTALL_TIMEOUT_MILLISECONDS
24142
24577
  });
24143
- await validateManagedAdapter(staging, specification);
24578
+ await Promise.all([
24579
+ rm(join5(staging, ".npm-cache"), { force: true, recursive: true }),
24580
+ rm(join5(staging, "home"), { force: true, recursive: true })
24581
+ ]);
24582
+ await validateManagedNpmPackage(staging, definition);
24144
24583
  try {
24145
- await rename(staging, published);
24584
+ await rename(staging, root);
24146
24585
  } catch (error61) {
24147
24586
  try {
24148
- return await validateManagedAdapter(published, specification);
24587
+ return await validateManagedNpmPackage(root, definition);
24149
24588
  } catch {
24150
- throw new ManagedAdapterInstallError(
24151
- "adapter_publish_failed",
24152
- "The managed adapter could not be published",
24589
+ throw new ManagedNpmPackageError(
24590
+ "managed_package_publish_failed",
24591
+ "The managed npm package could not be published",
24153
24592
  { cause: error61 }
24154
24593
  );
24155
24594
  }
24156
24595
  }
24157
- return await validateManagedAdapter(published, specification);
24596
+ return await validateManagedNpmPackage(root, definition);
24158
24597
  } catch (error61) {
24159
24598
  if (signal.aborted) {
24160
24599
  signal.throwIfAborted();
24161
24600
  }
24162
- if (error61 instanceof ManagedAdapterInstallError) {
24601
+ if (error61 instanceof ManagedNpmPackageError) {
24163
24602
  throw error61;
24164
24603
  }
24165
- throw new ManagedAdapterInstallError(
24166
- "adapter_install_failed",
24167
- "The pinned ACP adapter could not be installed",
24604
+ throw new ManagedNpmPackageError(
24605
+ "managed_package_install_failed",
24606
+ "The pinned npm package could not be installed",
24168
24607
  { cause: error61 }
24169
24608
  );
24170
24609
  } finally {
@@ -24173,42 +24612,76 @@ var ManagedAdapterInstaller = class {
24173
24612
  };
24174
24613
  };
24175
24614
 
24176
- // src/agent-catalog/discover-local-agents.ts
24615
+ // src/agent-catalog/agent-specification.ts
24616
+ import { join as join6 } from "node:path";
24177
24617
  var VERSION_PROBE_TIMEOUT_MILLISECONDS = 3e3;
24178
24618
  var ACP_PROBE_TIMEOUT_MILLISECONDS = 5e3;
24179
- var ACP_OUTPUT_LIMIT_BYTES = 1024 * 1024;
24619
+ var DEFAULT_PROMPT_TIMEOUT_MILLISECONDS = 30 * 60 * 1e3;
24180
24620
  var LocalAgentSpecification = class {
24181
- recoveryCommand = () => `npm install -g --omit=optional ${this.adapterPackage}@${this.adapterVersion}`;
24621
+ acpProbeTimeoutMilliseconds = ACP_PROBE_TIMEOUT_MILLISECONDS;
24622
+ authenticationCommand = () => "";
24623
+ adapterVersionArguments = ["--version"];
24624
+ agentVersionArguments = ["--version"];
24625
+ promptTimeoutMilliseconds = DEFAULT_PROMPT_TIMEOUT_MILLISECONDS;
24626
+ versionProbeTimeoutMilliseconds = VERSION_PROBE_TIMEOUT_MILLISECONDS;
24627
+ resolveManagedAgent = async (stateDirectory, platform, signal) => {
24628
+ signal.throwIfAborted();
24629
+ const executable = await resolveExecutablePath(
24630
+ join6(stateDirectory, ...this.managedAgentExecutablePath),
24631
+ platform
24632
+ );
24633
+ signal.throwIfAborted();
24634
+ if (executable === null) {
24635
+ throw new Error("The managed Agent executable is unavailable");
24636
+ }
24637
+ return executable;
24638
+ };
24639
+ createLaunchEnvironment = async (_agent, _context) => Object.freeze({});
24640
+ recoveryCommand = () => "";
24182
24641
  supportsInstallation = (platform, architecture) => (platform === "darwin" || platform === "linux") && (architecture === "arm64" || architecture === "x64");
24642
+ verifyAcp = (_connection, _initialized, _defaultWorkspace, _signal) => Promise.resolve();
24183
24643
  };
24184
- var CodexAgentSpecification = class extends LocalAgentSpecification {
24185
- adapterEnvironmentVariable = "CODEX_PATH";
24186
- adapterExecutable = "codex-acp";
24187
- adapterOverrideVariable = "MOBIUS_CODEX_ACP_PATH";
24188
- adapterPackage = "@agentclientprotocol/codex-acp";
24189
- adapterVersion = "1.8.0";
24190
- agentExecutable = "codex";
24191
- agentOverrideVariable = "MOBIUS_CODEX_PATH";
24192
- id = "codex";
24193
- label = "Codex";
24194
- managedAdapterExecutablePath = [
24195
- "adapters",
24196
- "codex",
24197
- "1.8.0",
24198
- "node_modules",
24199
- "@agentclientprotocol",
24200
- "codex-acp",
24201
- "dist",
24202
- "index.js"
24203
- ];
24204
- managedAgentExecutablePath = ["agents", "codex", "bin", "codex"];
24644
+ var DirectAcpAgentDefinition = class extends LocalAgentSpecification {
24645
+ adapterOverrideVariable;
24646
+ agentOverrideVariable;
24647
+ launchArguments;
24648
+ managedAdapterExecutablePath;
24649
+ managedAgentExecutablePath;
24650
+ constructor(executableOverrideVariable, launchArguments, managedExecutablePath) {
24651
+ super();
24652
+ this.adapterOverrideVariable = executableOverrideVariable;
24653
+ this.agentOverrideVariable = executableOverrideVariable;
24654
+ this.launchArguments = Object.freeze([...launchArguments]);
24655
+ this.managedAdapterExecutablePath = Object.freeze([
24656
+ ...managedExecutablePath
24657
+ ]);
24658
+ this.managedAgentExecutablePath = this.managedAdapterExecutablePath;
24659
+ }
24660
+ };
24661
+ var BridgedAcpAgentDefinition = class extends LocalAgentSpecification {
24662
+ launchArguments = Object.freeze([]);
24663
+ get adapterExecutable() {
24664
+ return this.adapterPackageDefinition.executableName;
24665
+ }
24666
+ get adapterPackage() {
24667
+ return this.adapterPackageDefinition.packageName;
24668
+ }
24669
+ get adapterVersion() {
24670
+ return this.adapterPackageDefinition.version;
24671
+ }
24672
+ createLaunchEnvironment = async (agent, _context) => Object.freeze({ [this.adapterEnvironmentVariable]: agent.path });
24673
+ recoveryCommand = () => `npm install -g --omit=optional ${this.adapterPackage}@${this.adapterVersion}`;
24205
24674
  };
24206
- var ClaudeCodeAgentSpecification = class extends LocalAgentSpecification {
24675
+
24676
+ // src/agent-catalog/agents/claude-code-agent.ts
24677
+ var ClaudeCodeAgentSpecification = class extends BridgedAcpAgentDefinition {
24207
24678
  adapterEnvironmentVariable = "CLAUDE_CODE_EXECUTABLE";
24208
- adapterExecutable = "claude-agent-acp";
24209
24679
  adapterOverrideVariable = "MOBIUS_CLAUDE_ACP_PATH";
24210
- adapterPackage = "@agentclientprotocol/claude-agent-acp";
24211
- adapterVersion = "0.73.0";
24680
+ adapterPackageDefinition = new ManagedNpmPackageDefinition(
24681
+ "@agentclientprotocol/claude-agent-acp",
24682
+ "0.73.0",
24683
+ "claude-agent-acp"
24684
+ );
24212
24685
  agentExecutable = "claude";
24213
24686
  agentOverrideVariable = "MOBIUS_CLAUDE_PATH";
24214
24687
  id = "claude";
@@ -24232,122 +24705,1001 @@ var ClaudeCodeAgentSpecification = class extends LocalAgentSpecification {
24232
24705
  "claude"
24233
24706
  ];
24234
24707
  };
24235
- function supportedLocalAgentSpecifications() {
24236
- return Object.freeze([
24237
- new CodexAgentSpecification(),
24238
- new ClaudeCodeAgentSpecification()
24708
+
24709
+ // src/agent-catalog/agents/codex-agent.ts
24710
+ var CodexAgentSpecification = class extends BridgedAcpAgentDefinition {
24711
+ adapterEnvironmentVariable = "CODEX_PATH";
24712
+ adapterOverrideVariable = "MOBIUS_CODEX_ACP_PATH";
24713
+ adapterPackageDefinition = new ManagedNpmPackageDefinition(
24714
+ "@agentclientprotocol/codex-acp",
24715
+ "1.8.0",
24716
+ "codex-acp"
24717
+ );
24718
+ agentExecutable = "codex";
24719
+ agentOverrideVariable = "MOBIUS_CODEX_PATH";
24720
+ id = "codex";
24721
+ label = "Codex";
24722
+ managedAdapterExecutablePath = [
24723
+ "adapters",
24724
+ "codex",
24725
+ "1.8.0",
24726
+ "node_modules",
24727
+ "@agentclientprotocol",
24728
+ "codex-acp",
24729
+ "dist",
24730
+ "index.js"
24731
+ ];
24732
+ managedAgentExecutablePath = ["agents", "codex", "bin", "codex"];
24733
+ };
24734
+
24735
+ // src/agent-catalog/agents/deepseek-harness-agent.ts
24736
+ import { realpath as realpath3, stat as stat3 } from "node:fs/promises";
24737
+ import { isAbsolute as isAbsolute2, join as join7, normalize } from "node:path";
24738
+
24739
+ // src/agent-installation/deepseek-managed-package.ts
24740
+ var DeepSeekHarnessManagedPackage = class extends SriManagedNpmPackageDefinition {
24741
+ dependencyResolutionArguments = Object.freeze([
24742
+ "--before=2026-09-03T06:31:52.107Z"
24239
24743
  ]);
24240
- }
24241
- var AgentDiscovery = class {
24242
- specification;
24243
- constructor(specification) {
24244
- this.specification = specification;
24245
- }
24744
+ includeOptionalDependencies = true;
24745
+ verifyDependencyClosure = true;
24246
24746
  };
24247
- var AvailableAgent = class extends AgentDiscovery {
24248
- agent;
24249
- status = "ready";
24250
- constructor(specification, agent) {
24251
- super(specification);
24252
- this.agent = agent;
24747
+ var DEEPSEEK_HARNESS_PACKAGE = new DeepSeekHarnessManagedPackage(
24748
+ "@deepseek-ai/dsh",
24749
+ "0.1.2-rc.1",
24750
+ "dsh",
24751
+ "sha512-RPq48TzxvwpdT9/7W1tbhZDBMmeK+bxDrX9cqQC27Wx/LqtgJF8PSa3b3xriU8oxtvhwYmk21w2cej3uMQrnVA==",
24752
+ "https://registry.npmjs.org/@deepseek-ai/dsh/-/dsh-0.1.2-rc.1.tgz"
24753
+ );
24754
+
24755
+ // src/agent-catalog/agent-probe-error.ts
24756
+ var AgentProbeError = class extends Error {
24757
+ code;
24758
+ constructor(code, message, options = {}) {
24759
+ super(message, options);
24760
+ this.code = code;
24761
+ this.name = "AgentProbeError";
24253
24762
  }
24254
24763
  };
24255
- var UnavailableAgent = class extends AgentDiscovery {
24256
- };
24257
- var MissingAdapter = class extends UnavailableAgent {
24258
- code = "adapter_not_found";
24259
- message = "ACP adapter not found";
24260
- status = "missing_adapter";
24261
- constructor(specification) {
24262
- super(specification);
24764
+
24765
+ // src/agent-catalog/agents/deepseek-harness-agent.ts
24766
+ async function validateAgentHome(path2) {
24767
+ if (!isAbsolute2(path2) || normalize(path2) !== path2) {
24768
+ throw new AgentProbeError(
24769
+ "agent_environment_invalid",
24770
+ "The configured Agent home is invalid"
24771
+ );
24263
24772
  }
24264
- };
24265
- var MissingAgent = class extends UnavailableAgent {
24266
- code = "agent_not_found";
24267
- message = "Agent executable not found";
24268
- status = "missing_agent";
24269
- constructor(specification) {
24270
- super(specification);
24773
+ try {
24774
+ const resolved = await realpath3(path2);
24775
+ const metadata = await stat3(resolved);
24776
+ if (!metadata.isDirectory() || typeof process.getuid === "function" && metadata.uid !== process.getuid()) {
24777
+ throw new Error("Agent home is not a user-owned directory");
24778
+ }
24779
+ return resolved;
24780
+ } catch (error61) {
24781
+ if (error61 instanceof AgentProbeError) {
24782
+ throw error61;
24783
+ }
24784
+ throw new AgentProbeError(
24785
+ "agent_environment_invalid",
24786
+ "The configured Agent home is invalid",
24787
+ { cause: error61 }
24788
+ );
24789
+ }
24790
+ }
24791
+ var DeepSeekHarnessAgentSpecification = class extends DirectAcpAgentDefinition {
24792
+ adapterVersion = DEEPSEEK_HARNESS_PACKAGE.version;
24793
+ authenticationCommand = () => "dsh web";
24794
+ agentExecutable = "dsh";
24795
+ id = "deepseek-harness";
24796
+ label = "DeepSeek Harness";
24797
+ constructor() {
24798
+ super(
24799
+ "MOBIUS_DEEPSEEK_HARNESS_PATH",
24800
+ ["--profile", "acp"],
24801
+ [
24802
+ "agents",
24803
+ "deepseek-harness",
24804
+ DEEPSEEK_HARNESS_PACKAGE.version,
24805
+ "node_modules",
24806
+ "@deepseek-ai",
24807
+ "dsh",
24808
+ "lib",
24809
+ "bin.js"
24810
+ ]
24811
+ );
24271
24812
  }
24813
+ createLaunchEnvironment = async (agent, context) => {
24814
+ let selectedHome = context.environment["DSH_HOME"];
24815
+ try {
24816
+ const managed = await this.resolveManagedAgent(
24817
+ readStateDirectory(context.environment),
24818
+ context.platform ?? process.platform,
24819
+ context.signal
24820
+ );
24821
+ if (managed.path === agent.path) {
24822
+ selectedHome = join7(
24823
+ readStateDirectory(context.environment),
24824
+ "agents",
24825
+ this.id,
24826
+ "home"
24827
+ );
24828
+ }
24829
+ } catch {
24830
+ context.signal.throwIfAborted();
24831
+ }
24832
+ if (selectedHome === void 0 || selectedHome.length === 0) {
24833
+ return Object.freeze({ DSH_PERMISSION_MODE: "workspace-write" });
24834
+ }
24835
+ return Object.freeze({
24836
+ DSH_HOME: await validateAgentHome(selectedHome),
24837
+ DSH_PERMISSION_MODE: "workspace-write"
24838
+ });
24839
+ };
24840
+ resolveManagedAgent = async (stateDirectory, _platform, signal) => {
24841
+ signal.throwIfAborted();
24842
+ const executable = await validateManagedNpmPackage(
24843
+ join7(stateDirectory, "agents", this.id, DEEPSEEK_HARNESS_PACKAGE.version),
24844
+ DEEPSEEK_HARNESS_PACKAGE
24845
+ );
24846
+ signal.throwIfAborted();
24847
+ return executable;
24848
+ };
24849
+ verifyAcp = (_connection, initialized, _defaultWorkspace, _signal) => {
24850
+ const capabilities = initialized.agentCapabilities ?? {};
24851
+ const session = capabilities.sessionCapabilities;
24852
+ const prompt = capabilities.promptCapabilities;
24853
+ if ((initialized.authMethods ?? []).length !== 0 || capabilities.loadSession === true || capabilities.mcpCapabilities?.http !== true || session?.close == null || session.list == null || session.resume == null || session.additionalDirectories != null || session.delete != null || session.fork != null || prompt?.audio === true || prompt?.embeddedContext === true || prompt?.image === true) {
24854
+ throw new AgentProbeError(
24855
+ "acp_incompatible",
24856
+ "DeepSeek Harness reported an unsupported ACP capability set"
24857
+ );
24858
+ }
24859
+ return Promise.resolve();
24860
+ };
24272
24861
  };
24273
- var ProbeFailed = class extends UnavailableAgent {
24862
+
24863
+ // src/agent-catalog/agents/opencode-agent.ts
24864
+ import { join as join9 } from "node:path";
24865
+
24866
+ // src/agent-installation/managed-agent-archive.ts
24867
+ import { createHash as createHash2 } from "node:crypto";
24868
+ import { createReadStream } from "node:fs";
24869
+ import {
24870
+ chmod,
24871
+ copyFile,
24872
+ mkdir as mkdir2,
24873
+ mkdtemp as mkdtemp2,
24874
+ open as open5,
24875
+ realpath as realpath4,
24876
+ rename as rename2,
24877
+ rm as rm2,
24878
+ stat as stat4,
24879
+ writeFile
24880
+ } from "node:fs/promises";
24881
+ import { dirname as dirname4, isAbsolute as isAbsolute3, join as join8, relative as relative2, sep as sep2 } from "node:path";
24882
+
24883
+ // src/agent-installation/verified-download.ts
24884
+ import { createHash } from "node:crypto";
24885
+ import { open as open4, unlink } from "node:fs/promises";
24886
+ import { fetch } from "undici";
24887
+
24888
+ // src/network/environment-proxy.ts
24889
+ import { EnvHttpProxyAgent } from "undici";
24890
+ var environmentProxyDispatcher = new EnvHttpProxyAgent();
24891
+
24892
+ // src/agent-installation/verified-download.ts
24893
+ var MAX_REDIRECTS = 4;
24894
+ var REDIRECT_STATUSES = /* @__PURE__ */ new Set([301, 302, 303, 307, 308]);
24895
+ var InstallerDownloadError = class extends Error {
24274
24896
  code;
24275
- message;
24276
- status = "probe_failed";
24277
- constructor(specification, code, message) {
24278
- super(specification);
24897
+ constructor(code, message, options = {}) {
24898
+ super(message, options);
24279
24899
  this.code = code;
24280
- this.message = message;
24900
+ this.name = "InstallerDownloadError";
24281
24901
  }
24282
24902
  };
24283
- var IncompatibleAdapter = class extends UnavailableAgent {
24284
- code = "acp_incompatible";
24285
- message = "ACP adapter is incompatible";
24286
- status = "incompatible_adapter";
24287
- constructor(specification) {
24288
- super(specification);
24903
+ var VerifiedDownload = class {
24904
+ bytes;
24905
+ sha256;
24906
+ url;
24907
+ constructor(url2, bytes, sha256) {
24908
+ this.bytes = bytes;
24909
+ this.sha256 = sha256;
24910
+ this.url = url2;
24289
24911
  }
24290
24912
  };
24291
- var LocalAgentInventory = class {
24292
- available;
24293
- discoveries;
24294
- installable;
24295
- unavailable;
24296
- constructor(discoveries, grantedAgents = /* @__PURE__ */ new Set(), platform = process.platform, architecture = process.arch) {
24297
- const available = [];
24298
- const unavailable = [];
24299
- for (const discovery of discoveries) {
24300
- if (discovery instanceof AvailableAgent) {
24301
- available.push(discovery);
24302
- } else if (discovery instanceof UnavailableAgent) {
24303
- unavailable.push(discovery);
24304
- } else {
24305
- throw new Error("Unsupported Agent discovery outcome");
24306
- }
24307
- }
24308
- this.available = Object.freeze(available);
24309
- this.discoveries = Object.freeze([...discoveries]);
24310
- this.installable = Object.freeze(
24311
- unavailable.filter(
24312
- (discovery) => discovery.specification.supportsInstallation(platform, architecture)
24313
- ).map(
24314
- (discovery) => new InstallableAgentDefinition(
24315
- discovery.specification.id,
24316
- discovery.specification.label,
24317
- !grantedAgents.has(discovery.specification.id)
24318
- )
24319
- )
24913
+ var UndiciInstallerDownloadTransport = class {
24914
+ get = async (url2, signal) => await fetch(url2, {
24915
+ dispatcher: environmentProxyDispatcher,
24916
+ headers: {
24917
+ accept: "text/plain, application/octet-stream;q=0.9",
24918
+ "user-agent": "Mobius-Agent-Installer/0.0.3"
24919
+ },
24920
+ method: "GET",
24921
+ redirect: "manual",
24922
+ signal
24923
+ });
24924
+ };
24925
+ function validateUrl(url2, allowedHosts) {
24926
+ if (url2.protocol !== "https:" || url2.username.length > 0 || url2.password.length > 0 || url2.port.length > 0 || !allowedHosts.has(url2.hostname)) {
24927
+ throw new InstallerDownloadError(
24928
+ "installer_host_not_allowed",
24929
+ "The installer download target is not allowed"
24930
+ );
24931
+ }
24932
+ }
24933
+ async function fetchInstaller(options, signal, transport) {
24934
+ let url2 = new URL(options.url);
24935
+ for (let redirectCount = 0; redirectCount <= MAX_REDIRECTS; redirectCount += 1) {
24936
+ validateUrl(url2, options.allowedHosts);
24937
+ const response = await transport.get(url2, signal);
24938
+ if (!REDIRECT_STATUSES.has(response.status)) {
24939
+ return { response, url: url2 };
24940
+ }
24941
+ await response.body?.cancel();
24942
+ const location = response.headers.get("location");
24943
+ if (location === null || redirectCount === MAX_REDIRECTS) {
24944
+ throw new InstallerDownloadError(
24945
+ "installer_redirect_invalid",
24946
+ "The installer returned an invalid redirect"
24947
+ );
24948
+ }
24949
+ let redirected;
24950
+ try {
24951
+ redirected = new URL(location, url2);
24952
+ } catch (error61) {
24953
+ throw new InstallerDownloadError(
24954
+ "installer_redirect_invalid",
24955
+ "The installer returned an invalid redirect",
24956
+ { cause: error61 }
24957
+ );
24958
+ }
24959
+ try {
24960
+ validateUrl(redirected, options.allowedHosts);
24961
+ } catch (error61) {
24962
+ throw new InstallerDownloadError(
24963
+ "installer_redirect_not_allowed",
24964
+ "The installer redirect left the approved host allowlist",
24965
+ { cause: error61 }
24966
+ );
24967
+ }
24968
+ url2 = redirected;
24969
+ }
24970
+ throw new InstallerDownloadError(
24971
+ "installer_redirect_invalid",
24972
+ "The installer returned too many redirects"
24973
+ );
24974
+ }
24975
+ async function writeCompleteChunk(handle, chunk) {
24976
+ let offset = 0;
24977
+ while (offset < chunk.byteLength) {
24978
+ const written = await handle.write(
24979
+ chunk,
24980
+ offset,
24981
+ chunk.byteLength - offset
24982
+ );
24983
+ if (written.bytesWritten < 1) {
24984
+ throw new InstallerDownloadError(
24985
+ "installer_write_failed",
24986
+ "The verified installer could not be stored"
24987
+ );
24988
+ }
24989
+ offset += written.bytesWritten;
24990
+ }
24991
+ }
24992
+ async function downloadVerifiedFile(options, transport = new UndiciInstallerDownloadTransport()) {
24993
+ options.signal.throwIfAborted();
24994
+ const timeoutSignal = AbortSignal.timeout(options.timeoutMilliseconds);
24995
+ const signal = AbortSignal.any([options.signal, timeoutSignal]);
24996
+ let handle = null;
24997
+ let responseBody = null;
24998
+ try {
24999
+ const fetched = await fetchInstaller(options, signal, transport);
25000
+ responseBody = fetched.response.body;
25001
+ if (!fetched.response.ok || fetched.response.body === null) {
25002
+ throw new InstallerDownloadError(
25003
+ "installer_download_failed",
25004
+ "The approved installer could not be downloaded"
25005
+ );
25006
+ }
25007
+ const contentLength = fetched.response.headers.get("content-length");
25008
+ if (contentLength !== null) {
25009
+ const declaredLength = Number(contentLength);
25010
+ if (!Number.isSafeInteger(declaredLength) || declaredLength < 1 || declaredLength > options.maximumBytes) {
25011
+ throw new InstallerDownloadError(
25012
+ "installer_size_invalid",
25013
+ "The installer size is outside the approved limit"
25014
+ );
25015
+ }
25016
+ }
25017
+ handle = await open4(options.destination, "wx", 384);
25018
+ const digest = createHash("sha256");
25019
+ const reader = fetched.response.body.getReader();
25020
+ let bytes = 0;
25021
+ try {
25022
+ while (true) {
25023
+ signal.throwIfAborted();
25024
+ const chunk = await reader.read();
25025
+ if (chunk.done) {
25026
+ break;
25027
+ }
25028
+ bytes += chunk.value.byteLength;
25029
+ if (bytes > options.maximumBytes) {
25030
+ throw new InstallerDownloadError(
25031
+ "installer_size_invalid",
25032
+ "The installer exceeded the approved size limit"
25033
+ );
25034
+ }
25035
+ digest.update(chunk.value);
25036
+ await writeCompleteChunk(handle, chunk.value);
25037
+ }
25038
+ } finally {
25039
+ await reader.cancel().catch(() => void 0);
25040
+ reader.releaseLock();
25041
+ }
25042
+ if (bytes === 0) {
25043
+ throw new InstallerDownloadError(
25044
+ "installer_verification_failed",
25045
+ "The downloaded installer is empty"
25046
+ );
25047
+ }
25048
+ await handle.sync();
25049
+ await handle.close();
25050
+ handle = null;
25051
+ return new VerifiedDownload(fetched.url, bytes, digest.digest("hex"));
25052
+ } catch (error61) {
25053
+ if (handle !== null) {
25054
+ await handle.close().catch(() => void 0);
25055
+ }
25056
+ await unlink(options.destination).catch(() => void 0);
25057
+ if (options.signal.aborted) {
25058
+ options.signal.throwIfAborted();
25059
+ }
25060
+ if (timeoutSignal.aborted) {
25061
+ throw new InstallerDownloadError(
25062
+ "installer_download_timeout",
25063
+ "The installer download timed out",
25064
+ { cause: error61 }
25065
+ );
25066
+ }
25067
+ if (error61 instanceof InstallerDownloadError) {
25068
+ throw error61;
25069
+ }
25070
+ throw new InstallerDownloadError(
25071
+ "installer_download_failed",
25072
+ "The approved installer could not be downloaded",
25073
+ { cause: error61 }
25074
+ );
25075
+ } finally {
25076
+ await responseBody?.cancel().catch(() => void 0);
25077
+ }
25078
+ }
25079
+
25080
+ // src/agent-installation/managed-agent-archive.ts
25081
+ var ARCHIVE_DOWNLOAD_LIMIT_BYTES = 128 * 1024 * 1024;
25082
+ var ARCHIVE_DOWNLOAD_TIMEOUT_MILLISECONDS = 2 * 60 * 1e3;
25083
+ var ARCHIVE_EXTRACTION_TIMEOUT_MILLISECONDS = 6e4;
25084
+ var MANIFEST_LIMIT_BYTES = 16 * 1024;
25085
+ var MINIMAL_PATH = "/usr/bin:/bin";
25086
+ var ManagedAgentArchiveDefinition = class {
25087
+ archiveName;
25088
+ archiveSha256;
25089
+ archiveUrl;
25090
+ executableName;
25091
+ version;
25092
+ constructor(version2, archiveName, archiveUrl, archiveSha256, executableName) {
25093
+ this.archiveName = archiveName;
25094
+ this.archiveSha256 = archiveSha256;
25095
+ this.archiveUrl = new URL(archiveUrl);
25096
+ this.executableName = executableName;
25097
+ this.version = version2;
25098
+ }
25099
+ };
25100
+ var ZipManagedAgentArchiveDefinition = class extends ManagedAgentArchiveDefinition {
25101
+ extractor = "/usr/bin/unzip";
25102
+ extractArguments = (archivePath, destination) => ["-q", archivePath, "-d", destination];
25103
+ listArguments = (archivePath) => [
25104
+ "-Z1",
25105
+ archivePath
25106
+ ];
25107
+ };
25108
+ var TarGzipManagedAgentArchiveDefinition = class extends ManagedAgentArchiveDefinition {
25109
+ extractor = "/usr/bin/tar";
25110
+ extractArguments = (archivePath, destination) => ["-xzf", archivePath, "-C", destination];
25111
+ listArguments = (archivePath) => [
25112
+ "-tzf",
25113
+ archivePath
25114
+ ];
25115
+ };
25116
+ var ManagedAgentArchiveError = class extends Error {
25117
+ code;
25118
+ constructor(code, message, options = {}) {
25119
+ super(message, options);
25120
+ this.code = code;
25121
+ this.name = "ManagedAgentArchiveError";
25122
+ }
25123
+ };
25124
+ var ManagedAgentArchiveDownloader = class {
25125
+ download = async (options) => await downloadVerifiedFile(options);
25126
+ };
25127
+ function isRecord6(value) {
25128
+ return typeof value === "object" && value !== null && !Array.isArray(value);
25129
+ }
25130
+ function isContainedPath2(root, candidate) {
25131
+ const difference = relative2(root, candidate);
25132
+ return difference.length > 0 && difference !== ".." && !difference.startsWith(`..${sep2}`) && !isAbsolute3(difference);
25133
+ }
25134
+ async function hashFile(path2, signal) {
25135
+ signal.throwIfAborted();
25136
+ const digest = createHash2("sha256");
25137
+ const stream = createReadStream(path2, { signal });
25138
+ try {
25139
+ for await (const chunk of stream) {
25140
+ signal.throwIfAborted();
25141
+ if (!(chunk instanceof Uint8Array)) {
25142
+ throw new ManagedAgentArchiveError(
25143
+ "managed_archive_verification_failed",
25144
+ "The managed Agent archive produced invalid bytes"
25145
+ );
25146
+ }
25147
+ digest.update(chunk);
25148
+ }
25149
+ return digest.digest("hex");
25150
+ } catch (error61) {
25151
+ if (signal.aborted) {
25152
+ signal.throwIfAborted();
25153
+ }
25154
+ if (error61 instanceof ManagedAgentArchiveError) {
25155
+ throw error61;
25156
+ }
25157
+ throw new ManagedAgentArchiveError(
25158
+ "managed_archive_verification_failed",
25159
+ "The managed Agent artifact could not be verified",
25160
+ { cause: error61 }
25161
+ );
25162
+ }
25163
+ }
25164
+ async function readManifest(path2) {
25165
+ let handle;
25166
+ try {
25167
+ handle = await open5(path2, "r");
25168
+ } catch (error61) {
25169
+ throw new ManagedAgentArchiveError(
25170
+ "managed_archive_verification_failed",
25171
+ "The managed Agent archive manifest is invalid",
25172
+ { cause: error61 }
25173
+ );
25174
+ }
25175
+ try {
25176
+ const metadata = await handle.stat();
25177
+ if (!metadata.isFile() || metadata.size > MANIFEST_LIMIT_BYTES) {
25178
+ throw new ManagedAgentArchiveError(
25179
+ "managed_archive_verification_failed",
25180
+ "The managed Agent archive manifest is invalid"
25181
+ );
25182
+ }
25183
+ const parsed = JSON.parse(
25184
+ await handle.readFile({ encoding: "utf8" })
25185
+ );
25186
+ if (!isRecord6(parsed)) {
25187
+ throw new ManagedAgentArchiveError(
25188
+ "managed_archive_verification_failed",
25189
+ "The managed Agent archive manifest is invalid"
25190
+ );
25191
+ }
25192
+ return parsed;
25193
+ } catch (error61) {
25194
+ if (error61 instanceof ManagedAgentArchiveError) {
25195
+ throw error61;
25196
+ }
25197
+ throw new ManagedAgentArchiveError(
25198
+ "managed_archive_verification_failed",
25199
+ "The managed Agent archive manifest is invalid",
25200
+ { cause: error61 }
25201
+ );
25202
+ } finally {
25203
+ await handle.close();
25204
+ }
25205
+ }
25206
+ async function validateManagedAgentArchive(root, definition, signal) {
25207
+ try {
25208
+ const rootPath = await realpath4(root);
25209
+ const rootMetadata = await stat4(rootPath);
25210
+ if (!rootMetadata.isDirectory() || typeof process.getuid === "function" && rootMetadata.uid !== process.getuid()) {
25211
+ throw new Error("Managed Agent root is not user-owned");
25212
+ }
25213
+ const manifest = await readManifest(join8(rootPath, "archive.json"));
25214
+ if (manifest["archiveSha256"] !== definition.archiveSha256 || manifest["archiveUrl"] !== definition.archiveUrl.toString() || manifest["version"] !== definition.version || typeof manifest["executableSha256"] !== "string") {
25215
+ throw new Error("Managed Agent archive identity is invalid");
25216
+ }
25217
+ const executable = await resolveExecutablePath(
25218
+ join8(rootPath, "bin", definition.executableName)
25219
+ );
25220
+ if (executable === null || !isContainedPath2(rootPath, executable.path) || await hashFile(executable.path, signal) !== manifest["executableSha256"]) {
25221
+ throw new Error("Managed Agent executable is invalid");
25222
+ }
25223
+ return executable;
25224
+ } catch (error61) {
25225
+ if (signal.aborted) {
25226
+ signal.throwIfAborted();
25227
+ }
25228
+ if (error61 instanceof ManagedAgentArchiveError) {
25229
+ throw error61;
25230
+ }
25231
+ throw new ManagedAgentArchiveError(
25232
+ "managed_archive_verification_failed",
25233
+ "The managed Agent archive did not match its pinned artifact",
25234
+ { cause: error61 }
25235
+ );
25236
+ }
25237
+ }
25238
+ function validateArchiveEntries(output2, definition) {
25239
+ const entries = output2.split(/\r?\n/).map((entry) => entry.trim()).filter((entry) => entry.length > 0);
25240
+ if (entries.length !== 1 || entries[0] !== definition.executableName && entries[0] !== `./${definition.executableName}`) {
25241
+ throw new ManagedAgentArchiveError(
25242
+ "managed_archive_verification_failed",
25243
+ "The managed Agent archive contains unexpected entries"
25244
+ );
25245
+ }
25246
+ }
25247
+ var ManagedAgentArchiveInstaller = class {
25248
+ #downloader;
25249
+ constructor(downloader = new ManagedAgentArchiveDownloader()) {
25250
+ this.#downloader = downloader;
25251
+ }
25252
+ install = async (root, definition, signal) => {
25253
+ signal.throwIfAborted();
25254
+ try {
25255
+ const metadata = await stat4(root);
25256
+ if (metadata.isDirectory()) {
25257
+ return await validateManagedAgentArchive(root, definition, signal);
25258
+ }
25259
+ } catch (error61) {
25260
+ if (error61 instanceof ManagedAgentArchiveError || !(error61 instanceof Error) || !("code" in error61) || error61.code !== "ENOENT") {
25261
+ throw error61;
25262
+ }
25263
+ }
25264
+ const parent = dirname4(root);
25265
+ await mkdir2(parent, { mode: 448, recursive: true });
25266
+ const working = await mkdtemp2(
25267
+ join8(parent, `.${definition.version}.archive-`)
25268
+ );
25269
+ const staging = await mkdtemp2(
25270
+ join8(parent, `.${definition.version}.staging-`)
25271
+ );
25272
+ try {
25273
+ const archivePath = join8(working, definition.archiveName);
25274
+ const extractionRoot = join8(working, "extracted");
25275
+ await mkdir2(extractionRoot, { mode: 448 });
25276
+ const canonicalExtractionRoot = await realpath4(extractionRoot);
25277
+ const download = await this.#downloader.download({
25278
+ allowedHosts: /* @__PURE__ */ new Set([
25279
+ "github.com",
25280
+ "objects.githubusercontent.com",
25281
+ "release-assets.githubusercontent.com"
25282
+ ]),
25283
+ destination: archivePath,
25284
+ maximumBytes: ARCHIVE_DOWNLOAD_LIMIT_BYTES,
25285
+ signal,
25286
+ timeoutMilliseconds: ARCHIVE_DOWNLOAD_TIMEOUT_MILLISECONDS,
25287
+ url: definition.archiveUrl
25288
+ });
25289
+ if (download.sha256 !== definition.archiveSha256) {
25290
+ throw new ManagedAgentArchiveError(
25291
+ "managed_archive_verification_failed",
25292
+ "The managed Agent archive checksum is invalid"
25293
+ );
25294
+ }
25295
+ const list = await runBoundedProcess({
25296
+ arguments: definition.listArguments(archivePath),
25297
+ command: definition.extractor,
25298
+ cwd: working,
25299
+ environment: { PATH: MINIMAL_PATH },
25300
+ outputLimitBytes: 64 * 1024,
25301
+ signal,
25302
+ timeoutMilliseconds: ARCHIVE_EXTRACTION_TIMEOUT_MILLISECONDS
25303
+ });
25304
+ validateArchiveEntries(list.stdout, definition);
25305
+ await runBoundedProcess({
25306
+ arguments: definition.extractArguments(archivePath, extractionRoot),
25307
+ command: definition.extractor,
25308
+ cwd: working,
25309
+ environment: { PATH: MINIMAL_PATH },
25310
+ outputLimitBytes: 64 * 1024,
25311
+ signal,
25312
+ timeoutMilliseconds: ARCHIVE_EXTRACTION_TIMEOUT_MILLISECONDS
25313
+ });
25314
+ const extracted = await realpath4(
25315
+ join8(canonicalExtractionRoot, definition.executableName)
25316
+ );
25317
+ const extractedMetadata = await stat4(extracted);
25318
+ if (!isContainedPath2(canonicalExtractionRoot, extracted) || !extractedMetadata.isFile()) {
25319
+ throw new ManagedAgentArchiveError(
25320
+ "managed_archive_verification_failed",
25321
+ "The managed Agent archive executable is invalid"
25322
+ );
25323
+ }
25324
+ const binDirectory = join8(staging, "bin");
25325
+ const executablePath = join8(binDirectory, definition.executableName);
25326
+ await mkdir2(binDirectory, { mode: 448 });
25327
+ await copyFile(extracted, executablePath);
25328
+ await chmod(executablePath, 448);
25329
+ const executableSha256 = await hashFile(executablePath, signal);
25330
+ await writeFile(
25331
+ join8(staging, "archive.json"),
25332
+ `${JSON.stringify({
25333
+ archiveSha256: definition.archiveSha256,
25334
+ archiveUrl: definition.archiveUrl.toString(),
25335
+ executableSha256,
25336
+ version: definition.version
25337
+ })}
25338
+ `,
25339
+ { mode: 384 }
25340
+ );
25341
+ await validateManagedAgentArchive(staging, definition, signal);
25342
+ try {
25343
+ await rename2(staging, root);
25344
+ } catch (error61) {
25345
+ try {
25346
+ return await validateManagedAgentArchive(root, definition, signal);
25347
+ } catch {
25348
+ throw new ManagedAgentArchiveError(
25349
+ "managed_archive_publish_failed",
25350
+ "The managed Agent archive could not be published",
25351
+ { cause: error61 }
25352
+ );
25353
+ }
25354
+ }
25355
+ return await validateManagedAgentArchive(root, definition, signal);
25356
+ } catch (error61) {
25357
+ if (signal.aborted) {
25358
+ signal.throwIfAborted();
25359
+ }
25360
+ if (error61 instanceof ManagedAgentArchiveError) {
25361
+ throw error61;
25362
+ }
25363
+ throw new ManagedAgentArchiveError(
25364
+ "managed_archive_install_failed",
25365
+ "The pinned Agent archive could not be installed",
25366
+ { cause: error61 }
25367
+ );
25368
+ } finally {
25369
+ await Promise.all([
25370
+ rm2(working, { force: true, recursive: true }),
25371
+ rm2(staging, { force: true, recursive: true })
25372
+ ]);
25373
+ }
25374
+ };
25375
+ };
25376
+
25377
+ // src/agent-installation/opencode-managed-release.ts
25378
+ var OPENCODE_MANAGED_VERSION = "1.18.29";
25379
+ function releaseUrl(asset) {
25380
+ return new URL(
25381
+ `https://github.com/anomalyco/opencode/releases/download/v${OPENCODE_MANAGED_VERSION}/${asset}`
25382
+ );
25383
+ }
25384
+ function openCodeManagedArchive(platform, architecture) {
25385
+ if (platform === "darwin" && architecture === "arm64") {
25386
+ const asset = "opencode-darwin-arm64.zip";
25387
+ return new ZipManagedAgentArchiveDefinition(
25388
+ OPENCODE_MANAGED_VERSION,
25389
+ asset,
25390
+ releaseUrl(asset),
25391
+ "fe764f7f360c584a83e18dd5f23fb1a6b2725f5ee8854b0252fe558f7798e946",
25392
+ "opencode"
25393
+ );
25394
+ }
25395
+ if (platform === "darwin" && architecture === "x64") {
25396
+ const asset = "opencode-darwin-x64.zip";
25397
+ return new ZipManagedAgentArchiveDefinition(
25398
+ OPENCODE_MANAGED_VERSION,
25399
+ asset,
25400
+ releaseUrl(asset),
25401
+ "9858853e7bacdbbd22c2d70c377e009dc4b354dd04f5588705411e7afb89fd2d",
25402
+ "opencode"
25403
+ );
25404
+ }
25405
+ if (platform === "linux" && architecture === "arm64") {
25406
+ const asset = "opencode-linux-arm64.tar.gz";
25407
+ return new TarGzipManagedAgentArchiveDefinition(
25408
+ OPENCODE_MANAGED_VERSION,
25409
+ asset,
25410
+ releaseUrl(asset),
25411
+ "70baf769395ca4e7a68924026530c390eace194f3b7e4919d4efcb2aa2eed3c0",
25412
+ "opencode"
25413
+ );
25414
+ }
25415
+ if (platform === "linux" && architecture === "x64") {
25416
+ const asset = "opencode-linux-x64.tar.gz";
25417
+ return new TarGzipManagedAgentArchiveDefinition(
25418
+ OPENCODE_MANAGED_VERSION,
25419
+ asset,
25420
+ releaseUrl(asset),
25421
+ "ea800b7ff56226b70952126c9fc1e2517ca4c4b5682fd9d3f9e87449697a1194",
25422
+ "opencode"
25423
+ );
25424
+ }
25425
+ throw new Error(
25426
+ "OpenCode does not publish an approved archive for this platform"
25427
+ );
25428
+ }
25429
+
25430
+ // src/agent-catalog/agents/opencode-agent.ts
25431
+ var OpenCodeAgentSpecification = class extends DirectAcpAgentDefinition {
25432
+ versionProbeTimeoutMilliseconds = 15e3;
25433
+ adapterVersion = OPENCODE_MANAGED_VERSION;
25434
+ authenticationCommand = () => "opencode auth login";
25435
+ agentExecutable = "opencode";
25436
+ id = "opencode";
25437
+ label = "OpenCode";
25438
+ constructor() {
25439
+ super(
25440
+ "MOBIUS_OPENCODE_PATH",
25441
+ ["acp"],
25442
+ [
25443
+ "agents",
25444
+ "opencode",
25445
+ OPENCODE_MANAGED_VERSION,
25446
+ "bin",
25447
+ process.platform === "win32" ? "opencode.exe" : "opencode"
25448
+ ]
25449
+ );
25450
+ }
25451
+ createLaunchEnvironment = async (_agent, _context) => Object.freeze({ OPENCODE_DISABLE_AUTOUPDATE: "1" });
25452
+ resolveManagedAgent = async (stateDirectory, platform, signal) => await validateManagedAgentArchive(
25453
+ join9(stateDirectory, "agents", this.id, OPENCODE_MANAGED_VERSION),
25454
+ openCodeManagedArchive(platform, process.arch),
25455
+ signal
25456
+ );
25457
+ verifyAcp = (_connection, initialized, _defaultWorkspace, _signal) => {
25458
+ const capabilities = initialized.agentCapabilities ?? {};
25459
+ const session = capabilities.sessionCapabilities;
25460
+ if (capabilities.loadSession !== true || session?.close == null || session.list == null || session.resume == null) {
25461
+ throw new AgentProbeError(
25462
+ "acp_incompatible",
25463
+ "OpenCode does not support the required ACP session lifecycle"
25464
+ );
25465
+ }
25466
+ return Promise.resolve();
25467
+ };
25468
+ };
25469
+
25470
+ // src/agent-catalog/agents/pi-agent.ts
25471
+ import { join as join10 } from "node:path";
25472
+ import {
25473
+ methods as methods3
25474
+ } from "@agentclientprotocol/sdk";
25475
+
25476
+ // src/agent-installation/pi-managed-packages.ts
25477
+ var PI_ACP_PACKAGE = new SriManagedNpmPackageDefinition(
25478
+ "pi-acp",
25479
+ "0.0.33",
25480
+ "pi-acp",
25481
+ "sha512-vX9kY1tK14E72G4dBAx+RGCk/k7XPjTHls6dLUxA8WSkBav6B6JHuSBv3eusp50LCR/GTRsR2kIKsG0Z5jANzw==",
25482
+ "https://registry.npmjs.org/pi-acp/-/pi-acp-0.0.33.tgz"
25483
+ );
25484
+ var PI_AGENT_PACKAGE = new SriManagedNpmPackageDefinition(
25485
+ "@earendil-works/pi-coding-agent",
25486
+ "0.85.0",
25487
+ "pi",
25488
+ "sha512-INxVkLAVfAMju5MojJpmyu/0bMP+r+ffZuS7UqVv32E2JwHBRbcHfELDfmFNvapEbgYfKN2r9OYO1p3TqDBR+g==",
25489
+ "https://registry.npmjs.org/@earendil-works/pi-coding-agent/-/pi-coding-agent-0.85.0.tgz"
25490
+ );
25491
+
25492
+ // src/agent-catalog/agents/pi-agent.ts
25493
+ var ACP_PROBE_TIMEOUT_MILLISECONDS2 = 3e4;
25494
+ var PROMPT_TIMEOUT_MILLISECONDS = 5 * 60 * 1e3;
25495
+ var PiAgentSpecification = class extends BridgedAcpAgentDefinition {
25496
+ acpProbeTimeoutMilliseconds = ACP_PROBE_TIMEOUT_MILLISECONDS2;
25497
+ adapterEnvironmentVariable = "PI_ACP_PI_COMMAND";
25498
+ adapterOverrideVariable = "MOBIUS_PI_ACP_PATH";
25499
+ adapterPackageDefinition = PI_ACP_PACKAGE;
25500
+ adapterVersionArguments = [];
25501
+ authenticationCommand = () => "pi-acp --terminal-login";
25502
+ agentExecutable = "pi";
25503
+ agentOverrideVariable = "MOBIUS_PI_PATH";
25504
+ id = "pi";
25505
+ label = "Pi";
25506
+ managedAdapterExecutablePath = [
25507
+ "adapters",
25508
+ "pi",
25509
+ PI_ACP_PACKAGE.version,
25510
+ "node_modules",
25511
+ "pi-acp",
25512
+ "dist",
25513
+ "index.js"
25514
+ ];
25515
+ managedAgentExecutablePath = [
25516
+ "agents",
25517
+ "pi",
25518
+ PI_AGENT_PACKAGE.version,
25519
+ "node_modules",
25520
+ "@earendil-works",
25521
+ "pi-coding-agent",
25522
+ "dist",
25523
+ "bundle",
25524
+ "cli.js"
25525
+ ];
25526
+ promptTimeoutMilliseconds = PROMPT_TIMEOUT_MILLISECONDS;
25527
+ resolveManagedAgent = async (stateDirectory, _platform, signal) => {
25528
+ signal.throwIfAborted();
25529
+ const executable = await validateManagedNpmPackage(
25530
+ join10(stateDirectory, "agents", this.id, PI_AGENT_PACKAGE.version),
25531
+ PI_AGENT_PACKAGE
25532
+ );
25533
+ signal.throwIfAborted();
25534
+ return executable;
25535
+ };
25536
+ verifyAcp = async (connection, initialized, defaultWorkspace, signal) => {
25537
+ const capabilities = initialized.agentCapabilities ?? {};
25538
+ if (capabilities.loadSession !== true) {
25539
+ throw new AgentProbeError(
25540
+ "acp_incompatible",
25541
+ "Pi ACP adapter does not support session recovery"
25542
+ );
25543
+ }
25544
+ const session = await connection.agent.request(
25545
+ methods3.agent.session.new,
25546
+ {
25547
+ additionalDirectories: [],
25548
+ cwd: defaultWorkspace,
25549
+ mcpServers: []
25550
+ },
25551
+ { cancellationSignal: signal }
25552
+ );
25553
+ if (session.sessionId.length === 0) {
25554
+ throw new AgentProbeError(
25555
+ "acp_incompatible",
25556
+ "Pi ACP adapter returned an invalid session"
25557
+ );
25558
+ }
25559
+ const prompt = await connection.agent.request(
25560
+ methods3.agent.session.prompt,
25561
+ {
25562
+ prompt: [{ text: "/session", type: "text" }],
25563
+ sessionId: session.sessionId
25564
+ },
25565
+ { cancellationSignal: signal }
25566
+ );
25567
+ if (prompt.stopReason !== "end_turn") {
25568
+ throw new AgentProbeError(
25569
+ "acp_incompatible",
25570
+ "Pi ACP adapter did not complete its conformance prompt"
25571
+ );
25572
+ }
25573
+ };
25574
+ };
25575
+
25576
+ // src/agent-catalog/agents/supported-agent-specifications.ts
25577
+ function supportedLocalAgentSpecifications() {
25578
+ return Object.freeze([
25579
+ new CodexAgentSpecification(),
25580
+ new ClaudeCodeAgentSpecification(),
25581
+ new PiAgentSpecification(),
25582
+ new DeepSeekHarnessAgentSpecification(),
25583
+ new OpenCodeAgentSpecification()
25584
+ ]);
25585
+ }
25586
+
25587
+ // src/agent-catalog/acp-readiness-probe.ts
25588
+ import { spawn as spawn3 } from "node:child_process";
25589
+ import {
25590
+ methods as methods4,
25591
+ ndJsonStream as ndJsonStream2,
25592
+ PROTOCOL_VERSION as PROTOCOL_VERSION2,
25593
+ RequestError as RequestError2
25594
+ } from "@agentclientprotocol/sdk";
25595
+
25596
+ // src/agent-catalog/executable-discovery.ts
25597
+ import { isAbsolute as isAbsolute4, join as join12 } from "node:path";
25598
+
25599
+ // src/agent-installation/managed-adapter-installer.ts
25600
+ import { join as join11 } from "node:path";
25601
+ var ManagedAdapterInstallError = class extends Error {
25602
+ code;
25603
+ constructor(code, message, options = {}) {
25604
+ super(message, options);
25605
+ this.code = code;
25606
+ this.name = "ManagedAdapterInstallError";
25607
+ }
25608
+ };
25609
+ function translateError(error61) {
25610
+ if (error61 instanceof ManagedAdapterInstallError) {
25611
+ return error61;
25612
+ }
25613
+ if (error61 instanceof ManagedNpmPackageError) {
25614
+ if (error61.code === "package_manager_not_found") {
25615
+ return new ManagedAdapterInstallError(
25616
+ error61.code,
25617
+ "A supported npm executable is required to install the ACP adapter",
25618
+ { cause: error61 }
25619
+ );
25620
+ }
25621
+ if (error61.code === "managed_package_verification_failed") {
25622
+ return new ManagedAdapterInstallError(
25623
+ "adapter_verification_failed",
25624
+ "The managed adapter did not match its pinned artifact",
25625
+ { cause: error61 }
25626
+ );
25627
+ }
25628
+ if (error61.code === "managed_package_publish_failed") {
25629
+ return new ManagedAdapterInstallError(
25630
+ "adapter_publish_failed",
25631
+ "The managed adapter could not be published",
25632
+ { cause: error61 }
25633
+ );
25634
+ }
25635
+ }
25636
+ return new ManagedAdapterInstallError(
25637
+ "adapter_install_failed",
25638
+ "The pinned ACP adapter could not be installed",
25639
+ { cause: error61 }
25640
+ );
25641
+ }
25642
+ async function validateManagedAdapter(root, specification) {
25643
+ try {
25644
+ return await validateManagedNpmPackage(
25645
+ root,
25646
+ specification.adapterPackageDefinition
24320
25647
  );
24321
- this.unavailable = Object.freeze(unavailable);
25648
+ } catch (error61) {
25649
+ throw translateError(error61);
24322
25650
  }
24323
- readyAgents = () => this.available.map((discovery) => discovery.agent);
24324
- };
24325
- var AgentProbeError = class extends Error {
24326
- code;
24327
- constructor(code, message, options = {}) {
24328
- super(message, options);
24329
- this.code = code;
24330
- this.name = "AgentProbeError";
25651
+ }
25652
+ var ManagedAdapterInstaller = class {
25653
+ #environment;
25654
+ #npmInstaller;
25655
+ #stateDirectory;
25656
+ constructor(options, npmInstaller = new ManagedNpmPackageInstaller()) {
25657
+ this.#environment = options.environment;
25658
+ this.#npmInstaller = npmInstaller;
25659
+ this.#stateDirectory = options.stateDirectory;
24331
25660
  }
25661
+ install = async (specification, signal) => {
25662
+ const root = join11(
25663
+ this.#stateDirectory,
25664
+ "adapters",
25665
+ specification.id,
25666
+ specification.adapterVersion
25667
+ );
25668
+ try {
25669
+ return await this.#npmInstaller.install(
25670
+ root,
25671
+ specification.adapterPackageDefinition,
25672
+ this.#environment,
25673
+ signal
25674
+ );
25675
+ } catch (error61) {
25676
+ if (signal.aborted) {
25677
+ signal.throwIfAborted();
25678
+ }
25679
+ throw translateError(error61);
25680
+ }
25681
+ };
24332
25682
  };
24333
- var DiscoveryAcpHandler = class {
24334
- onElicitation = (_request, _signal) => Promise.reject(new Error("ACP probe does not accept elicitations"));
24335
- onElicitationComplete = (_notification) => Promise.resolve();
24336
- onPermission = (_request, _signal) => Promise.reject(new Error("ACP probe does not grant permissions"));
24337
- onUpdate = (_notification) => Promise.resolve();
24338
- };
24339
- async function resolveManagedExecutable(managedExecutablePath, options) {
24340
- return await resolveExecutablePath(
24341
- join6(readStateDirectory(options.environment), ...managedExecutablePath),
24342
- options.platform
24343
- );
25683
+
25684
+ // src/agent-catalog/executable-discovery.ts
25685
+ async function resolveManagedExecutable(specification, context) {
25686
+ try {
25687
+ return await specification.resolveManagedAgent(
25688
+ readStateDirectory(context.environment),
25689
+ context.platform ?? process.platform,
25690
+ context.signal
25691
+ );
25692
+ } catch {
25693
+ context.signal.throwIfAborted();
25694
+ return null;
25695
+ }
24344
25696
  }
24345
- async function resolveManagedAdapterExecutable(specification, options) {
25697
+ async function resolveManagedAdapterExecutable(specification, context) {
24346
25698
  let managed;
24347
25699
  try {
24348
25700
  managed = await validateManagedAdapter(
24349
- join6(
24350
- readStateDirectory(options.environment),
25701
+ join12(
25702
+ readStateDirectory(context.environment),
24351
25703
  "adapters",
24352
25704
  specification.id,
24353
25705
  specification.adapterVersion
@@ -24359,19 +25711,19 @@ async function resolveManagedAdapterExecutable(specification, options) {
24359
25711
  }
24360
25712
  return managed;
24361
25713
  }
24362
- async function resolveSpecificationExecutables(executableName, overrideVariable, resolveManaged, options) {
24363
- const override = options.environment[overrideVariable];
25714
+ async function resolveSpecificationExecutables(executableName, overrideVariable, resolveManaged, context) {
25715
+ const override = context.environment[overrideVariable];
24364
25716
  if (override !== void 0) {
24365
- if (override.length === 0 || !isAbsolute(override)) {
25717
+ if (override.length === 0 || !isAbsolute4(override)) {
24366
25718
  return [];
24367
25719
  }
24368
- const executable = await resolveExecutablePath(override, options.platform);
25720
+ const executable = await resolveExecutablePath(override, context.platform);
24369
25721
  return executable === null ? [] : [executable];
24370
25722
  }
24371
25723
  const external = await findExecutableOnPath(
24372
25724
  executableName,
24373
- options.environment,
24374
- options.platform
25725
+ context.environment,
25726
+ context.platform
24375
25727
  );
24376
25728
  const managed = await resolveManaged();
24377
25729
  if (external === null) {
@@ -24382,44 +25734,47 @@ async function resolveSpecificationExecutables(executableName, overrideVariable,
24382
25734
  }
24383
25735
  return [external, managed];
24384
25736
  }
24385
- async function resolveAgentExecutables(specification, options) {
25737
+ async function resolveAgentExecutables(specification, context) {
24386
25738
  return await resolveSpecificationExecutables(
24387
25739
  specification.agentExecutable,
24388
25740
  specification.agentOverrideVariable,
24389
- async () => await resolveManagedExecutable(
24390
- specification.managedAgentExecutablePath,
24391
- options
24392
- ),
24393
- options
25741
+ async () => await resolveManagedExecutable(specification, context),
25742
+ context
24394
25743
  );
24395
25744
  }
24396
- async function resolveAdapterExecutables(specification, options) {
25745
+ async function resolveAdapterExecutables(specification, context) {
25746
+ if (specification instanceof DirectAcpAgentDefinition) {
25747
+ return await resolveAgentExecutables(specification, context);
25748
+ }
25749
+ if (!(specification instanceof BridgedAcpAgentDefinition)) {
25750
+ throw new Error("Unsupported local Agent execution topology");
25751
+ }
24397
25752
  return await resolveSpecificationExecutables(
24398
25753
  specification.adapterExecutable,
24399
25754
  specification.adapterOverrideVariable,
24400
- async () => await resolveManagedAdapterExecutable(specification, options),
24401
- options
25755
+ async () => await resolveManagedAdapterExecutable(specification, context),
25756
+ context
24402
25757
  );
24403
25758
  }
24404
- async function resolveAgentExecutable(specification, options) {
24405
- const executables = await resolveAgentExecutables(specification, options);
25759
+ async function resolveAgentExecutable(specification, context) {
25760
+ const executables = await resolveAgentExecutables(specification, context);
24406
25761
  return executables[0] ?? null;
24407
25762
  }
24408
- async function resolveAdapterExecutable(specification, options) {
24409
- const executables = await resolveAdapterExecutables(specification, options);
25763
+ async function resolveAdapterExecutable(specification, context) {
25764
+ const executables = await resolveAdapterExecutables(specification, context);
24410
25765
  return executables[0] ?? null;
24411
25766
  }
24412
25767
  function normalizedVersion(output2) {
24413
25768
  return output2.trim().split(/\r?\n/, 1)[0]?.trim().slice(0, 128) ?? "";
24414
25769
  }
24415
- async function probeVersion(executable, environment, defaultWorkspace, signal) {
25770
+ async function probeVersion(executable, arguments_, environment, defaultWorkspace, signal, timeoutMilliseconds) {
24416
25771
  const result = await runBoundedProcess({
24417
- arguments: ["--version"],
25772
+ arguments: arguments_,
24418
25773
  command: executable.path,
24419
25774
  cwd: defaultWorkspace,
24420
25775
  environment,
24421
25776
  signal,
24422
- timeoutMilliseconds: VERSION_PROBE_TIMEOUT_MILLISECONDS
25777
+ timeoutMilliseconds
24423
25778
  });
24424
25779
  const version2 = normalizedVersion(result.stdout || result.stderr);
24425
25780
  if (version2.length === 0) {
@@ -24438,62 +25793,73 @@ var VerifiedAgentExecutable = class {
24438
25793
  this.version = version2;
24439
25794
  }
24440
25795
  };
24441
- async function findVerifiedAgentExecutable(specification, options) {
24442
- const executables = await resolveAgentExecutables(specification, options);
25796
+ async function findVerifiedAgentExecutable(specification, context) {
25797
+ const executables = await resolveAgentExecutables(specification, context);
24443
25798
  for (const executable of executables) {
24444
25799
  try {
24445
25800
  const version2 = await probeVersion(
24446
25801
  executable,
24447
- options.environment,
24448
- options.defaultWorkspace,
24449
- options.signal
25802
+ specification.agentVersionArguments,
25803
+ context.environment,
25804
+ context.defaultWorkspace,
25805
+ context.signal,
25806
+ specification.versionProbeTimeoutMilliseconds
24450
25807
  );
24451
25808
  return new VerifiedAgentExecutable(executable, version2);
24452
25809
  } catch {
24453
- if (options.signal.aborted) {
24454
- options.signal.throwIfAborted();
25810
+ if (context.signal.aborted) {
25811
+ context.signal.throwIfAborted();
24455
25812
  }
24456
25813
  }
24457
25814
  }
24458
25815
  return null;
24459
25816
  }
25817
+
25818
+ // src/agent-catalog/acp-readiness-probe.ts
25819
+ var ACP_OUTPUT_LIMIT_BYTES = 1024 * 1024;
25820
+ var DiscoveryAcpHandler = class {
25821
+ onElicitation = (_request, _signal) => Promise.reject(new Error("ACP probe does not accept elicitations"));
25822
+ onElicitationComplete = (_notification) => Promise.resolve();
25823
+ onPermission = (_request, _signal) => Promise.reject(new Error("ACP probe does not grant permissions"));
25824
+ onUpdate = (_notification) => Promise.resolve();
25825
+ };
24460
25826
  function readableAcpStream(input2) {
24461
25827
  let byteLength = 0;
24462
- let open6 = true;
25828
+ let open7 = true;
24463
25829
  return new ReadableStream({
24464
25830
  start(controller) {
24465
25831
  input2.on("data", (chunk) => {
24466
- if (!open6) {
25832
+ if (!open7) {
24467
25833
  return;
24468
25834
  }
24469
25835
  if (!(chunk instanceof Uint8Array)) {
24470
- open6 = false;
25836
+ open7 = false;
24471
25837
  controller.error(new Error("ACP adapter produced invalid output"));
24472
25838
  return;
24473
25839
  }
24474
25840
  byteLength += chunk.byteLength;
24475
25841
  if (byteLength > ACP_OUTPUT_LIMIT_BYTES) {
24476
- open6 = false;
25842
+ open7 = false;
24477
25843
  controller.error(new Error("ACP adapter output limit exceeded"));
24478
25844
  return;
24479
25845
  }
24480
25846
  controller.enqueue(new Uint8Array(chunk));
24481
25847
  });
24482
25848
  input2.once("end", () => {
24483
- if (open6) {
24484
- open6 = false;
25849
+ if (open7) {
25850
+ open7 = false;
24485
25851
  controller.close();
24486
25852
  }
24487
25853
  });
24488
25854
  input2.once("error", (error61) => {
24489
- if (open6) {
24490
- open6 = false;
25855
+ if (open7) {
25856
+ open7 = false;
24491
25857
  controller.error(error61);
24492
25858
  }
24493
25859
  });
24494
25860
  },
24495
25861
  cancel() {
24496
- open6 = false;
25862
+ open7 = false;
24497
25863
  }
24498
25864
  });
24499
25865
  }
@@ -24512,14 +25878,14 @@ function writableAcpStream(output2) {
24512
25878
  }
24513
25879
  });
24514
25880
  }
24515
- async function probeAcp(agent, environment, defaultWorkspace, signal) {
25881
+ async function probeAcpReadiness(specification, agent, environment, defaultWorkspace, signal) {
24516
25882
  signal.throwIfAborted();
24517
25883
  const controller = new AbortController();
24518
25884
  let timedOut = false;
24519
25885
  const timeout = setTimeout(() => {
24520
25886
  timedOut = true;
24521
25887
  controller.abort(new Error("ACP probe timed out"));
24522
- }, ACP_PROBE_TIMEOUT_MILLISECONDS);
25888
+ }, specification.acpProbeTimeoutMilliseconds);
24523
25889
  const abort = () => controller.abort(signal.reason);
24524
25890
  signal.addEventListener("abort", abort, { once: true });
24525
25891
  if (signal.aborted) {
@@ -24556,13 +25922,13 @@ async function probeAcp(agent, environment, defaultWorkspace, signal) {
24556
25922
  }
24557
25923
  };
24558
25924
  stderr.on("data", consumeStderr);
24559
- const connection = createAcpClient(new DiscoveryAcpHandler()).connect(
24560
- ndJsonStream2(writableAcpStream(stdin), readableAcpStream(stdout))
24561
- );
25925
+ const connection = createAcpClient(
25926
+ new DiscoveryAcpHandler()
25927
+ ).connect(ndJsonStream2(writableAcpStream(stdin), readableAcpStream(stdout)));
24562
25928
  try {
24563
25929
  const initialized = await Promise.race([
24564
25930
  connection.agent.request(
24565
- methods3.agent.initialize,
25931
+ methods4.agent.initialize,
24566
25932
  {
24567
25933
  clientCapabilities: {},
24568
25934
  clientInfo: { name: "mobius", version: "0.0.3" },
@@ -24578,6 +25944,13 @@ async function probeAcp(agent, environment, defaultWorkspace, signal) {
24578
25944
  "ACP adapter selected an unsupported protocol version"
24579
25945
  );
24580
25946
  }
25947
+ await specification.verifyAcp(
25948
+ connection,
25949
+ initialized,
25950
+ defaultWorkspace,
25951
+ controller.signal
25952
+ );
25953
+ return normalizedVersion(initialized.agentInfo?.version ?? "");
24581
25954
  } catch (error61) {
24582
25955
  if (signal.aborted) {
24583
25956
  signal.throwIfAborted();
@@ -24592,6 +25965,13 @@ async function probeAcp(agent, environment, defaultWorkspace, signal) {
24592
25965
  if (error61 instanceof AgentProbeError) {
24593
25966
  throw error61;
24594
25967
  }
25968
+ if (error61 instanceof RequestError2 && error61.code === -32e3 && specification.authenticationCommand().length > 0) {
25969
+ throw new AgentProbeError(
25970
+ "authentication_required",
25971
+ "Agent authentication is required",
25972
+ { cause: error61 }
25973
+ );
25974
+ }
24595
25975
  throw new AgentProbeError(
24596
25976
  "acp_incompatible",
24597
25977
  "ACP adapter initialization failed",
@@ -24606,8 +25986,13 @@ async function probeAcp(agent, environment, defaultWorkspace, signal) {
24606
25986
  await stopProcessTree(child);
24607
25987
  }
24608
25988
  }
25989
+
25990
+ // src/agent-catalog/discover-agent.ts
24609
25991
  function probeFailure(specification, executableKind, error61) {
24610
25992
  if (error61 instanceof AgentProbeError) {
25993
+ if (error61.code === "authentication_required") {
25994
+ return new AuthenticationRequiredAgent(specification);
25995
+ }
24611
25996
  return error61.code === "acp_incompatible" ? new IncompatibleAdapter(specification) : new ProbeFailed(specification, error61.code, error61.message);
24612
25997
  }
24613
25998
  if (error61 instanceof ProcessExecutionError) {
@@ -24624,12 +26009,15 @@ function probeFailure(specification, executableKind, error61) {
24624
26009
  `${executableKind === "agent" ? "Agent" : "Adapter"} probe failed`
24625
26010
  );
24626
26011
  }
24627
- async function discoverSpecification(specification, options) {
24628
- options.signal.throwIfAborted();
26012
+ async function discoverAgent(specification, context) {
26013
+ context.signal.throwIfAborted();
24629
26014
  const [adapters, agents] = await Promise.all([
24630
- resolveAdapterExecutables(specification, options),
24631
- resolveAgentExecutables(specification, options)
26015
+ resolveAdapterExecutables(specification, context),
26016
+ resolveAgentExecutables(specification, context)
24632
26017
  ]);
26018
+ if (specification instanceof DirectAcpAgentDefinition && agents.length === 0) {
26019
+ return new MissingAgent(specification);
26020
+ }
24633
26021
  if (adapters.length === 0) {
24634
26022
  return new MissingAdapter(specification);
24635
26023
  }
@@ -24642,32 +26030,46 @@ async function discoverSpecification(specification, options) {
24642
26030
  try {
24643
26031
  agentVersion = await probeVersion(
24644
26032
  agent,
24645
- options.environment,
24646
- options.defaultWorkspace,
24647
- options.signal
26033
+ specification.agentVersionArguments,
26034
+ context.environment,
26035
+ context.defaultWorkspace,
26036
+ context.signal,
26037
+ specification.versionProbeTimeoutMilliseconds
24648
26038
  );
24649
26039
  } catch (error61) {
24650
- if (options.signal.aborted) {
24651
- options.signal.throwIfAborted();
26040
+ if (context.signal.aborted) {
26041
+ context.signal.throwIfAborted();
24652
26042
  }
24653
26043
  lastFailure = probeFailure(specification, "agent", error61);
24654
26044
  continue;
24655
26045
  }
24656
26046
  for (const adapter of adapters) {
26047
+ if (specification instanceof DirectAcpAgentDefinition && adapter.path !== agent.path) {
26048
+ continue;
26049
+ }
24657
26050
  let adapterVersion = "";
26051
+ let launchEnvironment;
24658
26052
  try {
24659
- adapterVersion = await probeVersion(
24660
- adapter,
24661
- {
24662
- ...options.environment,
24663
- [specification.adapterEnvironmentVariable]: agent.path
24664
- },
24665
- options.defaultWorkspace,
24666
- options.signal
26053
+ launchEnvironment = await specification.createLaunchEnvironment(
26054
+ agent,
26055
+ context
24667
26056
  );
26057
+ if (specification.adapterVersionArguments.length > 0) {
26058
+ adapterVersion = await probeVersion(
26059
+ adapter,
26060
+ specification.adapterVersionArguments,
26061
+ {
26062
+ ...context.environment,
26063
+ ...launchEnvironment
26064
+ },
26065
+ context.defaultWorkspace,
26066
+ context.signal,
26067
+ specification.versionProbeTimeoutMilliseconds
26068
+ );
26069
+ }
24668
26070
  } catch (error61) {
24669
- if (options.signal.aborted) {
24670
- options.signal.throwIfAborted();
26071
+ if (context.signal.aborted) {
26072
+ context.signal.throwIfAborted();
24671
26073
  }
24672
26074
  lastFailure = probeFailure(specification, "adapter", error61);
24673
26075
  continue;
@@ -24676,36 +26078,65 @@ async function discoverSpecification(specification, options) {
24676
26078
  specification.id,
24677
26079
  specification.label,
24678
26080
  adapter.path,
24679
- [],
24680
- { [specification.adapterEnvironmentVariable]: agent.path },
26081
+ specification.launchArguments,
26082
+ launchEnvironment,
24681
26083
  adapterVersion,
24682
26084
  agentVersion,
24683
26085
  adapter.identity,
24684
- agent.identity
26086
+ agent.identity,
26087
+ specification.promptTimeoutMilliseconds
24685
26088
  );
24686
26089
  try {
24687
- await probeAcp(
26090
+ const acpVersion = await probeAcpReadiness(
26091
+ specification,
24688
26092
  definition,
24689
- options.environment,
24690
- options.defaultWorkspace,
24691
- options.signal
26093
+ context.environment,
26094
+ context.defaultWorkspace,
26095
+ context.signal
26096
+ );
26097
+ const verifiedAdapterVersion = adapterVersion.length > 0 ? adapterVersion : acpVersion;
26098
+ if (verifiedAdapterVersion.length === 0) {
26099
+ throw new AgentProbeError(
26100
+ "acp_incompatible",
26101
+ "ACP adapter did not report a version"
26102
+ );
26103
+ }
26104
+ return new AvailableAgent(
26105
+ specification,
26106
+ new LocalAgentDefinition(
26107
+ specification.id,
26108
+ specification.label,
26109
+ adapter.path,
26110
+ specification.launchArguments,
26111
+ launchEnvironment,
26112
+ verifiedAdapterVersion,
26113
+ agentVersion,
26114
+ adapter.identity,
26115
+ agent.identity,
26116
+ specification.promptTimeoutMilliseconds
26117
+ )
24692
26118
  );
24693
- return new AvailableAgent(specification, definition);
24694
26119
  } catch (error61) {
24695
- if (options.signal.aborted) {
24696
- options.signal.throwIfAborted();
26120
+ if (context.signal.aborted) {
26121
+ context.signal.throwIfAborted();
24697
26122
  }
24698
- lastFailure = probeFailure(specification, "adapter", error61);
26123
+ const failure = probeFailure(specification, "adapter", error61);
26124
+ if (failure instanceof AuthenticationRequiredAgent) {
26125
+ return failure;
26126
+ }
26127
+ lastFailure = failure;
24699
26128
  }
24700
26129
  }
24701
26130
  }
24702
26131
  return lastFailure ?? new IncompatibleAdapter(specification);
24703
26132
  }
26133
+
26134
+ // src/agent-catalog/discover-local-agents.ts
24704
26135
  async function discoverLocalAgentInventory(options) {
24705
26136
  const specifications = options.specifications ?? supportedLocalAgentSpecifications();
24706
26137
  const discoveries = await Promise.all(
24707
26138
  specifications.map(
24708
- async (specification) => await discoverSpecification(specification, options)
26139
+ async (specification) => await discoverAgent(specification, options)
24709
26140
  )
24710
26141
  );
24711
26142
  let grantedAgents = /* @__PURE__ */ new Set();
@@ -24723,10 +26154,6 @@ async function discoverLocalAgentInventory(options) {
24723
26154
  );
24724
26155
  }
24725
26156
 
24726
- // src/network/environment-proxy.ts
24727
- import { EnvHttpProxyAgent } from "undici";
24728
- var environmentProxyDispatcher = new EnvHttpProxyAgent();
24729
-
24730
26157
  // src/pairing/pair-local-machine.ts
24731
26158
  var PAIRING_TIMEOUT_MILLISECONDS = 2e4;
24732
26159
  var PAIRING_CODE_PATTERN = /^[A-HJ-NP-Z2-9]{4}(?:-[A-HJ-NP-Z2-9]{4}){4}$/;
@@ -24752,7 +26179,7 @@ var PairingClientError = class extends Error {
24752
26179
  this.name = "PairingClientError";
24753
26180
  }
24754
26181
  };
24755
- function isRecord6(value) {
26182
+ function isRecord7(value) {
24756
26183
  return typeof value === "object" && value !== null && !Array.isArray(value);
24757
26184
  }
24758
26185
  function hasExactKeys(value, expectedKeys) {
@@ -24865,9 +26292,9 @@ function parseChannelArgument(arguments_) {
24865
26292
  async function resolveDefaultWorkspace(path2) {
24866
26293
  const requestedWorkspace = resolve3(path2);
24867
26294
  try {
24868
- await mkdir2(requestedWorkspace, { recursive: true, mode: 448 });
24869
- const defaultWorkspace = await realpath3(requestedWorkspace);
24870
- const metadata = await stat3(defaultWorkspace);
26295
+ await mkdir3(requestedWorkspace, { recursive: true, mode: 448 });
26296
+ const defaultWorkspace = await realpath5(requestedWorkspace);
26297
+ const metadata = await stat5(defaultWorkspace);
24871
26298
  if (!metadata.isDirectory()) {
24872
26299
  throw new PairingClientError(
24873
26300
  "invalid_workspace",
@@ -24905,9 +26332,9 @@ async function readJsonResponse(response) {
24905
26332
  }
24906
26333
  }
24907
26334
  function readRelayError(value) {
24908
- if (isRecord6(value)) {
26335
+ if (isRecord7(value)) {
24909
26336
  const error61 = value["error"];
24910
- if (isRecord6(error61)) {
26337
+ if (isRecord7(error61)) {
24911
26338
  const code = error61["code"];
24912
26339
  const message = error61["message"];
24913
26340
  if (typeof code === "string" && typeof message === "string") {
@@ -24921,7 +26348,7 @@ function readRelayError(value) {
24921
26348
  );
24922
26349
  }
24923
26350
  function decodeClaimResponse(value) {
24924
- if (!isRecord6(value) || !hasExactKeys(value, CLAIM_RESPONSE_KEYS)) {
26351
+ if (!isRecord7(value) || !hasExactKeys(value, CLAIM_RESPONSE_KEYS)) {
24925
26352
  throw new PairingClientError(
24926
26353
  "invalid_relay_response",
24927
26354
  "The relay returned an invalid pairing response"
@@ -24946,7 +26373,7 @@ async function claimPairing(options, defaultWorkspace, localAgents, installableA
24946
26373
  const endpoint = new URL("/api/pairings/claim", options.relayOrigin);
24947
26374
  let response;
24948
26375
  try {
24949
- response = await fetch(endpoint, {
26376
+ response = await fetch2(endpoint, {
24950
26377
  body: JSON.stringify({
24951
26378
  agents,
24952
26379
  installableAgents: installableAgents.map((agent) => ({
@@ -24980,14 +26407,14 @@ async function claimPairing(options, defaultWorkspace, localAgents, installableA
24980
26407
  return decodeClaimResponse(value);
24981
26408
  }
24982
26409
  async function persistConnection(channelId, relayOrigin, daemonToken, defaultWorkspace) {
24983
- const connectionsDirectory = join7(readStateDirectory(), "connections");
24984
- await mkdir2(connectionsDirectory, { mode: 448, recursive: true });
24985
- const connectionPath = join7(connectionsDirectory, `${channelId}.json`);
24986
- const temporaryPath = join7(
26410
+ const connectionsDirectory = join13(readStateDirectory(), "connections");
26411
+ await mkdir3(connectionsDirectory, { mode: 448, recursive: true });
26412
+ const connectionPath = join13(connectionsDirectory, `${channelId}.json`);
26413
+ const temporaryPath = join13(
24987
26414
  connectionsDirectory,
24988
26415
  `.${channelId}.${randomUUID()}.tmp`
24989
26416
  );
24990
- await writeFile(
26417
+ await writeFile2(
24991
26418
  temporaryPath,
24992
26419
  `${JSON.stringify(
24993
26420
  {
@@ -25002,11 +26429,11 @@ async function persistConnection(channelId, relayOrigin, daemonToken, defaultWor
25002
26429
  `,
25003
26430
  { flag: "wx", mode: 384 }
25004
26431
  );
25005
- await rename2(temporaryPath, connectionPath);
26432
+ await rename3(temporaryPath, connectionPath);
25006
26433
  return connectionPath;
25007
26434
  }
25008
26435
  function decodeSavedConnection(value, expectedChannelId) {
25009
- if (!isRecord6(value) || !hasExactKeys(value, SAVED_CONNECTION_KEYS)) {
26436
+ if (!isRecord7(value) || !hasExactKeys(value, SAVED_CONNECTION_KEYS)) {
25010
26437
  throw new PairingClientError(
25011
26438
  "invalid_connection",
25012
26439
  "The saved connection is invalid"
@@ -25030,13 +26457,13 @@ function decodeSavedConnection(value, expectedChannelId) {
25030
26457
  };
25031
26458
  }
25032
26459
  async function readSavedConnection(channelId) {
25033
- const connectionPath = join7(
26460
+ const connectionPath = join13(
25034
26461
  readStateDirectory(),
25035
26462
  "connections",
25036
26463
  `${channelId}.json`
25037
26464
  );
25038
26465
  let encoded = "";
25039
- const handle = await open4(connectionPath, "r");
26466
+ const handle = await open6(connectionPath, "r");
25040
26467
  try {
25041
26468
  const metadata = await handle.stat();
25042
26469
  if (!metadata.isFile() || metadata.size > MAX_CONNECTION_FILE_LENGTH) {
@@ -25085,7 +26512,7 @@ function buildPairedDaemon(connection, connectionPath, inventory) {
25085
26512
  );
25086
26513
  relayUrl.protocol = relayUrl.protocol === "https:" ? "wss:" : "ws:";
25087
26514
  relayUrl.searchParams.set("token", connection.daemonToken);
25088
- const auditDatabasePath = join7(
26515
+ const auditDatabasePath = join13(
25089
26516
  readStateDirectory(),
25090
26517
  "audit",
25091
26518
  `${connection.channelId}.sqlite`
@@ -25144,7 +26571,7 @@ async function pairLocalMachine(arguments_, signal = new AbortController().signa
25144
26571
  }
25145
26572
  async function resumeLocalMachine(arguments_, signal = new AbortController().signal) {
25146
26573
  const channelId = parseChannelArgument(arguments_);
25147
- const connectionPath = join7(
26574
+ const connectionPath = join13(
25148
26575
  readStateDirectory(),
25149
26576
  "connections",
25150
26577
  `${channelId}.json`
@@ -25163,7 +26590,7 @@ import { basename as basename3 } from "node:path";
25163
26590
  import { WebSocket as WebSocket2 } from "undici";
25164
26591
 
25165
26592
  // src/agent-catalog/publish-agent-catalog.ts
25166
- import { fetch as fetch2 } from "undici";
26593
+ import { fetch as fetch3 } from "undici";
25167
26594
  var CATALOG_UPDATE_TIMEOUT_MILLISECONDS = 2e4;
25168
26595
  var AgentCatalogPublishError = class extends Error {
25169
26596
  code = "agent_catalog_update_failed";
@@ -25190,7 +26617,7 @@ async function publishAgentCatalog(config2, signal) {
25190
26617
  let response;
25191
26618
  const catalog = config2.catalog.read();
25192
26619
  try {
25193
- response = await fetch2(catalogEndpoint(config2.relayUrl), {
26620
+ response = await fetch3(catalogEndpoint(config2.relayUrl), {
25194
26621
  body: JSON.stringify({
25195
26622
  agents: catalog.agents.map((agent) => ({
25196
26623
  id: agent.id,
@@ -25596,7 +27023,7 @@ var InstalledAutomaticAdapter = class {
25596
27023
  }
25597
27024
  };
25598
27025
  function shouldProvisionAdapter(unavailable, options) {
25599
- return AUTOMATIC_ADAPTER_FAILURE_CODES.has(unavailable.code) && options.environment[unavailable.specification.adapterOverrideVariable] === void 0 && unavailable.specification.supportsInstallation(
27026
+ return unavailable.specification instanceof BridgedAcpAgentDefinition && AUTOMATIC_ADAPTER_FAILURE_CODES.has(unavailable.code) && options.environment[unavailable.specification.adapterOverrideVariable] === void 0 && unavailable.specification.supportsInstallation(
25600
27027
  options.platform ?? process.platform,
25601
27028
  options.architecture ?? process.arch
25602
27029
  );
@@ -25640,6 +27067,10 @@ var AutomaticAdapterProvisioner = class {
25640
27067
  for (const unavailable of candidates) {
25641
27068
  signal.throwIfAborted();
25642
27069
  const specification = unavailable.specification;
27070
+ if (!(specification instanceof BridgedAcpAgentDefinition)) {
27071
+ attempts.push(null);
27072
+ continue;
27073
+ }
25643
27074
  const verifiedAgent = await findVerifiedAgentExecutable(
25644
27075
  specification,
25645
27076
  discoveryOptions(
@@ -25719,252 +27150,59 @@ var AutomaticAdapterProvisioner = class {
25719
27150
  this.#options,
25720
27151
  verificationEnvironment,
25721
27152
  signal,
25722
- this.#specifications
25723
- )
25724
- );
25725
- }
25726
- this.#options.catalog.transition(
25727
- inventory.readyAgents(),
25728
- inventory.installable
25729
- );
25730
- for (const attempt of installed) {
25731
- const available = inventory.available.find(
25732
- (candidate) => candidate instanceof AvailableAgent && candidate.specification.id === attempt.specification.id
25733
- );
25734
- if (available === void 0) {
25735
- const unavailable = inventory.unavailable.find(
25736
- (candidate) => candidate.specification.id === attempt.specification.id
25737
- );
25738
- this.#options.audit.record(
25739
- "agent_adapter_auto_install_verification_failed",
25740
- attempt.requestId,
25741
- attempt.specification.id,
25742
- { code: unavailable?.code ?? "agent_verification_failed" }
25743
- );
25744
- continue;
25745
- }
25746
- this.#options.audit.record(
25747
- "agent_adapter_auto_install_verified",
25748
- attempt.requestId,
25749
- attempt.specification.id,
25750
- {
25751
- adapterVersion: available.agent.adapterVersion,
25752
- agentVersion: available.agent.agentVersion
25753
- }
25754
- );
25755
- process.stdout.write(
25756
- `${attempt.specification.label} ACP integration is ready.
25757
- `
25758
- );
25759
- }
25760
- return inventory;
25761
- };
25762
- };
25763
-
25764
- // src/agent-installation/fixed-installation-executor.ts
25765
- import { realpathSync as realpathSync2, statSync as statSync2 } from "node:fs";
25766
- import { resolve as resolve4 } from "node:path";
25767
-
25768
- // src/agent-installation/fixed-agent-install-recipes.ts
25769
- import { mkdir as mkdir3, mkdtemp as mkdtemp2, rm as rm2 } from "node:fs/promises";
25770
- import { join as join8 } from "node:path";
25771
-
25772
- // src/agent-installation/verified-download.ts
25773
- import { createHash } from "node:crypto";
25774
- import { open as open5, unlink } from "node:fs/promises";
25775
- import { fetch as fetch3 } from "undici";
25776
- var MAX_REDIRECTS = 4;
25777
- var REDIRECT_STATUSES = /* @__PURE__ */ new Set([301, 302, 303, 307, 308]);
25778
- var InstallerDownloadError = class extends Error {
25779
- code;
25780
- constructor(code, message, options = {}) {
25781
- super(message, options);
25782
- this.code = code;
25783
- this.name = "InstallerDownloadError";
25784
- }
25785
- };
25786
- var VerifiedDownload = class {
25787
- bytes;
25788
- sha256;
25789
- url;
25790
- constructor(url2, bytes, sha256) {
25791
- this.bytes = bytes;
25792
- this.sha256 = sha256;
25793
- this.url = url2;
25794
- }
25795
- };
25796
- var UndiciInstallerDownloadTransport = class {
25797
- get = async (url2, signal) => await fetch3(url2, {
25798
- dispatcher: environmentProxyDispatcher,
25799
- headers: {
25800
- accept: "text/plain, application/octet-stream;q=0.9",
25801
- "user-agent": "Mobius-Agent-Installer/0.0.3"
25802
- },
25803
- method: "GET",
25804
- redirect: "manual",
25805
- signal
25806
- });
25807
- };
25808
- function validateUrl(url2, allowedHosts) {
25809
- if (url2.protocol !== "https:" || url2.username.length > 0 || url2.password.length > 0 || url2.port.length > 0 || !allowedHosts.has(url2.hostname)) {
25810
- throw new InstallerDownloadError(
25811
- "installer_host_not_allowed",
25812
- "The installer download target is not allowed"
25813
- );
25814
- }
25815
- }
25816
- async function fetchInstaller(options, signal, transport) {
25817
- let url2 = new URL(options.url);
25818
- for (let redirectCount = 0; redirectCount <= MAX_REDIRECTS; redirectCount += 1) {
25819
- validateUrl(url2, options.allowedHosts);
25820
- const response = await transport.get(url2, signal);
25821
- if (!REDIRECT_STATUSES.has(response.status)) {
25822
- return { response, url: url2 };
25823
- }
25824
- await response.body?.cancel();
25825
- const location = response.headers.get("location");
25826
- if (location === null || redirectCount === MAX_REDIRECTS) {
25827
- throw new InstallerDownloadError(
25828
- "installer_redirect_invalid",
25829
- "The installer returned an invalid redirect"
25830
- );
25831
- }
25832
- let redirected;
25833
- try {
25834
- redirected = new URL(location, url2);
25835
- } catch (error61) {
25836
- throw new InstallerDownloadError(
25837
- "installer_redirect_invalid",
25838
- "The installer returned an invalid redirect",
25839
- { cause: error61 }
25840
- );
25841
- }
25842
- try {
25843
- validateUrl(redirected, options.allowedHosts);
25844
- } catch (error61) {
25845
- throw new InstallerDownloadError(
25846
- "installer_redirect_not_allowed",
25847
- "The installer redirect left the approved host allowlist",
25848
- { cause: error61 }
25849
- );
25850
- }
25851
- url2 = redirected;
25852
- }
25853
- throw new InstallerDownloadError(
25854
- "installer_redirect_invalid",
25855
- "The installer returned too many redirects"
25856
- );
25857
- }
25858
- async function writeCompleteChunk(handle, chunk) {
25859
- let offset = 0;
25860
- while (offset < chunk.byteLength) {
25861
- const written = await handle.write(
25862
- chunk,
25863
- offset,
25864
- chunk.byteLength - offset
25865
- );
25866
- if (written.bytesWritten < 1) {
25867
- throw new InstallerDownloadError(
25868
- "installer_write_failed",
25869
- "The verified installer could not be stored"
27153
+ this.#specifications
27154
+ )
25870
27155
  );
25871
27156
  }
25872
- offset += written.bytesWritten;
25873
- }
25874
- }
25875
- async function downloadVerifiedFile(options, transport = new UndiciInstallerDownloadTransport()) {
25876
- options.signal.throwIfAborted();
25877
- const timeoutSignal = AbortSignal.timeout(options.timeoutMilliseconds);
25878
- const signal = AbortSignal.any([options.signal, timeoutSignal]);
25879
- let handle = null;
25880
- let responseBody = null;
25881
- try {
25882
- const fetched = await fetchInstaller(options, signal, transport);
25883
- responseBody = fetched.response.body;
25884
- if (!fetched.response.ok || fetched.response.body === null) {
25885
- throw new InstallerDownloadError(
25886
- "installer_download_failed",
25887
- "The approved installer could not be downloaded"
27157
+ this.#options.catalog.transition(
27158
+ inventory.readyAgents(),
27159
+ inventory.installable
27160
+ );
27161
+ for (const attempt of installed) {
27162
+ const available = inventory.available.find(
27163
+ (candidate) => candidate instanceof AvailableAgent && candidate.specification.id === attempt.specification.id
25888
27164
  );
25889
- }
25890
- const contentLength = fetched.response.headers.get("content-length");
25891
- if (contentLength !== null) {
25892
- const declaredLength = Number(contentLength);
25893
- if (!Number.isSafeInteger(declaredLength) || declaredLength < 1 || declaredLength > options.maximumBytes) {
25894
- throw new InstallerDownloadError(
25895
- "installer_size_invalid",
25896
- "The installer size is outside the approved limit"
27165
+ if (available === void 0) {
27166
+ const unavailable = inventory.unavailable.find(
27167
+ (candidate) => candidate.specification.id === attempt.specification.id
27168
+ );
27169
+ this.#options.audit.record(
27170
+ "agent_adapter_auto_install_verification_failed",
27171
+ attempt.requestId,
27172
+ attempt.specification.id,
27173
+ { code: unavailable?.code ?? "agent_verification_failed" }
25897
27174
  );
27175
+ continue;
25898
27176
  }
25899
- }
25900
- handle = await open5(options.destination, "wx", 384);
25901
- const digest = createHash("sha256");
25902
- const reader = fetched.response.body.getReader();
25903
- let bytes = 0;
25904
- try {
25905
- while (true) {
25906
- signal.throwIfAborted();
25907
- const chunk = await reader.read();
25908
- if (chunk.done) {
25909
- break;
25910
- }
25911
- bytes += chunk.value.byteLength;
25912
- if (bytes > options.maximumBytes) {
25913
- throw new InstallerDownloadError(
25914
- "installer_size_invalid",
25915
- "The installer exceeded the approved size limit"
25916
- );
27177
+ this.#options.audit.record(
27178
+ "agent_adapter_auto_install_verified",
27179
+ attempt.requestId,
27180
+ attempt.specification.id,
27181
+ {
27182
+ adapterVersion: available.agent.adapterVersion,
27183
+ agentVersion: available.agent.agentVersion
25917
27184
  }
25918
- digest.update(chunk.value);
25919
- await writeCompleteChunk(handle, chunk.value);
25920
- }
25921
- } finally {
25922
- await reader.cancel().catch(() => void 0);
25923
- reader.releaseLock();
25924
- }
25925
- if (bytes === 0) {
25926
- throw new InstallerDownloadError(
25927
- "installer_verification_failed",
25928
- "The downloaded installer is empty"
25929
27185
  );
25930
- }
25931
- await handle.sync();
25932
- await handle.close();
25933
- handle = null;
25934
- return new VerifiedDownload(fetched.url, bytes, digest.digest("hex"));
25935
- } catch (error61) {
25936
- if (handle !== null) {
25937
- await handle.close().catch(() => void 0);
25938
- }
25939
- await unlink(options.destination).catch(() => void 0);
25940
- if (options.signal.aborted) {
25941
- options.signal.throwIfAborted();
25942
- }
25943
- if (timeoutSignal.aborted) {
25944
- throw new InstallerDownloadError(
25945
- "installer_download_timeout",
25946
- "The installer download timed out",
25947
- { cause: error61 }
27186
+ process.stdout.write(
27187
+ `${attempt.specification.label} ACP integration is ready.
27188
+ `
25948
27189
  );
25949
27190
  }
25950
- if (error61 instanceof InstallerDownloadError) {
25951
- throw error61;
25952
- }
25953
- throw new InstallerDownloadError(
25954
- "installer_download_failed",
25955
- "The approved installer could not be downloaded",
25956
- { cause: error61 }
25957
- );
25958
- } finally {
25959
- await responseBody?.cancel().catch(() => void 0);
25960
- }
25961
- }
27191
+ return inventory;
27192
+ };
27193
+ };
27194
+
27195
+ // src/agent-installation/fixed-installation-executor.ts
27196
+ import { realpathSync as realpathSync2, statSync as statSync2 } from "node:fs";
27197
+ import { resolve as resolve4 } from "node:path";
25962
27198
 
25963
27199
  // src/agent-installation/fixed-agent-install-recipes.ts
27200
+ import { mkdir as mkdir4, mkdtemp as mkdtemp3, rm as rm3 } from "node:fs/promises";
27201
+ import { join as join14 } from "node:path";
25964
27202
  var INSTALLER_DOWNLOAD_LIMIT_BYTES = 1024 * 1024;
25965
27203
  var INSTALLER_DOWNLOAD_TIMEOUT_MILLISECONDS = 6e4;
25966
27204
  var AGENT_INSTALL_TIMEOUT_MILLISECONDS = 5 * 60 * 1e3;
25967
- var MINIMAL_PATH = "/usr/bin:/bin";
27205
+ var MINIMAL_PATH2 = "/usr/bin:/bin";
25968
27206
  var FixedAgentInstallRecipe = class {
25969
27207
  assertSupportedPlatform = () => {
25970
27208
  if (process.platform !== "darwin" && process.platform !== "linux" || process.arch !== "arm64" && process.arch !== "x64") {
@@ -25991,22 +27229,22 @@ var CodexInstallRecipe = class extends FixedAgentInstallRecipe {
25991
27229
  releaseChannel = "latest";
25992
27230
  install = async (options) => {
25993
27231
  this.assertSupportedPlatform();
25994
- const root = join8(options.stateDirectory, "agents", this.id);
25995
- const temporaryRoot = join8(options.stateDirectory, "temporary");
27232
+ const root = join14(options.stateDirectory, "agents", this.id);
27233
+ const temporaryRoot = join14(options.stateDirectory, "temporary");
25996
27234
  await Promise.all([
25997
- mkdir3(root, { mode: 448, recursive: true }),
25998
- mkdir3(temporaryRoot, { mode: 448, recursive: true })
27235
+ mkdir4(root, { mode: 448, recursive: true }),
27236
+ mkdir4(temporaryRoot, { mode: 448, recursive: true })
25999
27237
  ]);
26000
- const temporaryDirectory = await mkdtemp2(
26001
- join8(temporaryRoot, ".codex-install-")
27238
+ const temporaryDirectory = await mkdtemp3(
27239
+ join14(temporaryRoot, ".codex-install-")
26002
27240
  );
26003
- const installerPath = join8(temporaryDirectory, "install.sh");
26004
- const installDirectory = join8(root, "bin");
26005
- const codexHome = join8(root, "home");
27241
+ const installerPath = join14(temporaryDirectory, "install.sh");
27242
+ const installDirectory = join14(root, "bin");
27243
+ const codexHome = join14(root, "home");
26006
27244
  try {
26007
27245
  await Promise.all([
26008
- mkdir3(installDirectory, { mode: 448, recursive: true }),
26009
- mkdir3(codexHome, { mode: 448, recursive: true })
27246
+ mkdir4(installDirectory, { mode: 448, recursive: true }),
27247
+ mkdir4(codexHome, { mode: 448, recursive: true })
26010
27248
  ]);
26011
27249
  await options.report("downloading");
26012
27250
  const download = await downloadVerifiedFile({
@@ -26039,14 +27277,14 @@ var CodexInstallRecipe = class extends FixedAgentInstallRecipe {
26039
27277
  CODEX_NON_INTERACTIVE: "1",
26040
27278
  CODEX_RELEASE: this.releaseChannel,
26041
27279
  HOME: codexHome,
26042
- PATH: MINIMAL_PATH
27280
+ PATH: MINIMAL_PATH2
26043
27281
  },
26044
27282
  outputLimitBytes: 64 * 1024,
26045
27283
  signal: options.signal,
26046
27284
  timeoutMilliseconds: AGENT_INSTALL_TIMEOUT_MILLISECONDS
26047
27285
  });
26048
27286
  return await this.requireInstalledExecutable(
26049
- join8(installDirectory, "codex")
27287
+ join14(installDirectory, "codex")
26050
27288
  );
26051
27289
  } catch (error61) {
26052
27290
  if (options.signal.aborted) {
@@ -26060,7 +27298,7 @@ var CodexInstallRecipe = class extends FixedAgentInstallRecipe {
26060
27298
  "The fixed Codex installation recipe failed"
26061
27299
  );
26062
27300
  } finally {
26063
- await rm2(temporaryDirectory, { force: true, recursive: true });
27301
+ await rm3(temporaryDirectory, { force: true, recursive: true });
26064
27302
  }
26065
27303
  };
26066
27304
  };
@@ -26070,17 +27308,17 @@ var ClaudeCodeInstallRecipe = class extends FixedAgentInstallRecipe {
26070
27308
  releaseChannel = "stable";
26071
27309
  install = async (options) => {
26072
27310
  this.assertSupportedPlatform();
26073
- const root = join8(options.stateDirectory, "agents", this.id);
26074
- const managedHome = join8(root, "home");
26075
- const temporaryRoot = join8(options.stateDirectory, "temporary");
27311
+ const root = join14(options.stateDirectory, "agents", this.id);
27312
+ const managedHome = join14(root, "home");
27313
+ const temporaryRoot = join14(options.stateDirectory, "temporary");
26076
27314
  await Promise.all([
26077
- mkdir3(managedHome, { mode: 448, recursive: true }),
26078
- mkdir3(temporaryRoot, { mode: 448, recursive: true })
27315
+ mkdir4(managedHome, { mode: 448, recursive: true }),
27316
+ mkdir4(temporaryRoot, { mode: 448, recursive: true })
26079
27317
  ]);
26080
- const temporaryDirectory = await mkdtemp2(
26081
- join8(temporaryRoot, ".claude-install-")
27318
+ const temporaryDirectory = await mkdtemp3(
27319
+ join14(temporaryRoot, ".claude-install-")
26082
27320
  );
26083
- const installerPath = join8(temporaryDirectory, "install.sh");
27321
+ const installerPath = join14(temporaryDirectory, "install.sh");
26084
27322
  try {
26085
27323
  await options.report("downloading");
26086
27324
  const download = await downloadVerifiedFile({
@@ -26109,7 +27347,7 @@ var ClaudeCodeInstallRecipe = class extends FixedAgentInstallRecipe {
26109
27347
  cwd: temporaryDirectory,
26110
27348
  environment: {
26111
27349
  HOME: managedHome,
26112
- PATH: MINIMAL_PATH,
27350
+ PATH: MINIMAL_PATH2,
26113
27351
  SHELL: "/bin/bash"
26114
27352
  },
26115
27353
  outputLimitBytes: 64 * 1024,
@@ -26117,7 +27355,7 @@ var ClaudeCodeInstallRecipe = class extends FixedAgentInstallRecipe {
26117
27355
  timeoutMilliseconds: AGENT_INSTALL_TIMEOUT_MILLISECONDS
26118
27356
  });
26119
27357
  return await this.requireInstalledExecutable(
26120
- join8(managedHome, ".local", "bin", "claude")
27358
+ join14(managedHome, ".local", "bin", "claude")
26121
27359
  );
26122
27360
  } catch (error61) {
26123
27361
  if (options.signal.aborted) {
@@ -26131,14 +27369,236 @@ var ClaudeCodeInstallRecipe = class extends FixedAgentInstallRecipe {
26131
27369
  "The fixed Claude Code installation recipe failed"
26132
27370
  );
26133
27371
  } finally {
26134
- await rm2(temporaryDirectory, { force: true, recursive: true });
27372
+ await rm3(temporaryDirectory, { force: true, recursive: true });
27373
+ }
27374
+ };
27375
+ };
27376
+ var PiInstallRecipe = class extends FixedAgentInstallRecipe {
27377
+ #npmInstaller;
27378
+ id = "pi";
27379
+ label = "Pi";
27380
+ releaseChannel = PI_AGENT_PACKAGE.version;
27381
+ constructor(npmInstaller = new ManagedNpmPackageInstaller()) {
27382
+ super();
27383
+ this.#npmInstaller = npmInstaller;
27384
+ }
27385
+ install = async (options) => {
27386
+ this.assertSupportedPlatform();
27387
+ try {
27388
+ await options.report("downloading");
27389
+ await options.report("verifying");
27390
+ await options.report("installing_agent");
27391
+ const executable = await this.#npmInstaller.install(
27392
+ join14(
27393
+ options.stateDirectory,
27394
+ "agents",
27395
+ this.id,
27396
+ PI_AGENT_PACKAGE.version
27397
+ ),
27398
+ PI_AGENT_PACKAGE,
27399
+ options.environment,
27400
+ options.signal
27401
+ );
27402
+ options.audit.record(
27403
+ "agent_npm_package_verified",
27404
+ options.requestId,
27405
+ this.id,
27406
+ {
27407
+ integrity: PI_AGENT_PACKAGE.integrity,
27408
+ package: PI_AGENT_PACKAGE.packageName,
27409
+ version: PI_AGENT_PACKAGE.version
27410
+ }
27411
+ );
27412
+ return executable;
27413
+ } catch (error61) {
27414
+ if (options.signal.aborted) {
27415
+ options.signal.throwIfAborted();
27416
+ }
27417
+ if (error61 instanceof ManagedNpmPackageError) {
27418
+ if (error61.code === "managed_package_verification_failed") {
27419
+ throw new InstallationManagerError(
27420
+ "agent_verification_failed",
27421
+ "The managed Pi package did not match its pinned artifact",
27422
+ { cause: error61 }
27423
+ );
27424
+ }
27425
+ if (error61.code === "managed_package_publish_failed") {
27426
+ throw new InstallationManagerError(
27427
+ "agent_publish_failed",
27428
+ "The managed Pi package could not be published",
27429
+ { cause: error61 }
27430
+ );
27431
+ }
27432
+ throw new InstallationManagerError(error61.code, error61.message, {
27433
+ cause: error61
27434
+ });
27435
+ }
27436
+ if (error61 instanceof InstallationManagerError) {
27437
+ throw error61;
27438
+ }
27439
+ throw new InstallationManagerError(
27440
+ "agent_install_failed",
27441
+ "The fixed Pi installation recipe failed",
27442
+ { cause: error61 }
27443
+ );
27444
+ }
27445
+ };
27446
+ };
27447
+ var DeepSeekHarnessInstallRecipe = class extends FixedAgentInstallRecipe {
27448
+ #npmInstaller;
27449
+ id = "deepseek-harness";
27450
+ label = "DeepSeek Harness";
27451
+ releaseChannel = DEEPSEEK_HARNESS_PACKAGE.version;
27452
+ constructor(npmInstaller = new ManagedNpmPackageInstaller()) {
27453
+ super();
27454
+ this.#npmInstaller = npmInstaller;
27455
+ }
27456
+ install = async (options) => {
27457
+ this.assertSupportedPlatform();
27458
+ try {
27459
+ const managedHome = join14(
27460
+ options.stateDirectory,
27461
+ "agents",
27462
+ this.id,
27463
+ "home"
27464
+ );
27465
+ await mkdir4(managedHome, { mode: 448, recursive: true });
27466
+ await options.report("downloading");
27467
+ await options.report("verifying");
27468
+ await options.report("installing_agent");
27469
+ const executable = await this.#npmInstaller.install(
27470
+ join14(
27471
+ options.stateDirectory,
27472
+ "agents",
27473
+ this.id,
27474
+ DEEPSEEK_HARNESS_PACKAGE.version
27475
+ ),
27476
+ DEEPSEEK_HARNESS_PACKAGE,
27477
+ options.environment,
27478
+ options.signal
27479
+ );
27480
+ options.audit.record(
27481
+ "agent_npm_package_verified",
27482
+ options.requestId,
27483
+ this.id,
27484
+ {
27485
+ integrity: DEEPSEEK_HARNESS_PACKAGE.integrity,
27486
+ package: DEEPSEEK_HARNESS_PACKAGE.packageName,
27487
+ version: DEEPSEEK_HARNESS_PACKAGE.version
27488
+ }
27489
+ );
27490
+ return executable;
27491
+ } catch (error61) {
27492
+ if (options.signal.aborted) {
27493
+ options.signal.throwIfAborted();
27494
+ }
27495
+ if (error61 instanceof ManagedNpmPackageError) {
27496
+ if (error61.code === "managed_package_verification_failed") {
27497
+ throw new InstallationManagerError(
27498
+ "agent_verification_failed",
27499
+ "The managed DeepSeek Harness package did not match its pinned artifact",
27500
+ { cause: error61 }
27501
+ );
27502
+ }
27503
+ if (error61.code === "managed_package_publish_failed") {
27504
+ throw new InstallationManagerError(
27505
+ "agent_publish_failed",
27506
+ "The managed DeepSeek Harness package could not be published",
27507
+ { cause: error61 }
27508
+ );
27509
+ }
27510
+ throw new InstallationManagerError(error61.code, error61.message, {
27511
+ cause: error61
27512
+ });
27513
+ }
27514
+ if (error61 instanceof InstallationManagerError) {
27515
+ throw error61;
27516
+ }
27517
+ throw new InstallationManagerError(
27518
+ "agent_install_failed",
27519
+ "The fixed DeepSeek Harness installation recipe failed",
27520
+ { cause: error61 }
27521
+ );
27522
+ }
27523
+ };
27524
+ };
27525
+ var OpenCodeInstallRecipe = class extends FixedAgentInstallRecipe {
27526
+ #archiveInstaller;
27527
+ id = "opencode";
27528
+ label = "OpenCode";
27529
+ releaseChannel = OPENCODE_MANAGED_VERSION;
27530
+ constructor(archiveInstaller = new ManagedAgentArchiveInstaller()) {
27531
+ super();
27532
+ this.#archiveInstaller = archiveInstaller;
27533
+ }
27534
+ install = async (options) => {
27535
+ this.assertSupportedPlatform();
27536
+ const definition = openCodeManagedArchive(process.platform, process.arch);
27537
+ try {
27538
+ await options.report("downloading");
27539
+ await options.report("verifying");
27540
+ await options.report("installing_agent");
27541
+ const executable = await this.#archiveInstaller.install(
27542
+ join14(
27543
+ options.stateDirectory,
27544
+ "agents",
27545
+ this.id,
27546
+ OPENCODE_MANAGED_VERSION
27547
+ ),
27548
+ definition,
27549
+ options.signal
27550
+ );
27551
+ options.audit.record(
27552
+ "agent_archive_verified",
27553
+ options.requestId,
27554
+ this.id,
27555
+ {
27556
+ sha256: definition.archiveSha256,
27557
+ version: definition.version
27558
+ }
27559
+ );
27560
+ return executable;
27561
+ } catch (error61) {
27562
+ if (options.signal.aborted) {
27563
+ options.signal.throwIfAborted();
27564
+ }
27565
+ if (error61 instanceof ManagedAgentArchiveError) {
27566
+ if (error61.code === "managed_archive_verification_failed") {
27567
+ throw new InstallationManagerError(
27568
+ "agent_verification_failed",
27569
+ "The managed OpenCode archive did not match its pinned artifact",
27570
+ { cause: error61 }
27571
+ );
27572
+ }
27573
+ if (error61.code === "managed_archive_publish_failed") {
27574
+ throw new InstallationManagerError(
27575
+ "agent_publish_failed",
27576
+ "The managed OpenCode archive could not be published",
27577
+ { cause: error61 }
27578
+ );
27579
+ }
27580
+ throw new InstallationManagerError(error61.code, error61.message, {
27581
+ cause: error61
27582
+ });
27583
+ }
27584
+ if (error61 instanceof InstallationManagerError) {
27585
+ throw error61;
27586
+ }
27587
+ throw new InstallationManagerError(
27588
+ "agent_install_failed",
27589
+ "The fixed OpenCode installation recipe failed",
27590
+ { cause: error61 }
27591
+ );
26135
27592
  }
26136
27593
  };
26137
27594
  };
26138
27595
  function fixedAgentInstallRecipes() {
26139
27596
  return Object.freeze([
26140
27597
  new CodexInstallRecipe(),
26141
- new ClaudeCodeInstallRecipe()
27598
+ new ClaudeCodeInstallRecipe(),
27599
+ new PiInstallRecipe(),
27600
+ new DeepSeekHarnessInstallRecipe(),
27601
+ new OpenCodeInstallRecipe()
26142
27602
  ]);
26143
27603
  }
26144
27604
 
@@ -26268,6 +27728,7 @@ var FixedInstallationExecutor = class {
26268
27728
  if (agent === null) {
26269
27729
  agent = await recipe.install({
26270
27730
  audit: this.#audit,
27731
+ environment: this.#environment,
26271
27732
  report,
26272
27733
  requestId,
26273
27734
  signal,
@@ -26275,12 +27736,15 @@ var FixedInstallationExecutor = class {
26275
27736
  });
26276
27737
  installedAgent = true;
26277
27738
  }
26278
- let adapter = await resolveAdapterExecutable(
26279
- specification,
26280
- discoveryOptions2
26281
- );
27739
+ let adapter = specification instanceof DirectAcpAgentDefinition ? agent : await resolveAdapterExecutable(specification, discoveryOptions2);
26282
27740
  let installedAdapter = false;
26283
27741
  if (adapter === null) {
27742
+ if (!(specification instanceof BridgedAcpAgentDefinition)) {
27743
+ throw new InstallationManagerError(
27744
+ "agent_verification_failed",
27745
+ "The direct Agent executable is unavailable"
27746
+ );
27747
+ }
26284
27748
  await report("installing_adapter");
26285
27749
  adapter = await this.#adapterInstaller.install(specification, signal);
26286
27750
  installedAdapter = true;
@@ -26337,7 +27801,7 @@ var FixedInstallationExecutor = class {
26337
27801
  "The complete Agent ACP path did not pass verification"
26338
27802
  );
26339
27803
  }
26340
- if (!installedAdapter && requiresAdapterReplacement(unavailable.code)) {
27804
+ if (!installedAdapter && specification instanceof BridgedAcpAgentDefinition && requiresAdapterReplacement(unavailable.code)) {
26341
27805
  await report("installing_adapter");
26342
27806
  adapter = await this.#adapterInstaller.install(specification, signal);
26343
27807
  installedAdapter = true;
@@ -26349,12 +27813,16 @@ var FixedInstallationExecutor = class {
26349
27813
  if (!installedAgent && (requiresAgentReplacement(unavailable.code) || unavailable.code === "acp_incompatible")) {
26350
27814
  agent = await recipe.install({
26351
27815
  audit: this.#audit,
27816
+ environment: this.#environment,
26352
27817
  report,
26353
27818
  requestId,
26354
27819
  signal,
26355
27820
  stateDirectory: this.#stateDirectory
26356
27821
  });
26357
27822
  installedAgent = true;
27823
+ if (specification instanceof DirectAcpAgentDefinition) {
27824
+ adapter = agent;
27825
+ }
26358
27826
  continue;
26359
27827
  }
26360
27828
  throw new InstallationManagerError(
@@ -26407,15 +27875,15 @@ Mobius Web requested installation of ${label} (${requestId}). Allow this fixed u
26407
27875
  };
26408
27876
 
26409
27877
  // src/authorization/workspace-directory.ts
26410
- import { readdir, realpath as realpath4, stat as stat4 } from "node:fs/promises";
27878
+ import { readdir, realpath as realpath6, stat as stat6 } from "node:fs/promises";
26411
27879
  import { homedir as homedir2 } from "node:os";
26412
27880
  import {
26413
27881
  basename as basename2,
26414
- dirname as dirname4,
26415
- isAbsolute as isAbsolute2,
26416
- join as join9,
26417
- normalize,
26418
- relative as relative2
27882
+ dirname as dirname5,
27883
+ isAbsolute as isAbsolute5,
27884
+ join as join15,
27885
+ normalize as normalize2,
27886
+ relative as relative3
26419
27887
  } from "node:path";
26420
27888
  var WorkspaceDirectoryListing = class {
26421
27889
  directoryId;
@@ -26443,7 +27911,7 @@ function decodePath(value, prefix) {
26443
27911
  if (encoded.length === 0 || encoded.length > 2e3 || !/^[a-zA-Z0-9_-]+$/.test(encoded))
26444
27912
  throw new LocalAuthorizationError("The directory identifier is invalid");
26445
27913
  const decoded = Buffer.from(encoded, "base64url").toString("utf8");
26446
- if (Buffer.from(decoded, "utf8").toString("base64url") !== encoded || decoded.includes("\0") || normalize(decoded) !== decoded)
27914
+ if (Buffer.from(decoded, "utf8").toString("base64url") !== encoded || decoded.includes("\0") || normalize2(decoded) !== decoded)
26447
27915
  throw new LocalAuthorizationError("The directory identifier is invalid");
26448
27916
  return decoded;
26449
27917
  }
@@ -26465,20 +27933,20 @@ var WorkspaceDirectoryService = class {
26465
27933
  if (id === "home") return homedir2();
26466
27934
  if (id.startsWith("path-")) {
26467
27935
  const path2 = decodePath(id, "path-");
26468
- if (isAbsolute2(path2)) return path2;
27936
+ if (isAbsolute5(path2)) return path2;
26469
27937
  }
26470
27938
  throw new LocalAuthorizationError("The directory identifier is invalid");
26471
27939
  };
26472
27940
  resolvePath = async (requested, signal) => {
26473
27941
  signal.throwIfAborted();
26474
- if (!isAbsolute2(requested) || requested.includes("\0") || normalize(requested) !== requested)
27942
+ if (!isAbsolute5(requested) || requested.includes("\0") || normalize2(requested) !== requested)
26475
27943
  throw new LocalAuthorizationError("The local directory path is invalid");
26476
27944
  try {
26477
- const target = await realpath4(requested);
27945
+ const target = await realpath6(requested);
26478
27946
  signal.throwIfAborted();
26479
- const metadata = await stat4(target);
27947
+ const metadata = await stat6(target);
26480
27948
  signal.throwIfAborted();
26481
- if (!isAbsolute2(target) || normalize(target) !== target || !metadata.isDirectory())
27949
+ if (!isAbsolute5(target) || normalize2(target) !== target || !metadata.isDirectory())
26482
27950
  throw new LocalAuthorizationError(
26483
27951
  "The selected location is not a directory"
26484
27952
  );
@@ -26493,8 +27961,8 @@ var WorkspaceDirectoryService = class {
26493
27961
  }
26494
27962
  };
26495
27963
  label = (path2) => {
26496
- const suffix = relative2(homedir2(), path2);
26497
- return suffix === "" ? "~" : !isAbsolute2(suffix) && suffix !== ".." && !suffix.startsWith(`..${process.platform === "win32" ? "\\" : "/"}`) ? `~/${suffix.replaceAll("\\", "/")}` : path2;
27964
+ const suffix = relative3(homedir2(), path2);
27965
+ return suffix === "" ? "~" : !isAbsolute5(suffix) && suffix !== ".." && !suffix.startsWith(`..${process.platform === "win32" ? "\\" : "/"}`) ? `~/${suffix.replaceAll("\\", "/")}` : path2;
26498
27966
  };
26499
27967
  identify = async (bindingId, requestedPath, signal) => {
26500
27968
  this.authorizeMachine(bindingId);
@@ -26522,7 +27990,7 @@ var WorkspaceDirectoryService = class {
26522
27990
  continue;
26523
27991
  }
26524
27992
  try {
26525
- const path2 = await this.resolvePath(join9(target, child.name), signal);
27993
+ const path2 = await this.resolvePath(join15(target, child.name), signal);
26526
27994
  entries.push({ directoryId: encodePath(path2), name: child.name });
26527
27995
  } catch (cause) {
26528
27996
  signal.throwIfAborted();
@@ -26530,7 +27998,7 @@ var WorkspaceDirectoryService = class {
26530
27998
  }
26531
27999
  }
26532
28000
  entries.sort((a, b) => a.name.localeCompare(b.name));
26533
- const parent = dirname4(target);
28001
+ const parent = dirname5(target);
26534
28002
  return new WorkspaceDirectoryListing(
26535
28003
  id,
26536
28004
  this.label(target),
@@ -26645,7 +28113,8 @@ function decodeHistory(thread, value) {
26645
28113
  status: "available",
26646
28114
  messages,
26647
28115
  truncated,
26648
- coveredCommandIds: []
28116
+ coveredCommandIds: [],
28117
+ coveredMessageIds: []
26649
28118
  }
26650
28119
  };
26651
28120
  }
@@ -27322,7 +28791,7 @@ var RelayConnectionLiveness = class {
27322
28791
 
27323
28792
  // src/relay-connection/session-event-outbox.ts
27324
28793
  import { mkdirSync as mkdirSync3 } from "node:fs";
27325
- import { dirname as dirname5 } from "node:path";
28794
+ import { dirname as dirname6 } from "node:path";
27326
28795
  import { DatabaseSync as DatabaseSync3 } from "node:sqlite";
27327
28796
  function readPendingEnvelope(row) {
27328
28797
  if (typeof row !== "object" || row === null || Array.isArray(row)) {
@@ -27337,7 +28806,7 @@ function readPendingEnvelope(row) {
27337
28806
  var SessionEventOutbox = class {
27338
28807
  #database;
27339
28808
  constructor(path2) {
27340
- mkdirSync3(dirname5(path2), { recursive: true });
28809
+ mkdirSync3(dirname6(path2), { recursive: true });
27341
28810
  this.#database = new DatabaseSync3(path2);
27342
28811
  this.#database.exec(`
27343
28812
  CREATE TABLE IF NOT EXISTS relay_session_event_outbox (