@moxt-ai/mobius 0.0.10 → 0.0.12

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 (119) 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 +99 -24
  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 +1 -1
  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 -101
  61. package/dist/agent-catalog/discover-local-agents.d.ts.map +1 -1
  62. package/dist/agent-catalog/discover-local-agents.js +11 -564
  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-installation/agent-installation-manager.d.ts +1 -1
  69. package/dist/agent-installation/agent-installation-manager.d.ts.map +1 -1
  70. package/dist/agent-installation/automatic-adapter-provisioner.d.ts +2 -1
  71. package/dist/agent-installation/automatic-adapter-provisioner.d.ts.map +1 -1
  72. package/dist/agent-installation/automatic-adapter-provisioner.js +11 -2
  73. package/dist/agent-installation/automatic-adapter-provisioner.js.map +1 -1
  74. package/dist/agent-installation/deepseek-managed-package.d.ts +9 -0
  75. package/dist/agent-installation/deepseek-managed-package.d.ts.map +1 -0
  76. package/dist/agent-installation/deepseek-managed-package.js +10 -0
  77. package/dist/agent-installation/deepseek-managed-package.js.map +1 -0
  78. package/dist/agent-installation/fixed-agent-install-recipes.d.ts +18 -0
  79. package/dist/agent-installation/fixed-agent-install-recipes.d.ts.map +1 -1
  80. package/dist/agent-installation/fixed-agent-install-recipes.js +97 -0
  81. package/dist/agent-installation/fixed-agent-install-recipes.js.map +1 -1
  82. package/dist/agent-installation/fixed-installation-executor.d.ts +1 -1
  83. package/dist/agent-installation/fixed-installation-executor.d.ts.map +1 -1
  84. package/dist/agent-installation/fixed-installation-executor.js +17 -3
  85. package/dist/agent-installation/fixed-installation-executor.js.map +1 -1
  86. package/dist/agent-installation/managed-adapter-installer.d.ts +4 -4
  87. package/dist/agent-installation/managed-adapter-installer.d.ts.map +1 -1
  88. package/dist/agent-installation/managed-adapter-installer.js.map +1 -1
  89. package/dist/agent-installation/managed-agent-archive.d.ts +40 -0
  90. package/dist/agent-installation/managed-agent-archive.d.ts.map +1 -0
  91. package/dist/agent-installation/managed-agent-archive.js +274 -0
  92. package/dist/agent-installation/managed-agent-archive.js.map +1 -0
  93. package/dist/agent-installation/managed-npm-package.d.ts +3 -0
  94. package/dist/agent-installation/managed-npm-package.d.ts.map +1 -1
  95. package/dist/agent-installation/managed-npm-package.js +55 -24
  96. package/dist/agent-installation/managed-npm-package.js.map +1 -1
  97. package/dist/agent-installation/opencode-managed-release.d.ts +4 -0
  98. package/dist/agent-installation/opencode-managed-release.d.ts.map +1 -0
  99. package/dist/agent-installation/opencode-managed-release.js +25 -0
  100. package/dist/agent-installation/opencode-managed-release.js.map +1 -0
  101. package/dist/cli.js +2353 -1314
  102. package/dist/cli.js.map +4 -4
  103. package/dist/config.js +1 -1
  104. package/dist/config.js.map +1 -1
  105. package/dist/index.js +1802 -761
  106. package/dist/index.js.map +4 -4
  107. package/dist/native-sessions/codex-history.d.ts.map +1 -1
  108. package/dist/native-sessions/codex-history.js +1 -0
  109. package/dist/native-sessions/codex-history.js.map +1 -1
  110. package/dist/pairing/pair-local-machine.js +2 -2
  111. package/dist/pairing/pair-local-machine.js.map +1 -1
  112. package/dist/process/executable.d.ts +6 -1
  113. package/dist/process/executable.d.ts.map +1 -1
  114. package/dist/process/executable.js +150 -7
  115. package/dist/process/executable.js.map +1 -1
  116. package/dist/run-daemon.d.ts.map +1 -1
  117. package/dist/run-daemon.js +14 -2
  118. package/dist/run-daemon.js.map +1 -1
  119. 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"
@@ -499,7 +628,7 @@ function createDaemonConfig(connection, agents = [], installableAgents = []) {
499
628
  function loadDaemonConfig() {
500
629
  const relayUrl = new URL(
501
630
  // biome-ignore lint/complexity/useLiteralKeys: Environment variables use an index signature.
502
- process.env["MOBIUS_RELAY_URL"] ?? "ws://127.0.0.1:8787/api/channels/local/daemon"
631
+ process.env["MOBIUS_RELAY_URL"] ?? "ws://127.0.0.1:8787/mobius/api/channels/local/daemon"
503
632
  );
504
633
  relayUrl.searchParams.set(
505
634
  "token",
@@ -532,7 +661,8 @@ import { spawn as spawn2 } from "node:child_process";
532
661
  import {
533
662
  methods as methods2,
534
663
  ndJsonStream,
535
- PROTOCOL_VERSION
664
+ PROTOCOL_VERSION,
665
+ RequestError
536
666
  } from "@agentclientprotocol/sdk";
537
667
 
538
668
  // ../../node_modules/.pnpm/zod@4.5.4/node_modules/zod/v4/classic/external.js
@@ -20307,7 +20437,10 @@ var sessionHistorySchema = external_exports.discriminatedUnion("status", [
20307
20437
  status: external_exports.literal("available"),
20308
20438
  messages: external_exports.array(historyMessage).max(SESSION_HISTORY_MESSAGE_LIMIT).readonly(),
20309
20439
  truncated: external_exports.boolean(),
20310
- 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([])
20311
20444
  }).readonly(),
20312
20445
  external_exports.strictObject({ status: external_exports.literal("unavailable") }).readonly()
20313
20446
  ]).refine(
@@ -21546,7 +21679,8 @@ var AcpHistoryReplay = class {
21546
21679
  status: "available",
21547
21680
  messages: [...this.#messages],
21548
21681
  truncated: this.#truncated,
21549
- coveredCommandIds: []
21682
+ coveredCommandIds: [],
21683
+ coveredMessageIds: []
21550
21684
  });
21551
21685
  };
21552
21686
 
@@ -21762,6 +21896,8 @@ var SqliteAcpSessionStore = class {
21762
21896
 
21763
21897
  // src/acp/session-manager.ts
21764
21898
  var PROCESS_STOP_TIMEOUT_MILLISECONDS = 1e3;
21899
+ var MAX_PRE_SESSION_UPDATES = 100;
21900
+ var MAX_PRE_SESSION_UPDATE_BYTES = 1024 * 1024;
21765
21901
  var SESSION_CONTROL_COMMAND_ID = "session-control";
21766
21902
  var NullAcpSessionObserver = class {
21767
21903
  onCommands = () => Promise.resolve();
@@ -22370,8 +22506,11 @@ var AcpProcessSession = class _AcpProcessSession {
22370
22506
  #mobiusSessionId;
22371
22507
  #pendingElicitations = /* @__PURE__ */ new Map();
22372
22508
  #pendingPermissions = /* @__PURE__ */ new Map();
22509
+ #preSessionUpdates = [];
22373
22510
  #processExit;
22374
22511
  #store;
22512
+ #verifiedAgentVersion;
22513
+ #preSessionUpdateBytes = 0;
22375
22514
  #agentName = "";
22376
22515
  #agentVersion = "";
22377
22516
  #capabilities = {
@@ -22405,6 +22544,7 @@ var AcpProcessSession = class _AcpProcessSession {
22405
22544
  this.#getObserver = getObserver;
22406
22545
  this.#mobiusSessionId = mobiusSessionId;
22407
22546
  this.#store = store;
22547
+ this.#verifiedAgentVersion = agent.agentVersion;
22408
22548
  this.#child = spawn2(agent.adapterPath, [...agent.arguments], {
22409
22549
  cwd,
22410
22550
  detached: process.platform !== "win32",
@@ -22560,7 +22700,10 @@ var AcpProcessSession = class _AcpProcessSession {
22560
22700
  initialized.agentInfo?.title ?? initialized.agentInfo?.name ?? this.#agentId,
22561
22701
  255
22562
22702
  );
22563
- this.#agentVersion = truncate2(initialized.agentInfo?.version ?? "", 128);
22703
+ this.#agentVersion = truncate2(
22704
+ this.#verifiedAgentVersion.length > 0 ? this.#verifiedAgentVersion : initialized.agentInfo?.version ?? "",
22705
+ 128
22706
+ );
22564
22707
  }
22565
22708
  initialize = async (signal, origin) => {
22566
22709
  await this.#initializeAgent(signal);
@@ -22606,7 +22749,7 @@ var AcpProcessSession = class _AcpProcessSession {
22606
22749
  "ACP agent exited while forking a session",
22607
22750
  signal
22608
22751
  );
22609
- this.#nativeSessionId = nativeSessionIdSchema.parse(forked.sessionId);
22752
+ this.selectNativeSession(forked.sessionId);
22610
22753
  if (this.#nativeSessionId === origin.nativeSessionId || this.#store.findNative(this.#agentId, this.#nativeSessionId).length > 0) {
22611
22754
  throw new AcpExecutionError(
22612
22755
  "The Agent did not create an independent fork",
@@ -22621,7 +22764,7 @@ var AcpProcessSession = class _AcpProcessSession {
22621
22764
  stored.session.additionalDirectories,
22622
22765
  this.#additionalDirectories
22623
22766
  )) {
22624
- this.#nativeSessionId = stored.session.nativeSessionId;
22767
+ this.selectNativeSession(stored.session.nativeSessionId);
22625
22768
  this.#prompted = stored.session.prompted;
22626
22769
  this.#restored = true;
22627
22770
  if (this.#capabilities.resumeSession) {
@@ -22691,7 +22834,7 @@ var AcpProcessSession = class _AcpProcessSession {
22691
22834
  "ACP agent exited while starting a session",
22692
22835
  signal
22693
22836
  );
22694
- this.#nativeSessionId = created.sessionId;
22837
+ this.selectNativeSession(created.sessionId);
22695
22838
  lifecycleResponse = created;
22696
22839
  }
22697
22840
  const lifecycleRecord = isRecord3(lifecycleResponse) ? lifecycleResponse : {};
@@ -22953,13 +23096,17 @@ var AcpProcessSession = class _AcpProcessSession {
22953
23096
  }
22954
23097
  };
22955
23098
  cancel = async () => {
22956
- await this.cancelPendingInteractions();
22957
- if (!this.#turn.running) {
22958
- 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);
22959
23109
  }
22960
- await this.#connection.agent.notify(methods2.agent.session.cancel, {
22961
- sessionId: this.#nativeSessionId
22962
- });
22963
23110
  };
22964
23111
  respondPermission = async (options) => {
22965
23112
  const pending = this.#pendingPermissions.get(options.interactionId);
@@ -23146,11 +23293,45 @@ var AcpProcessSession = class _AcpProcessSession {
23146
23293
  });
23147
23294
  };
23148
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) => {
23149
23314
  this.#updateTail = this.#updateTail.then(
23150
23315
  async () => await this.processUpdate(notification)
23151
23316
  );
23152
23317
  return this.#updateTail;
23153
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
+ };
23154
23335
  processUpdate = async (notification) => {
23155
23336
  this.assertNativeSession(notification.sessionId);
23156
23337
  const update = notification.update;
@@ -23288,9 +23469,12 @@ var AcpProcessSession = class _AcpProcessSession {
23288
23469
  }
23289
23470
  await this.closeProcess();
23290
23471
  };
23291
- closeProcess = async () => {
23292
- this.#connection.close();
23293
- await stopProcessTree(this.#child);
23472
+ closeProcess = async (capturedProcesses = []) => {
23473
+ try {
23474
+ await stopProcessTree(this.#child, capturedProcesses);
23475
+ } finally {
23476
+ this.#connection.close();
23477
+ }
23294
23478
  };
23295
23479
  race = async (operation, exitMessage, signal) => {
23296
23480
  signal.throwIfAborted();
@@ -23306,13 +23490,25 @@ var AcpProcessSession = class _AcpProcessSession {
23306
23490
  };
23307
23491
  });
23308
23492
  try {
23309
- return await Promise.race([
23310
- operation,
23311
- this.#processExit.then(() => {
23312
- throw new AcpExecutionError(exitMessage);
23313
- }),
23314
- aborted2
23315
- ]);
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
+ }
23316
23512
  } finally {
23317
23513
  removeAbortListener();
23318
23514
  }
@@ -23571,7 +23767,13 @@ var AcpSessionManager = class {
23571
23767
  this.#cancellationRequests.add(sessionId);
23572
23768
  const runtime = this.#sessions.get(sessionId);
23573
23769
  if (runtime !== void 0) {
23574
- 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
+ }
23575
23777
  }
23576
23778
  };
23577
23779
  runPrompt = async (options) => {
@@ -23624,7 +23826,19 @@ var AcpSessionManager = class {
23624
23826
  if (this.#cancellationRequests.has(options.sessionId)) {
23625
23827
  return { stopReason: "cancelled" };
23626
23828
  }
23627
- return await runtime.prompt(boundedOptions);
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
+ }
23628
23842
  } catch (error61) {
23629
23843
  const failedRuntime = this.#sessions.get(options.sessionId);
23630
23844
  if (failedRuntime !== void 0) {
@@ -23932,26 +24146,16 @@ var LocalAuthorizationError = class extends Error {
23932
24146
  // src/pairing/pair-local-machine.ts
23933
24147
  import { randomUUID } from "node:crypto";
23934
24148
  import {
23935
- mkdir as mkdir2,
23936
- open as open4,
23937
- realpath as realpath3,
23938
- rename as rename2,
23939
- stat as stat3,
23940
- 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
23941
24155
  } from "node:fs/promises";
23942
24156
  import { hostname as hostname3 } from "node:os";
23943
- import { basename, join as join8, resolve as resolve3 } from "node:path";
23944
- import { fetch } from "undici";
23945
-
23946
- // src/agent-catalog/discover-local-agents.ts
23947
- import { spawn as spawn3 } from "node:child_process";
23948
- import { isAbsolute as isAbsolute2, join as join7 } from "node:path";
23949
- import {
23950
- methods as methods3,
23951
- ndJsonStream as ndJsonStream2,
23952
- PROTOCOL_VERSION as PROTOCOL_VERSION2,
23953
- RequestError
23954
- } from "@agentclientprotocol/sdk";
24157
+ import { basename, join as join13, resolve as resolve3 } from "node:path";
24158
+ import { fetch as fetch2 } from "undici";
23955
24159
 
23956
24160
  // src/agent-installation/installation-grants.ts
23957
24161
  import { open as open2 } from "node:fs/promises";
@@ -23995,8 +24199,102 @@ async function readGrantedAgents(stateDirectory) {
23995
24199
  }
23996
24200
  }
23997
24201
 
23998
- // src/agent-installation/managed-adapter-installer.ts
23999
- import { join as join6 } from "node:path";
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
+ };
24000
24298
 
24001
24299
  // src/agent-installation/managed-npm-package.ts
24002
24300
  import {
@@ -24013,9 +24311,12 @@ var INSTALL_TIMEOUT_MILLISECONDS = 5 * 60 * 1e3;
24013
24311
  var PACKAGE_METADATA_LIMIT_BYTES = 64 * 1024;
24014
24312
  var PACKAGE_LOCK_LIMIT_BYTES = 8 * 1024 * 1024;
24015
24313
  var ManagedNpmPackageDefinition = class {
24314
+ dependencyResolutionArguments = Object.freeze([]);
24016
24315
  executableName;
24316
+ includeOptionalDependencies = false;
24017
24317
  packageName;
24018
24318
  version;
24319
+ verifyDependencyClosure = false;
24019
24320
  constructor(packageName, version2, executableName) {
24020
24321
  this.executableName = executableName;
24021
24322
  this.packageName = packageName;
@@ -24116,6 +24417,27 @@ function verifyPackageLock(lock, definition) {
24116
24417
  let matches = 0;
24117
24418
  for (const [key, candidate] of Object.entries(packages)) {
24118
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
+ }
24119
24441
  if (normalizedKey === suffix || normalizedKey.endsWith(`/${suffix}`)) {
24120
24442
  entry = candidate;
24121
24443
  matches += 1;
@@ -24213,33 +24535,42 @@ var ManagedNpmPackageInstaller = class {
24213
24535
  "A supported npm executable is required to install the managed package"
24214
24536
  );
24215
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
+ }
24216
24569
  await runBoundedProcess({
24217
- arguments: [
24218
- "install",
24219
- "--prefix",
24220
- staging,
24221
- "--omit=optional",
24222
- "--ignore-scripts",
24223
- "--no-audit",
24224
- "--no-fund",
24225
- "--package-lock=true",
24226
- "--save-exact",
24227
- "--registry=https://registry.npmjs.org/",
24228
- `${definition.packageName}@${definition.version}`
24229
- ],
24570
+ arguments: installArguments,
24230
24571
  command: npm.path,
24231
24572
  cwd: staging,
24232
- environment: {
24233
- HOME: join5(staging, "home"),
24234
- NPM_CONFIG_AUDIT: "false",
24235
- NPM_CONFIG_CACHE: join5(staging, ".npm-cache"),
24236
- NPM_CONFIG_FUND: "false",
24237
- NPM_CONFIG_IGNORE_SCRIPTS: "true",
24238
- NPM_CONFIG_OMIT: "optional",
24239
- NPM_CONFIG_PACKAGE_LOCK: "true",
24240
- NPM_CONFIG_REGISTRY: "https://registry.npmjs.org/",
24241
- PATH: `${dirname3(process.execPath)}${delimiter}/usr/bin${delimiter}/bin`
24242
- },
24573
+ environment: installEnvironment,
24243
24574
  outputLimitBytes: 64 * 1024,
24244
24575
  signal,
24245
24576
  timeoutMilliseconds: INSTALL_TIMEOUT_MILLISECONDS
@@ -24281,144 +24612,101 @@ var ManagedNpmPackageInstaller = class {
24281
24612
  };
24282
24613
  };
24283
24614
 
24284
- // src/agent-installation/managed-adapter-installer.ts
24285
- var ManagedAdapterInstallError = class extends Error {
24286
- code;
24287
- constructor(code, message, options = {}) {
24288
- super(message, options);
24289
- this.code = code;
24290
- this.name = "ManagedAdapterInstallError";
24291
- }
24292
- };
24293
- function translateError(error61) {
24294
- if (error61 instanceof ManagedAdapterInstallError) {
24295
- return error61;
24296
- }
24297
- if (error61 instanceof ManagedNpmPackageError) {
24298
- if (error61.code === "package_manager_not_found") {
24299
- return new ManagedAdapterInstallError(
24300
- error61.code,
24301
- "A supported npm executable is required to install the ACP adapter",
24302
- { cause: error61 }
24303
- );
24304
- }
24305
- if (error61.code === "managed_package_verification_failed") {
24306
- return new ManagedAdapterInstallError(
24307
- "adapter_verification_failed",
24308
- "The managed adapter did not match its pinned artifact",
24309
- { cause: error61 }
24310
- );
24311
- }
24312
- if (error61.code === "managed_package_publish_failed") {
24313
- return new ManagedAdapterInstallError(
24314
- "adapter_publish_failed",
24315
- "The managed adapter could not be published",
24316
- { cause: error61 }
24317
- );
24318
- }
24319
- }
24320
- return new ManagedAdapterInstallError(
24321
- "adapter_install_failed",
24322
- "The pinned ACP adapter could not be installed",
24323
- { cause: error61 }
24324
- );
24325
- }
24326
- async function validateManagedAdapter(root, specification) {
24327
- try {
24328
- return await validateManagedNpmPackage(
24329
- root,
24330
- specification.adapterPackageDefinition
24331
- );
24332
- } catch (error61) {
24333
- throw translateError(error61);
24334
- }
24335
- }
24336
- var ManagedAdapterInstaller = class {
24337
- #environment;
24338
- #npmInstaller;
24339
- #stateDirectory;
24340
- constructor(options, npmInstaller = new ManagedNpmPackageInstaller()) {
24341
- this.#environment = options.environment;
24342
- this.#npmInstaller = npmInstaller;
24343
- this.#stateDirectory = options.stateDirectory;
24344
- }
24345
- install = async (specification, signal) => {
24346
- const root = join6(
24347
- this.#stateDirectory,
24348
- "adapters",
24349
- specification.id,
24350
- specification.adapterVersion
24351
- );
24352
- try {
24353
- return await this.#npmInstaller.install(
24354
- root,
24355
- specification.adapterPackageDefinition,
24356
- this.#environment,
24357
- signal
24358
- );
24359
- } catch (error61) {
24360
- if (signal.aborted) {
24361
- signal.throwIfAborted();
24362
- }
24363
- throw translateError(error61);
24364
- }
24365
- };
24366
- };
24367
-
24368
- // src/agent-installation/pi-managed-packages.ts
24369
- var PI_ACP_PACKAGE = new SriManagedNpmPackageDefinition(
24370
- "pi-acp",
24371
- "0.0.33",
24372
- "pi-acp",
24373
- "sha512-vX9kY1tK14E72G4dBAx+RGCk/k7XPjTHls6dLUxA8WSkBav6B6JHuSBv3eusp50LCR/GTRsR2kIKsG0Z5jANzw==",
24374
- "https://registry.npmjs.org/pi-acp/-/pi-acp-0.0.33.tgz"
24375
- );
24376
- var PI_AGENT_PACKAGE = new SriManagedNpmPackageDefinition(
24377
- "@earendil-works/pi-coding-agent",
24378
- "0.85.0",
24379
- "pi",
24380
- "sha512-INxVkLAVfAMju5MojJpmyu/0bMP+r+ffZuS7UqVv32E2JwHBRbcHfELDfmFNvapEbgYfKN2r9OYO1p3TqDBR+g==",
24381
- "https://registry.npmjs.org/@earendil-works/pi-coding-agent/-/pi-coding-agent-0.85.0.tgz"
24382
- );
24383
-
24384
- // src/agent-catalog/discover-local-agents.ts
24615
+ // src/agent-catalog/agent-specification.ts
24616
+ import { join as join6 } from "node:path";
24385
24617
  var VERSION_PROBE_TIMEOUT_MILLISECONDS = 3e3;
24386
24618
  var ACP_PROBE_TIMEOUT_MILLISECONDS = 5e3;
24387
- var ACP_OUTPUT_LIMIT_BYTES = 1024 * 1024;
24388
24619
  var DEFAULT_PROMPT_TIMEOUT_MILLISECONDS = 30 * 60 * 1e3;
24389
- var PI_ACP_PROBE_TIMEOUT_MILLISECONDS = 3e4;
24390
- var PI_PROMPT_TIMEOUT_MILLISECONDS = 5 * 60 * 1e3;
24391
24620
  var LocalAgentSpecification = class {
24392
24621
  acpProbeTimeoutMilliseconds = ACP_PROBE_TIMEOUT_MILLISECONDS;
24393
24622
  authenticationCommand = () => "";
24394
24623
  adapterVersionArguments = ["--version"];
24395
24624
  agentVersionArguments = ["--version"];
24396
24625
  promptTimeoutMilliseconds = DEFAULT_PROMPT_TIMEOUT_MILLISECONDS;
24397
- get adapterExecutable() {
24398
- return this.adapterPackageDefinition.executableName;
24399
- }
24400
- get adapterPackage() {
24401
- return this.adapterPackageDefinition.packageName;
24402
- }
24403
- get adapterVersion() {
24404
- return this.adapterPackageDefinition.version;
24405
- }
24406
- resolveManagedAgent = async (stateDirectory, platform) => {
24626
+ versionProbeTimeoutMilliseconds = VERSION_PROBE_TIMEOUT_MILLISECONDS;
24627
+ resolveManagedAgent = async (stateDirectory, platform, signal) => {
24628
+ signal.throwIfAborted();
24407
24629
  const executable = await resolveExecutablePath(
24408
- join7(stateDirectory, ...this.managedAgentExecutablePath),
24630
+ join6(stateDirectory, ...this.managedAgentExecutablePath),
24409
24631
  platform
24410
24632
  );
24633
+ signal.throwIfAborted();
24411
24634
  if (executable === null) {
24412
24635
  throw new Error("The managed Agent executable is unavailable");
24413
24636
  }
24414
24637
  return executable;
24415
24638
  };
24416
- recoveryCommand = () => `npm install -g --omit=optional ${this.adapterPackage}@${this.adapterVersion}`;
24639
+ createLaunchEnvironment = async (_agent, _context) => Object.freeze({});
24640
+ recoveryCommand = () => "";
24417
24641
  supportsInstallation = (platform, architecture) => (platform === "darwin" || platform === "linux") && (architecture === "arm64" || architecture === "x64");
24418
24642
  verifyAcp = (_connection, _initialized, _defaultWorkspace, _signal) => Promise.resolve();
24419
24643
  };
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
+ };
24420
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}`;
24674
+ };
24675
+
24676
+ // src/agent-catalog/agents/claude-code-agent.ts
24677
+ var ClaudeCodeAgentSpecification = class extends BridgedAcpAgentDefinition {
24678
+ adapterEnvironmentVariable = "CLAUDE_CODE_EXECUTABLE";
24679
+ adapterOverrideVariable = "MOBIUS_CLAUDE_ACP_PATH";
24680
+ adapterPackageDefinition = new ManagedNpmPackageDefinition(
24681
+ "@agentclientprotocol/claude-agent-acp",
24682
+ "0.73.0",
24683
+ "claude-agent-acp"
24684
+ );
24685
+ agentExecutable = "claude";
24686
+ agentOverrideVariable = "MOBIUS_CLAUDE_PATH";
24687
+ id = "claude";
24688
+ label = "Claude Code";
24689
+ managedAdapterExecutablePath = [
24690
+ "adapters",
24691
+ "claude",
24692
+ "0.73.0",
24693
+ "node_modules",
24694
+ "@agentclientprotocol",
24695
+ "claude-agent-acp",
24696
+ "dist",
24697
+ "index.js"
24698
+ ];
24699
+ managedAgentExecutablePath = [
24700
+ "agents",
24701
+ "claude",
24702
+ "home",
24703
+ ".local",
24704
+ "bin",
24705
+ "claude"
24706
+ ];
24421
24707
  };
24708
+
24709
+ // src/agent-catalog/agents/codex-agent.ts
24422
24710
  var CodexAgentSpecification = class extends BridgedAcpAgentDefinition {
24423
24711
  adapterEnvironmentVariable = "CODEX_PATH";
24424
24712
  adapterOverrideVariable = "MOBIUS_CODEX_ACP_PATH";
@@ -24443,39 +24731,769 @@ var CodexAgentSpecification = class extends BridgedAcpAgentDefinition {
24443
24731
  ];
24444
24732
  managedAgentExecutablePath = ["agents", "codex", "bin", "codex"];
24445
24733
  };
24446
- var ClaudeCodeAgentSpecification = class extends BridgedAcpAgentDefinition {
24447
- adapterEnvironmentVariable = "CLAUDE_CODE_EXECUTABLE";
24448
- adapterOverrideVariable = "MOBIUS_CLAUDE_ACP_PATH";
24449
- adapterPackageDefinition = new ManagedNpmPackageDefinition(
24450
- "@agentclientprotocol/claude-agent-acp",
24451
- "0.73.0",
24452
- "claude-agent-acp"
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"
24743
+ ]);
24744
+ includeOptionalDependencies = true;
24745
+ verifyDependencyClosure = true;
24746
+ };
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";
24762
+ }
24763
+ };
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
+ );
24772
+ }
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
+ );
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
+ };
24861
+ };
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 {
24896
+ code;
24897
+ constructor(code, message, options = {}) {
24898
+ super(message, options);
24899
+ this.code = code;
24900
+ this.name = "InstallerDownloadError";
24901
+ }
24902
+ };
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;
24911
+ }
24912
+ };
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}`
24453
25382
  );
24454
- agentExecutable = "claude";
24455
- agentOverrideVariable = "MOBIUS_CLAUDE_PATH";
24456
- id = "claude";
24457
- label = "Claude Code";
24458
- managedAdapterExecutablePath = [
24459
- "adapters",
24460
- "claude",
24461
- "0.73.0",
24462
- "node_modules",
24463
- "@agentclientprotocol",
24464
- "claude-agent-acp",
24465
- "dist",
24466
- "index.js"
24467
- ];
24468
- managedAgentExecutablePath = [
24469
- "agents",
24470
- "claude",
24471
- "home",
24472
- ".local",
24473
- "bin",
24474
- "claude"
24475
- ];
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
+ };
24476
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;
24477
25495
  var PiAgentSpecification = class extends BridgedAcpAgentDefinition {
24478
- acpProbeTimeoutMilliseconds = PI_ACP_PROBE_TIMEOUT_MILLISECONDS;
25496
+ acpProbeTimeoutMilliseconds = ACP_PROBE_TIMEOUT_MILLISECONDS2;
24479
25497
  adapterEnvironmentVariable = "PI_ACP_PI_COMMAND";
24480
25498
  adapterOverrideVariable = "MOBIUS_PI_ACP_PATH";
24481
25499
  adapterPackageDefinition = PI_ACP_PACKAGE;
@@ -24505,11 +25523,16 @@ var PiAgentSpecification = class extends BridgedAcpAgentDefinition {
24505
25523
  "bundle",
24506
25524
  "cli.js"
24507
25525
  ];
24508
- promptTimeoutMilliseconds = PI_PROMPT_TIMEOUT_MILLISECONDS;
24509
- resolveManagedAgent = async (stateDirectory, _platform) => await validateManagedNpmPackage(
24510
- join7(stateDirectory, "agents", this.id, PI_AGENT_PACKAGE.version),
24511
- PI_AGENT_PACKAGE
24512
- );
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
+ };
24513
25536
  verifyAcp = async (connection, initialized, defaultWorkspace, signal) => {
24514
25537
  const capabilities = initialized.agentCapabilities ?? {};
24515
25538
  if (capabilities.loadSession !== true) {
@@ -24549,138 +25572,134 @@ var PiAgentSpecification = class extends BridgedAcpAgentDefinition {
24549
25572
  }
24550
25573
  };
24551
25574
  };
25575
+
25576
+ // src/agent-catalog/agents/supported-agent-specifications.ts
24552
25577
  function supportedLocalAgentSpecifications() {
24553
25578
  return Object.freeze([
24554
25579
  new CodexAgentSpecification(),
24555
25580
  new ClaudeCodeAgentSpecification(),
24556
- new PiAgentSpecification()
25581
+ new PiAgentSpecification(),
25582
+ new DeepSeekHarnessAgentSpecification(),
25583
+ new OpenCodeAgentSpecification()
24557
25584
  ]);
24558
25585
  }
24559
- var AgentDiscovery = class {
24560
- specification;
24561
- constructor(specification) {
24562
- this.specification = specification;
24563
- }
24564
- };
24565
- var AvailableAgent = class extends AgentDiscovery {
24566
- agent;
24567
- status = "ready";
24568
- constructor(specification, agent) {
24569
- super(specification);
24570
- this.agent = agent;
24571
- }
24572
- };
24573
- var UnavailableAgent = class extends AgentDiscovery {
24574
- };
24575
- var MissingAdapter = class extends UnavailableAgent {
24576
- code = "adapter_not_found";
24577
- message = "ACP adapter not found";
24578
- status = "missing_adapter";
24579
- constructor(specification) {
24580
- super(specification);
24581
- }
24582
- };
24583
- var MissingAgent = class extends UnavailableAgent {
24584
- code = "agent_not_found";
24585
- message = "Agent executable not found";
24586
- status = "missing_agent";
24587
- constructor(specification) {
24588
- super(specification);
24589
- }
24590
- };
24591
- var ProbeFailed = class extends UnavailableAgent {
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 {
24592
25602
  code;
24593
- message;
24594
- status = "probe_failed";
24595
- constructor(specification, code, message) {
24596
- super(specification);
25603
+ constructor(code, message, options = {}) {
25604
+ super(message, options);
24597
25605
  this.code = code;
24598
- this.message = message;
24599
- }
24600
- };
24601
- var IncompatibleAdapter = class extends UnavailableAgent {
24602
- code = "acp_incompatible";
24603
- message = "ACP adapter is incompatible";
24604
- status = "incompatible_adapter";
24605
- constructor(specification) {
24606
- super(specification);
25606
+ this.name = "ManagedAdapterInstallError";
24607
25607
  }
24608
25608
  };
24609
- var AuthenticationRequiredAgent = class extends UnavailableAgent {
24610
- code = "authentication_required";
24611
- message = "Agent authentication is required";
24612
- status = "authentication_required";
24613
- constructor(specification) {
24614
- super(specification);
25609
+ function translateError(error61) {
25610
+ if (error61 instanceof ManagedAdapterInstallError) {
25611
+ return error61;
24615
25612
  }
24616
- };
24617
- var LocalAgentInventory = class {
24618
- available;
24619
- discoveries;
24620
- installable;
24621
- unavailable;
24622
- constructor(discoveries, grantedAgents = /* @__PURE__ */ new Set(), platform = process.platform, architecture = process.arch) {
24623
- const available = [];
24624
- const unavailable = [];
24625
- for (const discovery of discoveries) {
24626
- if (discovery instanceof AvailableAgent) {
24627
- available.push(discovery);
24628
- } else if (discovery instanceof UnavailableAgent) {
24629
- unavailable.push(discovery);
24630
- } else {
24631
- throw new Error("Unsupported Agent discovery outcome");
24632
- }
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
+ );
24633
25620
  }
24634
- this.available = Object.freeze(available);
24635
- this.discoveries = Object.freeze([...discoveries]);
24636
- this.installable = Object.freeze(
24637
- unavailable.filter(
24638
- (discovery) => !(discovery instanceof AuthenticationRequiredAgent) && discovery.specification.supportsInstallation(
24639
- platform,
24640
- architecture
24641
- )
24642
- ).map(
24643
- (discovery) => new InstallableAgentDefinition(
24644
- discovery.specification.id,
24645
- discovery.specification.label,
24646
- !grantedAgents.has(discovery.specification.id)
24647
- )
24648
- )
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
24649
25647
  );
24650
- this.unavailable = Object.freeze(unavailable);
25648
+ } catch (error61) {
25649
+ throw translateError(error61);
24651
25650
  }
24652
- readyAgents = () => this.available.map((discovery) => discovery.agent);
24653
- };
24654
- var AgentProbeError = class extends Error {
24655
- code;
24656
- constructor(code, message, options = {}) {
24657
- super(message, options);
24658
- this.code = code;
24659
- 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;
24660
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
+ };
24661
25682
  };
24662
- var DiscoveryAcpHandler = class {
24663
- onElicitation = (_request, _signal) => Promise.reject(new Error("ACP probe does not accept elicitations"));
24664
- onElicitationComplete = (_notification) => Promise.resolve();
24665
- onPermission = (_request, _signal) => Promise.reject(new Error("ACP probe does not grant permissions"));
24666
- onUpdate = (_notification) => Promise.resolve();
24667
- };
24668
- async function resolveManagedExecutable(specification, options) {
25683
+
25684
+ // src/agent-catalog/executable-discovery.ts
25685
+ async function resolveManagedExecutable(specification, context) {
24669
25686
  try {
24670
25687
  return await specification.resolveManagedAgent(
24671
- readStateDirectory(options.environment),
24672
- options.platform ?? process.platform
25688
+ readStateDirectory(context.environment),
25689
+ context.platform ?? process.platform,
25690
+ context.signal
24673
25691
  );
24674
25692
  } catch {
25693
+ context.signal.throwIfAborted();
24675
25694
  return null;
24676
25695
  }
24677
25696
  }
24678
- async function resolveManagedAdapterExecutable(specification, options) {
25697
+ async function resolveManagedAdapterExecutable(specification, context) {
24679
25698
  let managed;
24680
25699
  try {
24681
25700
  managed = await validateManagedAdapter(
24682
- join7(
24683
- readStateDirectory(options.environment),
25701
+ join12(
25702
+ readStateDirectory(context.environment),
24684
25703
  "adapters",
24685
25704
  specification.id,
24686
25705
  specification.adapterVersion
@@ -24692,19 +25711,19 @@ async function resolveManagedAdapterExecutable(specification, options) {
24692
25711
  }
24693
25712
  return managed;
24694
25713
  }
24695
- async function resolveSpecificationExecutables(executableName, overrideVariable, resolveManaged, options) {
24696
- const override = options.environment[overrideVariable];
25714
+ async function resolveSpecificationExecutables(executableName, overrideVariable, resolveManaged, context) {
25715
+ const override = context.environment[overrideVariable];
24697
25716
  if (override !== void 0) {
24698
- if (override.length === 0 || !isAbsolute2(override)) {
25717
+ if (override.length === 0 || !isAbsolute4(override)) {
24699
25718
  return [];
24700
25719
  }
24701
- const executable = await resolveExecutablePath(override, options.platform);
25720
+ const executable = await resolveExecutablePath(override, context.platform);
24702
25721
  return executable === null ? [] : [executable];
24703
25722
  }
24704
25723
  const external = await findExecutableOnPath(
24705
25724
  executableName,
24706
- options.environment,
24707
- options.platform
25725
+ context.environment,
25726
+ context.platform
24708
25727
  );
24709
25728
  const managed = await resolveManaged();
24710
25729
  if (external === null) {
@@ -24715,41 +25734,47 @@ async function resolveSpecificationExecutables(executableName, overrideVariable,
24715
25734
  }
24716
25735
  return [external, managed];
24717
25736
  }
24718
- async function resolveAgentExecutables(specification, options) {
25737
+ async function resolveAgentExecutables(specification, context) {
24719
25738
  return await resolveSpecificationExecutables(
24720
25739
  specification.agentExecutable,
24721
25740
  specification.agentOverrideVariable,
24722
- async () => await resolveManagedExecutable(specification, options),
24723
- options
25741
+ async () => await resolveManagedExecutable(specification, context),
25742
+ context
24724
25743
  );
24725
25744
  }
24726
- 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
+ }
24727
25752
  return await resolveSpecificationExecutables(
24728
25753
  specification.adapterExecutable,
24729
25754
  specification.adapterOverrideVariable,
24730
- async () => await resolveManagedAdapterExecutable(specification, options),
24731
- options
25755
+ async () => await resolveManagedAdapterExecutable(specification, context),
25756
+ context
24732
25757
  );
24733
25758
  }
24734
- async function resolveAgentExecutable(specification, options) {
24735
- const executables = await resolveAgentExecutables(specification, options);
25759
+ async function resolveAgentExecutable(specification, context) {
25760
+ const executables = await resolveAgentExecutables(specification, context);
24736
25761
  return executables[0] ?? null;
24737
25762
  }
24738
- async function resolveAdapterExecutable(specification, options) {
24739
- const executables = await resolveAdapterExecutables(specification, options);
25763
+ async function resolveAdapterExecutable(specification, context) {
25764
+ const executables = await resolveAdapterExecutables(specification, context);
24740
25765
  return executables[0] ?? null;
24741
25766
  }
24742
25767
  function normalizedVersion(output2) {
24743
25768
  return output2.trim().split(/\r?\n/, 1)[0]?.trim().slice(0, 128) ?? "";
24744
25769
  }
24745
- async function probeVersion(executable, arguments_, environment, defaultWorkspace, signal) {
25770
+ async function probeVersion(executable, arguments_, environment, defaultWorkspace, signal, timeoutMilliseconds) {
24746
25771
  const result = await runBoundedProcess({
24747
25772
  arguments: arguments_,
24748
25773
  command: executable.path,
24749
25774
  cwd: defaultWorkspace,
24750
25775
  environment,
24751
25776
  signal,
24752
- timeoutMilliseconds: VERSION_PROBE_TIMEOUT_MILLISECONDS
25777
+ timeoutMilliseconds
24753
25778
  });
24754
25779
  const version2 = normalizedVersion(result.stdout || result.stderr);
24755
25780
  if (version2.length === 0) {
@@ -24768,63 +25793,73 @@ var VerifiedAgentExecutable = class {
24768
25793
  this.version = version2;
24769
25794
  }
24770
25795
  };
24771
- async function findVerifiedAgentExecutable(specification, options) {
24772
- const executables = await resolveAgentExecutables(specification, options);
25796
+ async function findVerifiedAgentExecutable(specification, context) {
25797
+ const executables = await resolveAgentExecutables(specification, context);
24773
25798
  for (const executable of executables) {
24774
25799
  try {
24775
25800
  const version2 = await probeVersion(
24776
25801
  executable,
24777
25802
  specification.agentVersionArguments,
24778
- options.environment,
24779
- options.defaultWorkspace,
24780
- options.signal
25803
+ context.environment,
25804
+ context.defaultWorkspace,
25805
+ context.signal,
25806
+ specification.versionProbeTimeoutMilliseconds
24781
25807
  );
24782
25808
  return new VerifiedAgentExecutable(executable, version2);
24783
25809
  } catch {
24784
- if (options.signal.aborted) {
24785
- options.signal.throwIfAborted();
25810
+ if (context.signal.aborted) {
25811
+ context.signal.throwIfAborted();
24786
25812
  }
24787
25813
  }
24788
25814
  }
24789
25815
  return null;
24790
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
+ };
24791
25826
  function readableAcpStream(input2) {
24792
25827
  let byteLength = 0;
24793
- let open6 = true;
25828
+ let open7 = true;
24794
25829
  return new ReadableStream({
24795
25830
  start(controller) {
24796
25831
  input2.on("data", (chunk) => {
24797
- if (!open6) {
25832
+ if (!open7) {
24798
25833
  return;
24799
25834
  }
24800
25835
  if (!(chunk instanceof Uint8Array)) {
24801
- open6 = false;
25836
+ open7 = false;
24802
25837
  controller.error(new Error("ACP adapter produced invalid output"));
24803
25838
  return;
24804
25839
  }
24805
25840
  byteLength += chunk.byteLength;
24806
25841
  if (byteLength > ACP_OUTPUT_LIMIT_BYTES) {
24807
- open6 = false;
25842
+ open7 = false;
24808
25843
  controller.error(new Error("ACP adapter output limit exceeded"));
24809
25844
  return;
24810
25845
  }
24811
25846
  controller.enqueue(new Uint8Array(chunk));
24812
25847
  });
24813
25848
  input2.once("end", () => {
24814
- if (open6) {
24815
- open6 = false;
25849
+ if (open7) {
25850
+ open7 = false;
24816
25851
  controller.close();
24817
25852
  }
24818
25853
  });
24819
25854
  input2.once("error", (error61) => {
24820
- if (open6) {
24821
- open6 = false;
25855
+ if (open7) {
25856
+ open7 = false;
24822
25857
  controller.error(error61);
24823
25858
  }
24824
25859
  });
24825
25860
  },
24826
25861
  cancel() {
24827
- open6 = false;
25862
+ open7 = false;
24828
25863
  }
24829
25864
  });
24830
25865
  }
@@ -24843,7 +25878,7 @@ function writableAcpStream(output2) {
24843
25878
  }
24844
25879
  });
24845
25880
  }
24846
- async function probeAcp(specification, agent, environment, defaultWorkspace, signal) {
25881
+ async function probeAcpReadiness(specification, agent, environment, defaultWorkspace, signal) {
24847
25882
  signal.throwIfAborted();
24848
25883
  const controller = new AbortController();
24849
25884
  let timedOut = false;
@@ -24887,13 +25922,13 @@ async function probeAcp(specification, agent, environment, defaultWorkspace, sig
24887
25922
  }
24888
25923
  };
24889
25924
  stderr.on("data", consumeStderr);
24890
- const connection = createAcpClient(new DiscoveryAcpHandler()).connect(
24891
- ndJsonStream2(writableAcpStream(stdin), readableAcpStream(stdout))
24892
- );
25925
+ const connection = createAcpClient(
25926
+ new DiscoveryAcpHandler()
25927
+ ).connect(ndJsonStream2(writableAcpStream(stdin), readableAcpStream(stdout)));
24893
25928
  try {
24894
25929
  const initialized = await Promise.race([
24895
25930
  connection.agent.request(
24896
- methods3.agent.initialize,
25931
+ methods4.agent.initialize,
24897
25932
  {
24898
25933
  clientCapabilities: {},
24899
25934
  clientInfo: { name: "mobius", version: "0.0.3" },
@@ -24930,7 +25965,7 @@ async function probeAcp(specification, agent, environment, defaultWorkspace, sig
24930
25965
  if (error61 instanceof AgentProbeError) {
24931
25966
  throw error61;
24932
25967
  }
24933
- if (error61 instanceof RequestError && error61.code === -32e3 && specification.authenticationCommand().length > 0) {
25968
+ if (error61 instanceof RequestError2 && error61.code === -32e3 && specification.authenticationCommand().length > 0) {
24934
25969
  throw new AgentProbeError(
24935
25970
  "authentication_required",
24936
25971
  "Agent authentication is required",
@@ -24951,6 +25986,8 @@ async function probeAcp(specification, agent, environment, defaultWorkspace, sig
24951
25986
  await stopProcessTree(child);
24952
25987
  }
24953
25988
  }
25989
+
25990
+ // src/agent-catalog/discover-agent.ts
24954
25991
  function probeFailure(specification, executableKind, error61) {
24955
25992
  if (error61 instanceof AgentProbeError) {
24956
25993
  if (error61.code === "authentication_required") {
@@ -24972,12 +26009,15 @@ function probeFailure(specification, executableKind, error61) {
24972
26009
  `${executableKind === "agent" ? "Agent" : "Adapter"} probe failed`
24973
26010
  );
24974
26011
  }
24975
- async function discoverSpecification(specification, options) {
24976
- options.signal.throwIfAborted();
26012
+ async function discoverAgent(specification, context) {
26013
+ context.signal.throwIfAborted();
24977
26014
  const [adapters, agents] = await Promise.all([
24978
- resolveAdapterExecutables(specification, options),
24979
- resolveAgentExecutables(specification, options)
26015
+ resolveAdapterExecutables(specification, context),
26016
+ resolveAgentExecutables(specification, context)
24980
26017
  ]);
26018
+ if (specification instanceof DirectAcpAgentDefinition && agents.length === 0) {
26019
+ return new MissingAgent(specification);
26020
+ }
24981
26021
  if (adapters.length === 0) {
24982
26022
  return new MissingAdapter(specification);
24983
26023
  }
@@ -24991,35 +26031,45 @@ async function discoverSpecification(specification, options) {
24991
26031
  agentVersion = await probeVersion(
24992
26032
  agent,
24993
26033
  specification.agentVersionArguments,
24994
- options.environment,
24995
- options.defaultWorkspace,
24996
- options.signal
26034
+ context.environment,
26035
+ context.defaultWorkspace,
26036
+ context.signal,
26037
+ specification.versionProbeTimeoutMilliseconds
24997
26038
  );
24998
26039
  } catch (error61) {
24999
- if (options.signal.aborted) {
25000
- options.signal.throwIfAborted();
26040
+ if (context.signal.aborted) {
26041
+ context.signal.throwIfAborted();
25001
26042
  }
25002
26043
  lastFailure = probeFailure(specification, "agent", error61);
25003
26044
  continue;
25004
26045
  }
25005
26046
  for (const adapter of adapters) {
26047
+ if (specification instanceof DirectAcpAgentDefinition && adapter.path !== agent.path) {
26048
+ continue;
26049
+ }
25006
26050
  let adapterVersion = "";
26051
+ let launchEnvironment;
25007
26052
  try {
26053
+ launchEnvironment = await specification.createLaunchEnvironment(
26054
+ agent,
26055
+ context
26056
+ );
25008
26057
  if (specification.adapterVersionArguments.length > 0) {
25009
26058
  adapterVersion = await probeVersion(
25010
26059
  adapter,
25011
26060
  specification.adapterVersionArguments,
25012
26061
  {
25013
- ...options.environment,
25014
- [specification.adapterEnvironmentVariable]: agent.path
26062
+ ...context.environment,
26063
+ ...launchEnvironment
25015
26064
  },
25016
- options.defaultWorkspace,
25017
- options.signal
26065
+ context.defaultWorkspace,
26066
+ context.signal,
26067
+ specification.versionProbeTimeoutMilliseconds
25018
26068
  );
25019
26069
  }
25020
26070
  } catch (error61) {
25021
- if (options.signal.aborted) {
25022
- options.signal.throwIfAborted();
26071
+ if (context.signal.aborted) {
26072
+ context.signal.throwIfAborted();
25023
26073
  }
25024
26074
  lastFailure = probeFailure(specification, "adapter", error61);
25025
26075
  continue;
@@ -25028,8 +26078,8 @@ async function discoverSpecification(specification, options) {
25028
26078
  specification.id,
25029
26079
  specification.label,
25030
26080
  adapter.path,
25031
- [],
25032
- { [specification.adapterEnvironmentVariable]: agent.path },
26081
+ specification.launchArguments,
26082
+ launchEnvironment,
25033
26083
  adapterVersion,
25034
26084
  agentVersion,
25035
26085
  adapter.identity,
@@ -25037,12 +26087,12 @@ async function discoverSpecification(specification, options) {
25037
26087
  specification.promptTimeoutMilliseconds
25038
26088
  );
25039
26089
  try {
25040
- const acpVersion = await probeAcp(
26090
+ const acpVersion = await probeAcpReadiness(
25041
26091
  specification,
25042
26092
  definition,
25043
- options.environment,
25044
- options.defaultWorkspace,
25045
- options.signal
26093
+ context.environment,
26094
+ context.defaultWorkspace,
26095
+ context.signal
25046
26096
  );
25047
26097
  const verifiedAdapterVersion = adapterVersion.length > 0 ? adapterVersion : acpVersion;
25048
26098
  if (verifiedAdapterVersion.length === 0) {
@@ -25057,8 +26107,8 @@ async function discoverSpecification(specification, options) {
25057
26107
  specification.id,
25058
26108
  specification.label,
25059
26109
  adapter.path,
25060
- [],
25061
- { [specification.adapterEnvironmentVariable]: agent.path },
26110
+ specification.launchArguments,
26111
+ launchEnvironment,
25062
26112
  verifiedAdapterVersion,
25063
26113
  agentVersion,
25064
26114
  adapter.identity,
@@ -25067,20 +26117,26 @@ async function discoverSpecification(specification, options) {
25067
26117
  )
25068
26118
  );
25069
26119
  } catch (error61) {
25070
- if (options.signal.aborted) {
25071
- options.signal.throwIfAborted();
26120
+ if (context.signal.aborted) {
26121
+ context.signal.throwIfAborted();
25072
26122
  }
25073
- lastFailure = probeFailure(specification, "adapter", error61);
26123
+ const failure = probeFailure(specification, "adapter", error61);
26124
+ if (failure instanceof AuthenticationRequiredAgent) {
26125
+ return failure;
26126
+ }
26127
+ lastFailure = failure;
25074
26128
  }
25075
26129
  }
25076
26130
  }
25077
26131
  return lastFailure ?? new IncompatibleAdapter(specification);
25078
26132
  }
26133
+
26134
+ // src/agent-catalog/discover-local-agents.ts
25079
26135
  async function discoverLocalAgentInventory(options) {
25080
26136
  const specifications = options.specifications ?? supportedLocalAgentSpecifications();
25081
26137
  const discoveries = await Promise.all(
25082
26138
  specifications.map(
25083
- async (specification) => await discoverSpecification(specification, options)
26139
+ async (specification) => await discoverAgent(specification, options)
25084
26140
  )
25085
26141
  );
25086
26142
  let grantedAgents = /* @__PURE__ */ new Set();
@@ -25098,10 +26154,6 @@ async function discoverLocalAgentInventory(options) {
25098
26154
  );
25099
26155
  }
25100
26156
 
25101
- // src/network/environment-proxy.ts
25102
- import { EnvHttpProxyAgent } from "undici";
25103
- var environmentProxyDispatcher = new EnvHttpProxyAgent();
25104
-
25105
26157
  // src/pairing/pair-local-machine.ts
25106
26158
  var PAIRING_TIMEOUT_MILLISECONDS = 2e4;
25107
26159
  var PAIRING_CODE_PATTERN = /^[A-HJ-NP-Z2-9]{4}(?:-[A-HJ-NP-Z2-9]{4}){4}$/;
@@ -25127,7 +26179,7 @@ var PairingClientError = class extends Error {
25127
26179
  this.name = "PairingClientError";
25128
26180
  }
25129
26181
  };
25130
- function isRecord6(value) {
26182
+ function isRecord7(value) {
25131
26183
  return typeof value === "object" && value !== null && !Array.isArray(value);
25132
26184
  }
25133
26185
  function hasExactKeys(value, expectedKeys) {
@@ -25240,9 +26292,9 @@ function parseChannelArgument(arguments_) {
25240
26292
  async function resolveDefaultWorkspace(path2) {
25241
26293
  const requestedWorkspace = resolve3(path2);
25242
26294
  try {
25243
- await mkdir2(requestedWorkspace, { recursive: true, mode: 448 });
25244
- const defaultWorkspace = await realpath3(requestedWorkspace);
25245
- 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);
25246
26298
  if (!metadata.isDirectory()) {
25247
26299
  throw new PairingClientError(
25248
26300
  "invalid_workspace",
@@ -25280,9 +26332,9 @@ async function readJsonResponse(response) {
25280
26332
  }
25281
26333
  }
25282
26334
  function readRelayError(value) {
25283
- if (isRecord6(value)) {
26335
+ if (isRecord7(value)) {
25284
26336
  const error61 = value["error"];
25285
- if (isRecord6(error61)) {
26337
+ if (isRecord7(error61)) {
25286
26338
  const code = error61["code"];
25287
26339
  const message = error61["message"];
25288
26340
  if (typeof code === "string" && typeof message === "string") {
@@ -25296,7 +26348,7 @@ function readRelayError(value) {
25296
26348
  );
25297
26349
  }
25298
26350
  function decodeClaimResponse(value) {
25299
- if (!isRecord6(value) || !hasExactKeys(value, CLAIM_RESPONSE_KEYS)) {
26351
+ if (!isRecord7(value) || !hasExactKeys(value, CLAIM_RESPONSE_KEYS)) {
25300
26352
  throw new PairingClientError(
25301
26353
  "invalid_relay_response",
25302
26354
  "The relay returned an invalid pairing response"
@@ -25318,10 +26370,10 @@ async function claimPairing(options, defaultWorkspace, localAgents, installableA
25318
26370
  id: agent.id,
25319
26371
  label: agent.label
25320
26372
  }));
25321
- const endpoint = new URL("/api/pairings/claim", options.relayOrigin);
26373
+ const endpoint = new URL("/mobius/api/pairings/claim", options.relayOrigin);
25322
26374
  let response;
25323
26375
  try {
25324
- response = await fetch(endpoint, {
26376
+ response = await fetch2(endpoint, {
25325
26377
  body: JSON.stringify({
25326
26378
  agents,
25327
26379
  installableAgents: installableAgents.map((agent) => ({
@@ -25355,14 +26407,14 @@ async function claimPairing(options, defaultWorkspace, localAgents, installableA
25355
26407
  return decodeClaimResponse(value);
25356
26408
  }
25357
26409
  async function persistConnection(channelId, relayOrigin, daemonToken, defaultWorkspace) {
25358
- const connectionsDirectory = join8(readStateDirectory(), "connections");
25359
- await mkdir2(connectionsDirectory, { mode: 448, recursive: true });
25360
- const connectionPath = join8(connectionsDirectory, `${channelId}.json`);
25361
- const temporaryPath = join8(
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(
25362
26414
  connectionsDirectory,
25363
26415
  `.${channelId}.${randomUUID()}.tmp`
25364
26416
  );
25365
- await writeFile(
26417
+ await writeFile2(
25366
26418
  temporaryPath,
25367
26419
  `${JSON.stringify(
25368
26420
  {
@@ -25377,11 +26429,11 @@ async function persistConnection(channelId, relayOrigin, daemonToken, defaultWor
25377
26429
  `,
25378
26430
  { flag: "wx", mode: 384 }
25379
26431
  );
25380
- await rename2(temporaryPath, connectionPath);
26432
+ await rename3(temporaryPath, connectionPath);
25381
26433
  return connectionPath;
25382
26434
  }
25383
26435
  function decodeSavedConnection(value, expectedChannelId) {
25384
- if (!isRecord6(value) || !hasExactKeys(value, SAVED_CONNECTION_KEYS)) {
26436
+ if (!isRecord7(value) || !hasExactKeys(value, SAVED_CONNECTION_KEYS)) {
25385
26437
  throw new PairingClientError(
25386
26438
  "invalid_connection",
25387
26439
  "The saved connection is invalid"
@@ -25405,13 +26457,13 @@ function decodeSavedConnection(value, expectedChannelId) {
25405
26457
  };
25406
26458
  }
25407
26459
  async function readSavedConnection(channelId) {
25408
- const connectionPath = join8(
26460
+ const connectionPath = join13(
25409
26461
  readStateDirectory(),
25410
26462
  "connections",
25411
26463
  `${channelId}.json`
25412
26464
  );
25413
26465
  let encoded = "";
25414
- const handle = await open4(connectionPath, "r");
26466
+ const handle = await open6(connectionPath, "r");
25415
26467
  try {
25416
26468
  const metadata = await handle.stat();
25417
26469
  if (!metadata.isFile() || metadata.size > MAX_CONNECTION_FILE_LENGTH) {
@@ -25455,12 +26507,12 @@ function assertInventoryUsable(inventory) {
25455
26507
  function buildPairedDaemon(connection, connectionPath, inventory) {
25456
26508
  assertInventoryUsable(inventory);
25457
26509
  const relayUrl = new URL(
25458
- `/api/channels/${encodeURIComponent(connection.channelId)}/daemon`,
26510
+ `/mobius/api/channels/${encodeURIComponent(connection.channelId)}/daemon`,
25459
26511
  connection.relayOrigin
25460
26512
  );
25461
26513
  relayUrl.protocol = relayUrl.protocol === "https:" ? "wss:" : "ws:";
25462
26514
  relayUrl.searchParams.set("token", connection.daemonToken);
25463
- const auditDatabasePath = join8(
26515
+ const auditDatabasePath = join13(
25464
26516
  readStateDirectory(),
25465
26517
  "audit",
25466
26518
  `${connection.channelId}.sqlite`
@@ -25519,7 +26571,7 @@ async function pairLocalMachine(arguments_, signal = new AbortController().signa
25519
26571
  }
25520
26572
  async function resumeLocalMachine(arguments_, signal = new AbortController().signal) {
25521
26573
  const channelId = parseChannelArgument(arguments_);
25522
- const connectionPath = join8(
26574
+ const connectionPath = join13(
25523
26575
  readStateDirectory(),
25524
26576
  "connections",
25525
26577
  `${channelId}.json`
@@ -25535,10 +26587,11 @@ async function resumeLocalMachine(arguments_, signal = new AbortController().sig
25535
26587
 
25536
26588
  // src/run-daemon.ts
25537
26589
  import { basename as basename3 } from "node:path";
26590
+ import { styleText } from "node:util";
25538
26591
  import { WebSocket as WebSocket2 } from "undici";
25539
26592
 
25540
26593
  // src/agent-catalog/publish-agent-catalog.ts
25541
- import { fetch as fetch2 } from "undici";
26594
+ import { fetch as fetch3 } from "undici";
25542
26595
  var CATALOG_UPDATE_TIMEOUT_MILLISECONDS = 2e4;
25543
26596
  var AgentCatalogPublishError = class extends Error {
25544
26597
  code = "agent_catalog_update_failed";
@@ -25565,7 +26618,7 @@ async function publishAgentCatalog(config2, signal) {
25565
26618
  let response;
25566
26619
  const catalog = config2.catalog.read();
25567
26620
  try {
25568
- response = await fetch2(catalogEndpoint(config2.relayUrl), {
26621
+ response = await fetch3(catalogEndpoint(config2.relayUrl), {
25569
26622
  body: JSON.stringify({
25570
26623
  agents: catalog.agents.map((agent) => ({
25571
26624
  id: agent.id,
@@ -25971,7 +27024,7 @@ var InstalledAutomaticAdapter = class {
25971
27024
  }
25972
27025
  };
25973
27026
  function shouldProvisionAdapter(unavailable, options) {
25974
- return AUTOMATIC_ADAPTER_FAILURE_CODES.has(unavailable.code) && options.environment[unavailable.specification.adapterOverrideVariable] === void 0 && unavailable.specification.supportsInstallation(
27027
+ return unavailable.specification instanceof BridgedAcpAgentDefinition && AUTOMATIC_ADAPTER_FAILURE_CODES.has(unavailable.code) && options.environment[unavailable.specification.adapterOverrideVariable] === void 0 && unavailable.specification.supportsInstallation(
25975
27028
  options.platform ?? process.platform,
25976
27029
  options.architecture ?? process.arch
25977
27030
  );
@@ -26015,6 +27068,10 @@ var AutomaticAdapterProvisioner = class {
26015
27068
  for (const unavailable of candidates) {
26016
27069
  signal.throwIfAborted();
26017
27070
  const specification = unavailable.specification;
27071
+ if (!(specification instanceof BridgedAcpAgentDefinition)) {
27072
+ attempts.push(null);
27073
+ continue;
27074
+ }
26018
27075
  const verifiedAgent = await findVerifiedAgentExecutable(
26019
27076
  specification,
26020
27077
  discoveryOptions(
@@ -26053,293 +27110,100 @@ var AutomaticAdapterProvisioner = class {
26053
27110
  specification.id,
26054
27111
  { adapterVersion: specification.adapterVersion }
26055
27112
  );
26056
- attempts.push(
26057
- new InstalledAutomaticAdapter(specification, requestId, executable)
26058
- );
26059
- } catch (error61) {
26060
- if (signal.aborted) {
26061
- this.#options.audit.record(
26062
- "agent_adapter_auto_install_cancelled",
26063
- requestId,
26064
- specification.id
26065
- );
26066
- signal.throwIfAborted();
26067
- }
26068
- this.#options.audit.record(
26069
- "agent_adapter_auto_install_failed",
26070
- requestId,
26071
- specification.id,
26072
- { code: stableFailureCode(error61) }
26073
- );
26074
- process.stderr.write(
26075
- `The pinned ACP adapter for ${specification.label} could not be installed automatically; the daemon will continue.
26076
- `
26077
- );
26078
- attempts.push(null);
26079
- }
26080
- }
26081
- signal.throwIfAborted();
26082
- const installed = attempts.filter(
26083
- (attempt) => attempt !== null
26084
- );
26085
- if (installed.length > 0) {
26086
- const verificationEnvironment = {
26087
- ...this.#options.environment
26088
- };
26089
- for (const attempt of installed) {
26090
- verificationEnvironment[attempt.specification.adapterOverrideVariable] = attempt.executable.path;
26091
- }
26092
- inventory = await discoverLocalAgentInventory(
26093
- discoveryOptions(
26094
- this.#options,
26095
- verificationEnvironment,
26096
- signal,
26097
- this.#specifications
26098
- )
26099
- );
26100
- }
26101
- this.#options.catalog.transition(
26102
- inventory.readyAgents(),
26103
- inventory.installable
26104
- );
26105
- for (const attempt of installed) {
26106
- const available = inventory.available.find(
26107
- (candidate) => candidate instanceof AvailableAgent && candidate.specification.id === attempt.specification.id
26108
- );
26109
- if (available === void 0) {
26110
- const unavailable = inventory.unavailable.find(
26111
- (candidate) => candidate.specification.id === attempt.specification.id
26112
- );
26113
- this.#options.audit.record(
26114
- "agent_adapter_auto_install_verification_failed",
26115
- attempt.requestId,
26116
- attempt.specification.id,
26117
- { code: unavailable?.code ?? "agent_verification_failed" }
26118
- );
26119
- continue;
26120
- }
26121
- this.#options.audit.record(
26122
- "agent_adapter_auto_install_verified",
26123
- attempt.requestId,
26124
- attempt.specification.id,
26125
- {
26126
- adapterVersion: available.agent.adapterVersion,
26127
- agentVersion: available.agent.agentVersion
26128
- }
26129
- );
26130
- process.stdout.write(
26131
- `${attempt.specification.label} ACP integration is ready.
26132
- `
26133
- );
26134
- }
26135
- return inventory;
26136
- };
26137
- };
26138
-
26139
- // src/agent-installation/fixed-installation-executor.ts
26140
- import { realpathSync as realpathSync2, statSync as statSync2 } from "node:fs";
26141
- import { resolve as resolve4 } from "node:path";
26142
-
26143
- // src/agent-installation/fixed-agent-install-recipes.ts
26144
- import { mkdir as mkdir3, mkdtemp as mkdtemp2, rm as rm2 } from "node:fs/promises";
26145
- import { join as join9 } from "node:path";
26146
-
26147
- // src/agent-installation/verified-download.ts
26148
- import { createHash } from "node:crypto";
26149
- import { open as open5, unlink } from "node:fs/promises";
26150
- import { fetch as fetch3 } from "undici";
26151
- var MAX_REDIRECTS = 4;
26152
- var REDIRECT_STATUSES = /* @__PURE__ */ new Set([301, 302, 303, 307, 308]);
26153
- var InstallerDownloadError = class extends Error {
26154
- code;
26155
- constructor(code, message, options = {}) {
26156
- super(message, options);
26157
- this.code = code;
26158
- this.name = "InstallerDownloadError";
26159
- }
26160
- };
26161
- var VerifiedDownload = class {
26162
- bytes;
26163
- sha256;
26164
- url;
26165
- constructor(url2, bytes, sha256) {
26166
- this.bytes = bytes;
26167
- this.sha256 = sha256;
26168
- this.url = url2;
26169
- }
26170
- };
26171
- var UndiciInstallerDownloadTransport = class {
26172
- get = async (url2, signal) => await fetch3(url2, {
26173
- dispatcher: environmentProxyDispatcher,
26174
- headers: {
26175
- accept: "text/plain, application/octet-stream;q=0.9",
26176
- "user-agent": "Mobius-Agent-Installer/0.0.3"
26177
- },
26178
- method: "GET",
26179
- redirect: "manual",
26180
- signal
26181
- });
26182
- };
26183
- function validateUrl(url2, allowedHosts) {
26184
- if (url2.protocol !== "https:" || url2.username.length > 0 || url2.password.length > 0 || url2.port.length > 0 || !allowedHosts.has(url2.hostname)) {
26185
- throw new InstallerDownloadError(
26186
- "installer_host_not_allowed",
26187
- "The installer download target is not allowed"
26188
- );
26189
- }
26190
- }
26191
- async function fetchInstaller(options, signal, transport) {
26192
- let url2 = new URL(options.url);
26193
- for (let redirectCount = 0; redirectCount <= MAX_REDIRECTS; redirectCount += 1) {
26194
- validateUrl(url2, options.allowedHosts);
26195
- const response = await transport.get(url2, signal);
26196
- if (!REDIRECT_STATUSES.has(response.status)) {
26197
- return { response, url: url2 };
26198
- }
26199
- await response.body?.cancel();
26200
- const location = response.headers.get("location");
26201
- if (location === null || redirectCount === MAX_REDIRECTS) {
26202
- throw new InstallerDownloadError(
26203
- "installer_redirect_invalid",
26204
- "The installer returned an invalid redirect"
26205
- );
26206
- }
26207
- let redirected;
26208
- try {
26209
- redirected = new URL(location, url2);
26210
- } catch (error61) {
26211
- throw new InstallerDownloadError(
26212
- "installer_redirect_invalid",
26213
- "The installer returned an invalid redirect",
26214
- { cause: error61 }
26215
- );
26216
- }
26217
- try {
26218
- validateUrl(redirected, options.allowedHosts);
26219
- } catch (error61) {
26220
- throw new InstallerDownloadError(
26221
- "installer_redirect_not_allowed",
26222
- "The installer redirect left the approved host allowlist",
26223
- { cause: error61 }
26224
- );
26225
- }
26226
- url2 = redirected;
26227
- }
26228
- throw new InstallerDownloadError(
26229
- "installer_redirect_invalid",
26230
- "The installer returned too many redirects"
26231
- );
26232
- }
26233
- async function writeCompleteChunk(handle, chunk) {
26234
- let offset = 0;
26235
- while (offset < chunk.byteLength) {
26236
- const written = await handle.write(
26237
- chunk,
26238
- offset,
26239
- chunk.byteLength - offset
26240
- );
26241
- if (written.bytesWritten < 1) {
26242
- throw new InstallerDownloadError(
26243
- "installer_write_failed",
26244
- "The verified installer could not be stored"
26245
- );
26246
- }
26247
- offset += written.bytesWritten;
26248
- }
26249
- }
26250
- async function downloadVerifiedFile(options, transport = new UndiciInstallerDownloadTransport()) {
26251
- options.signal.throwIfAborted();
26252
- const timeoutSignal = AbortSignal.timeout(options.timeoutMilliseconds);
26253
- const signal = AbortSignal.any([options.signal, timeoutSignal]);
26254
- let handle = null;
26255
- let responseBody = null;
26256
- try {
26257
- const fetched = await fetchInstaller(options, signal, transport);
26258
- responseBody = fetched.response.body;
26259
- if (!fetched.response.ok || fetched.response.body === null) {
26260
- throw new InstallerDownloadError(
26261
- "installer_download_failed",
26262
- "The approved installer could not be downloaded"
26263
- );
26264
- }
26265
- const contentLength = fetched.response.headers.get("content-length");
26266
- if (contentLength !== null) {
26267
- const declaredLength = Number(contentLength);
26268
- if (!Number.isSafeInteger(declaredLength) || declaredLength < 1 || declaredLength > options.maximumBytes) {
26269
- throw new InstallerDownloadError(
26270
- "installer_size_invalid",
26271
- "The installer size is outside the approved limit"
26272
- );
26273
- }
26274
- }
26275
- handle = await open5(options.destination, "wx", 384);
26276
- const digest = createHash("sha256");
26277
- const reader = fetched.response.body.getReader();
26278
- let bytes = 0;
26279
- try {
26280
- while (true) {
26281
- signal.throwIfAborted();
26282
- const chunk = await reader.read();
26283
- if (chunk.done) {
26284
- break;
26285
- }
26286
- bytes += chunk.value.byteLength;
26287
- if (bytes > options.maximumBytes) {
26288
- throw new InstallerDownloadError(
26289
- "installer_size_invalid",
26290
- "The installer exceeded the approved size limit"
27113
+ attempts.push(
27114
+ new InstalledAutomaticAdapter(specification, requestId, executable)
27115
+ );
27116
+ } catch (error61) {
27117
+ if (signal.aborted) {
27118
+ this.#options.audit.record(
27119
+ "agent_adapter_auto_install_cancelled",
27120
+ requestId,
27121
+ specification.id
26291
27122
  );
27123
+ signal.throwIfAborted();
26292
27124
  }
26293
- digest.update(chunk.value);
26294
- await writeCompleteChunk(handle, chunk.value);
27125
+ this.#options.audit.record(
27126
+ "agent_adapter_auto_install_failed",
27127
+ requestId,
27128
+ specification.id,
27129
+ { code: stableFailureCode(error61) }
27130
+ );
27131
+ process.stderr.write(
27132
+ `The pinned ACP adapter for ${specification.label} could not be installed automatically; the daemon will continue.
27133
+ `
27134
+ );
27135
+ attempts.push(null);
26295
27136
  }
26296
- } finally {
26297
- await reader.cancel().catch(() => void 0);
26298
- reader.releaseLock();
26299
27137
  }
26300
- if (bytes === 0) {
26301
- throw new InstallerDownloadError(
26302
- "installer_verification_failed",
26303
- "The downloaded installer is empty"
27138
+ signal.throwIfAborted();
27139
+ const installed = attempts.filter(
27140
+ (attempt) => attempt !== null
27141
+ );
27142
+ if (installed.length > 0) {
27143
+ const verificationEnvironment = {
27144
+ ...this.#options.environment
27145
+ };
27146
+ for (const attempt of installed) {
27147
+ verificationEnvironment[attempt.specification.adapterOverrideVariable] = attempt.executable.path;
27148
+ }
27149
+ inventory = await discoverLocalAgentInventory(
27150
+ discoveryOptions(
27151
+ this.#options,
27152
+ verificationEnvironment,
27153
+ signal,
27154
+ this.#specifications
27155
+ )
26304
27156
  );
26305
27157
  }
26306
- await handle.sync();
26307
- await handle.close();
26308
- handle = null;
26309
- return new VerifiedDownload(fetched.url, bytes, digest.digest("hex"));
26310
- } catch (error61) {
26311
- if (handle !== null) {
26312
- await handle.close().catch(() => void 0);
26313
- }
26314
- await unlink(options.destination).catch(() => void 0);
26315
- if (options.signal.aborted) {
26316
- options.signal.throwIfAborted();
26317
- }
26318
- if (timeoutSignal.aborted) {
26319
- throw new InstallerDownloadError(
26320
- "installer_download_timeout",
26321
- "The installer download timed out",
26322
- { cause: error61 }
27158
+ this.#options.catalog.transition(
27159
+ inventory.readyAgents(),
27160
+ inventory.installable
27161
+ );
27162
+ for (const attempt of installed) {
27163
+ const available = inventory.available.find(
27164
+ (candidate) => candidate instanceof AvailableAgent && candidate.specification.id === attempt.specification.id
27165
+ );
27166
+ if (available === void 0) {
27167
+ const unavailable = inventory.unavailable.find(
27168
+ (candidate) => candidate.specification.id === attempt.specification.id
27169
+ );
27170
+ this.#options.audit.record(
27171
+ "agent_adapter_auto_install_verification_failed",
27172
+ attempt.requestId,
27173
+ attempt.specification.id,
27174
+ { code: unavailable?.code ?? "agent_verification_failed" }
27175
+ );
27176
+ continue;
27177
+ }
27178
+ this.#options.audit.record(
27179
+ "agent_adapter_auto_install_verified",
27180
+ attempt.requestId,
27181
+ attempt.specification.id,
27182
+ {
27183
+ adapterVersion: available.agent.adapterVersion,
27184
+ agentVersion: available.agent.agentVersion
27185
+ }
27186
+ );
27187
+ process.stdout.write(
27188
+ `${attempt.specification.label} ACP integration is ready.
27189
+ `
26323
27190
  );
26324
27191
  }
26325
- if (error61 instanceof InstallerDownloadError) {
26326
- throw error61;
26327
- }
26328
- throw new InstallerDownloadError(
26329
- "installer_download_failed",
26330
- "The approved installer could not be downloaded",
26331
- { cause: error61 }
26332
- );
26333
- } finally {
26334
- await responseBody?.cancel().catch(() => void 0);
26335
- }
26336
- }
27192
+ return inventory;
27193
+ };
27194
+ };
27195
+
27196
+ // src/agent-installation/fixed-installation-executor.ts
27197
+ import { realpathSync as realpathSync2, statSync as statSync2 } from "node:fs";
27198
+ import { resolve as resolve4 } from "node:path";
26337
27199
 
26338
27200
  // src/agent-installation/fixed-agent-install-recipes.ts
27201
+ import { mkdir as mkdir4, mkdtemp as mkdtemp3, rm as rm3 } from "node:fs/promises";
27202
+ import { join as join14 } from "node:path";
26339
27203
  var INSTALLER_DOWNLOAD_LIMIT_BYTES = 1024 * 1024;
26340
27204
  var INSTALLER_DOWNLOAD_TIMEOUT_MILLISECONDS = 6e4;
26341
27205
  var AGENT_INSTALL_TIMEOUT_MILLISECONDS = 5 * 60 * 1e3;
26342
- var MINIMAL_PATH = "/usr/bin:/bin";
27206
+ var MINIMAL_PATH2 = "/usr/bin:/bin";
26343
27207
  var FixedAgentInstallRecipe = class {
26344
27208
  assertSupportedPlatform = () => {
26345
27209
  if (process.platform !== "darwin" && process.platform !== "linux" || process.arch !== "arm64" && process.arch !== "x64") {
@@ -26366,22 +27230,22 @@ var CodexInstallRecipe = class extends FixedAgentInstallRecipe {
26366
27230
  releaseChannel = "latest";
26367
27231
  install = async (options) => {
26368
27232
  this.assertSupportedPlatform();
26369
- const root = join9(options.stateDirectory, "agents", this.id);
26370
- const temporaryRoot = join9(options.stateDirectory, "temporary");
27233
+ const root = join14(options.stateDirectory, "agents", this.id);
27234
+ const temporaryRoot = join14(options.stateDirectory, "temporary");
26371
27235
  await Promise.all([
26372
- mkdir3(root, { mode: 448, recursive: true }),
26373
- mkdir3(temporaryRoot, { mode: 448, recursive: true })
27236
+ mkdir4(root, { mode: 448, recursive: true }),
27237
+ mkdir4(temporaryRoot, { mode: 448, recursive: true })
26374
27238
  ]);
26375
- const temporaryDirectory = await mkdtemp2(
26376
- join9(temporaryRoot, ".codex-install-")
27239
+ const temporaryDirectory = await mkdtemp3(
27240
+ join14(temporaryRoot, ".codex-install-")
26377
27241
  );
26378
- const installerPath = join9(temporaryDirectory, "install.sh");
26379
- const installDirectory = join9(root, "bin");
26380
- const codexHome = join9(root, "home");
27242
+ const installerPath = join14(temporaryDirectory, "install.sh");
27243
+ const installDirectory = join14(root, "bin");
27244
+ const codexHome = join14(root, "home");
26381
27245
  try {
26382
27246
  await Promise.all([
26383
- mkdir3(installDirectory, { mode: 448, recursive: true }),
26384
- mkdir3(codexHome, { mode: 448, recursive: true })
27247
+ mkdir4(installDirectory, { mode: 448, recursive: true }),
27248
+ mkdir4(codexHome, { mode: 448, recursive: true })
26385
27249
  ]);
26386
27250
  await options.report("downloading");
26387
27251
  const download = await downloadVerifiedFile({
@@ -26414,14 +27278,14 @@ var CodexInstallRecipe = class extends FixedAgentInstallRecipe {
26414
27278
  CODEX_NON_INTERACTIVE: "1",
26415
27279
  CODEX_RELEASE: this.releaseChannel,
26416
27280
  HOME: codexHome,
26417
- PATH: MINIMAL_PATH
27281
+ PATH: MINIMAL_PATH2
26418
27282
  },
26419
27283
  outputLimitBytes: 64 * 1024,
26420
27284
  signal: options.signal,
26421
27285
  timeoutMilliseconds: AGENT_INSTALL_TIMEOUT_MILLISECONDS
26422
27286
  });
26423
27287
  return await this.requireInstalledExecutable(
26424
- join9(installDirectory, "codex")
27288
+ join14(installDirectory, "codex")
26425
27289
  );
26426
27290
  } catch (error61) {
26427
27291
  if (options.signal.aborted) {
@@ -26435,7 +27299,7 @@ var CodexInstallRecipe = class extends FixedAgentInstallRecipe {
26435
27299
  "The fixed Codex installation recipe failed"
26436
27300
  );
26437
27301
  } finally {
26438
- await rm2(temporaryDirectory, { force: true, recursive: true });
27302
+ await rm3(temporaryDirectory, { force: true, recursive: true });
26439
27303
  }
26440
27304
  };
26441
27305
  };
@@ -26445,17 +27309,17 @@ var ClaudeCodeInstallRecipe = class extends FixedAgentInstallRecipe {
26445
27309
  releaseChannel = "stable";
26446
27310
  install = async (options) => {
26447
27311
  this.assertSupportedPlatform();
26448
- const root = join9(options.stateDirectory, "agents", this.id);
26449
- const managedHome = join9(root, "home");
26450
- const temporaryRoot = join9(options.stateDirectory, "temporary");
27312
+ const root = join14(options.stateDirectory, "agents", this.id);
27313
+ const managedHome = join14(root, "home");
27314
+ const temporaryRoot = join14(options.stateDirectory, "temporary");
26451
27315
  await Promise.all([
26452
- mkdir3(managedHome, { mode: 448, recursive: true }),
26453
- mkdir3(temporaryRoot, { mode: 448, recursive: true })
27316
+ mkdir4(managedHome, { mode: 448, recursive: true }),
27317
+ mkdir4(temporaryRoot, { mode: 448, recursive: true })
26454
27318
  ]);
26455
- const temporaryDirectory = await mkdtemp2(
26456
- join9(temporaryRoot, ".claude-install-")
27319
+ const temporaryDirectory = await mkdtemp3(
27320
+ join14(temporaryRoot, ".claude-install-")
26457
27321
  );
26458
- const installerPath = join9(temporaryDirectory, "install.sh");
27322
+ const installerPath = join14(temporaryDirectory, "install.sh");
26459
27323
  try {
26460
27324
  await options.report("downloading");
26461
27325
  const download = await downloadVerifiedFile({
@@ -26484,7 +27348,7 @@ var ClaudeCodeInstallRecipe = class extends FixedAgentInstallRecipe {
26484
27348
  cwd: temporaryDirectory,
26485
27349
  environment: {
26486
27350
  HOME: managedHome,
26487
- PATH: MINIMAL_PATH,
27351
+ PATH: MINIMAL_PATH2,
26488
27352
  SHELL: "/bin/bash"
26489
27353
  },
26490
27354
  outputLimitBytes: 64 * 1024,
@@ -26492,7 +27356,7 @@ var ClaudeCodeInstallRecipe = class extends FixedAgentInstallRecipe {
26492
27356
  timeoutMilliseconds: AGENT_INSTALL_TIMEOUT_MILLISECONDS
26493
27357
  });
26494
27358
  return await this.requireInstalledExecutable(
26495
- join9(managedHome, ".local", "bin", "claude")
27359
+ join14(managedHome, ".local", "bin", "claude")
26496
27360
  );
26497
27361
  } catch (error61) {
26498
27362
  if (options.signal.aborted) {
@@ -26506,7 +27370,7 @@ var ClaudeCodeInstallRecipe = class extends FixedAgentInstallRecipe {
26506
27370
  "The fixed Claude Code installation recipe failed"
26507
27371
  );
26508
27372
  } finally {
26509
- await rm2(temporaryDirectory, { force: true, recursive: true });
27373
+ await rm3(temporaryDirectory, { force: true, recursive: true });
26510
27374
  }
26511
27375
  };
26512
27376
  };
@@ -26526,7 +27390,7 @@ var PiInstallRecipe = class extends FixedAgentInstallRecipe {
26526
27390
  await options.report("verifying");
26527
27391
  await options.report("installing_agent");
26528
27392
  const executable = await this.#npmInstaller.install(
26529
- join9(
27393
+ join14(
26530
27394
  options.stateDirectory,
26531
27395
  "agents",
26532
27396
  this.id,
@@ -26581,11 +27445,161 @@ var PiInstallRecipe = class extends FixedAgentInstallRecipe {
26581
27445
  }
26582
27446
  };
26583
27447
  };
27448
+ var DeepSeekHarnessInstallRecipe = class extends FixedAgentInstallRecipe {
27449
+ #npmInstaller;
27450
+ id = "deepseek-harness";
27451
+ label = "DeepSeek Harness";
27452
+ releaseChannel = DEEPSEEK_HARNESS_PACKAGE.version;
27453
+ constructor(npmInstaller = new ManagedNpmPackageInstaller()) {
27454
+ super();
27455
+ this.#npmInstaller = npmInstaller;
27456
+ }
27457
+ install = async (options) => {
27458
+ this.assertSupportedPlatform();
27459
+ try {
27460
+ const managedHome = join14(
27461
+ options.stateDirectory,
27462
+ "agents",
27463
+ this.id,
27464
+ "home"
27465
+ );
27466
+ await mkdir4(managedHome, { mode: 448, recursive: true });
27467
+ await options.report("downloading");
27468
+ await options.report("verifying");
27469
+ await options.report("installing_agent");
27470
+ const executable = await this.#npmInstaller.install(
27471
+ join14(
27472
+ options.stateDirectory,
27473
+ "agents",
27474
+ this.id,
27475
+ DEEPSEEK_HARNESS_PACKAGE.version
27476
+ ),
27477
+ DEEPSEEK_HARNESS_PACKAGE,
27478
+ options.environment,
27479
+ options.signal
27480
+ );
27481
+ options.audit.record(
27482
+ "agent_npm_package_verified",
27483
+ options.requestId,
27484
+ this.id,
27485
+ {
27486
+ integrity: DEEPSEEK_HARNESS_PACKAGE.integrity,
27487
+ package: DEEPSEEK_HARNESS_PACKAGE.packageName,
27488
+ version: DEEPSEEK_HARNESS_PACKAGE.version
27489
+ }
27490
+ );
27491
+ return executable;
27492
+ } catch (error61) {
27493
+ if (options.signal.aborted) {
27494
+ options.signal.throwIfAborted();
27495
+ }
27496
+ if (error61 instanceof ManagedNpmPackageError) {
27497
+ if (error61.code === "managed_package_verification_failed") {
27498
+ throw new InstallationManagerError(
27499
+ "agent_verification_failed",
27500
+ "The managed DeepSeek Harness package did not match its pinned artifact",
27501
+ { cause: error61 }
27502
+ );
27503
+ }
27504
+ if (error61.code === "managed_package_publish_failed") {
27505
+ throw new InstallationManagerError(
27506
+ "agent_publish_failed",
27507
+ "The managed DeepSeek Harness package could not be published",
27508
+ { cause: error61 }
27509
+ );
27510
+ }
27511
+ throw new InstallationManagerError(error61.code, error61.message, {
27512
+ cause: error61
27513
+ });
27514
+ }
27515
+ if (error61 instanceof InstallationManagerError) {
27516
+ throw error61;
27517
+ }
27518
+ throw new InstallationManagerError(
27519
+ "agent_install_failed",
27520
+ "The fixed DeepSeek Harness installation recipe failed",
27521
+ { cause: error61 }
27522
+ );
27523
+ }
27524
+ };
27525
+ };
27526
+ var OpenCodeInstallRecipe = class extends FixedAgentInstallRecipe {
27527
+ #archiveInstaller;
27528
+ id = "opencode";
27529
+ label = "OpenCode";
27530
+ releaseChannel = OPENCODE_MANAGED_VERSION;
27531
+ constructor(archiveInstaller = new ManagedAgentArchiveInstaller()) {
27532
+ super();
27533
+ this.#archiveInstaller = archiveInstaller;
27534
+ }
27535
+ install = async (options) => {
27536
+ this.assertSupportedPlatform();
27537
+ const definition = openCodeManagedArchive(process.platform, process.arch);
27538
+ try {
27539
+ await options.report("downloading");
27540
+ await options.report("verifying");
27541
+ await options.report("installing_agent");
27542
+ const executable = await this.#archiveInstaller.install(
27543
+ join14(
27544
+ options.stateDirectory,
27545
+ "agents",
27546
+ this.id,
27547
+ OPENCODE_MANAGED_VERSION
27548
+ ),
27549
+ definition,
27550
+ options.signal
27551
+ );
27552
+ options.audit.record(
27553
+ "agent_archive_verified",
27554
+ options.requestId,
27555
+ this.id,
27556
+ {
27557
+ sha256: definition.archiveSha256,
27558
+ version: definition.version
27559
+ }
27560
+ );
27561
+ return executable;
27562
+ } catch (error61) {
27563
+ if (options.signal.aborted) {
27564
+ options.signal.throwIfAborted();
27565
+ }
27566
+ if (error61 instanceof ManagedAgentArchiveError) {
27567
+ if (error61.code === "managed_archive_verification_failed") {
27568
+ throw new InstallationManagerError(
27569
+ "agent_verification_failed",
27570
+ "The managed OpenCode archive did not match its pinned artifact",
27571
+ { cause: error61 }
27572
+ );
27573
+ }
27574
+ if (error61.code === "managed_archive_publish_failed") {
27575
+ throw new InstallationManagerError(
27576
+ "agent_publish_failed",
27577
+ "The managed OpenCode archive could not be published",
27578
+ { cause: error61 }
27579
+ );
27580
+ }
27581
+ throw new InstallationManagerError(error61.code, error61.message, {
27582
+ cause: error61
27583
+ });
27584
+ }
27585
+ if (error61 instanceof InstallationManagerError) {
27586
+ throw error61;
27587
+ }
27588
+ throw new InstallationManagerError(
27589
+ "agent_install_failed",
27590
+ "The fixed OpenCode installation recipe failed",
27591
+ { cause: error61 }
27592
+ );
27593
+ }
27594
+ };
27595
+ };
26584
27596
  function fixedAgentInstallRecipes() {
26585
27597
  return Object.freeze([
26586
27598
  new CodexInstallRecipe(),
26587
27599
  new ClaudeCodeInstallRecipe(),
26588
- new PiInstallRecipe()
27600
+ new PiInstallRecipe(),
27601
+ new DeepSeekHarnessInstallRecipe(),
27602
+ new OpenCodeInstallRecipe()
26589
27603
  ]);
26590
27604
  }
26591
27605
 
@@ -26723,12 +27737,15 @@ var FixedInstallationExecutor = class {
26723
27737
  });
26724
27738
  installedAgent = true;
26725
27739
  }
26726
- let adapter = await resolveAdapterExecutable(
26727
- specification,
26728
- discoveryOptions2
26729
- );
27740
+ let adapter = specification instanceof DirectAcpAgentDefinition ? agent : await resolveAdapterExecutable(specification, discoveryOptions2);
26730
27741
  let installedAdapter = false;
26731
27742
  if (adapter === null) {
27743
+ if (!(specification instanceof BridgedAcpAgentDefinition)) {
27744
+ throw new InstallationManagerError(
27745
+ "agent_verification_failed",
27746
+ "The direct Agent executable is unavailable"
27747
+ );
27748
+ }
26732
27749
  await report("installing_adapter");
26733
27750
  adapter = await this.#adapterInstaller.install(specification, signal);
26734
27751
  installedAdapter = true;
@@ -26785,7 +27802,7 @@ var FixedInstallationExecutor = class {
26785
27802
  "The complete Agent ACP path did not pass verification"
26786
27803
  );
26787
27804
  }
26788
- if (!installedAdapter && requiresAdapterReplacement(unavailable.code)) {
27805
+ if (!installedAdapter && specification instanceof BridgedAcpAgentDefinition && requiresAdapterReplacement(unavailable.code)) {
26789
27806
  await report("installing_adapter");
26790
27807
  adapter = await this.#adapterInstaller.install(specification, signal);
26791
27808
  installedAdapter = true;
@@ -26804,6 +27821,9 @@ var FixedInstallationExecutor = class {
26804
27821
  stateDirectory: this.#stateDirectory
26805
27822
  });
26806
27823
  installedAgent = true;
27824
+ if (specification instanceof DirectAcpAgentDefinition) {
27825
+ adapter = agent;
27826
+ }
26807
27827
  continue;
26808
27828
  }
26809
27829
  throw new InstallationManagerError(
@@ -26856,15 +27876,15 @@ Mobius Web requested installation of ${label} (${requestId}). Allow this fixed u
26856
27876
  };
26857
27877
 
26858
27878
  // src/authorization/workspace-directory.ts
26859
- import { readdir, realpath as realpath4, stat as stat4 } from "node:fs/promises";
27879
+ import { readdir, realpath as realpath6, stat as stat6 } from "node:fs/promises";
26860
27880
  import { homedir as homedir2 } from "node:os";
26861
27881
  import {
26862
27882
  basename as basename2,
26863
- dirname as dirname4,
26864
- isAbsolute as isAbsolute3,
26865
- join as join10,
26866
- normalize,
26867
- relative as relative2
27883
+ dirname as dirname5,
27884
+ isAbsolute as isAbsolute5,
27885
+ join as join15,
27886
+ normalize as normalize2,
27887
+ relative as relative3
26868
27888
  } from "node:path";
26869
27889
  var WorkspaceDirectoryListing = class {
26870
27890
  directoryId;
@@ -26892,7 +27912,7 @@ function decodePath(value, prefix) {
26892
27912
  if (encoded.length === 0 || encoded.length > 2e3 || !/^[a-zA-Z0-9_-]+$/.test(encoded))
26893
27913
  throw new LocalAuthorizationError("The directory identifier is invalid");
26894
27914
  const decoded = Buffer.from(encoded, "base64url").toString("utf8");
26895
- if (Buffer.from(decoded, "utf8").toString("base64url") !== encoded || decoded.includes("\0") || normalize(decoded) !== decoded)
27915
+ if (Buffer.from(decoded, "utf8").toString("base64url") !== encoded || decoded.includes("\0") || normalize2(decoded) !== decoded)
26896
27916
  throw new LocalAuthorizationError("The directory identifier is invalid");
26897
27917
  return decoded;
26898
27918
  }
@@ -26914,20 +27934,20 @@ var WorkspaceDirectoryService = class {
26914
27934
  if (id === "home") return homedir2();
26915
27935
  if (id.startsWith("path-")) {
26916
27936
  const path2 = decodePath(id, "path-");
26917
- if (isAbsolute3(path2)) return path2;
27937
+ if (isAbsolute5(path2)) return path2;
26918
27938
  }
26919
27939
  throw new LocalAuthorizationError("The directory identifier is invalid");
26920
27940
  };
26921
27941
  resolvePath = async (requested, signal) => {
26922
27942
  signal.throwIfAborted();
26923
- if (!isAbsolute3(requested) || requested.includes("\0") || normalize(requested) !== requested)
27943
+ if (!isAbsolute5(requested) || requested.includes("\0") || normalize2(requested) !== requested)
26924
27944
  throw new LocalAuthorizationError("The local directory path is invalid");
26925
27945
  try {
26926
- const target = await realpath4(requested);
27946
+ const target = await realpath6(requested);
26927
27947
  signal.throwIfAborted();
26928
- const metadata = await stat4(target);
27948
+ const metadata = await stat6(target);
26929
27949
  signal.throwIfAborted();
26930
- if (!isAbsolute3(target) || normalize(target) !== target || !metadata.isDirectory())
27950
+ if (!isAbsolute5(target) || normalize2(target) !== target || !metadata.isDirectory())
26931
27951
  throw new LocalAuthorizationError(
26932
27952
  "The selected location is not a directory"
26933
27953
  );
@@ -26942,8 +27962,8 @@ var WorkspaceDirectoryService = class {
26942
27962
  }
26943
27963
  };
26944
27964
  label = (path2) => {
26945
- const suffix = relative2(homedir2(), path2);
26946
- return suffix === "" ? "~" : !isAbsolute3(suffix) && suffix !== ".." && !suffix.startsWith(`..${process.platform === "win32" ? "\\" : "/"}`) ? `~/${suffix.replaceAll("\\", "/")}` : path2;
27965
+ const suffix = relative3(homedir2(), path2);
27966
+ return suffix === "" ? "~" : !isAbsolute5(suffix) && suffix !== ".." && !suffix.startsWith(`..${process.platform === "win32" ? "\\" : "/"}`) ? `~/${suffix.replaceAll("\\", "/")}` : path2;
26947
27967
  };
26948
27968
  identify = async (bindingId, requestedPath, signal) => {
26949
27969
  this.authorizeMachine(bindingId);
@@ -26971,7 +27991,7 @@ var WorkspaceDirectoryService = class {
26971
27991
  continue;
26972
27992
  }
26973
27993
  try {
26974
- const path2 = await this.resolvePath(join10(target, child.name), signal);
27994
+ const path2 = await this.resolvePath(join15(target, child.name), signal);
26975
27995
  entries.push({ directoryId: encodePath(path2), name: child.name });
26976
27996
  } catch (cause) {
26977
27997
  signal.throwIfAborted();
@@ -26979,7 +27999,7 @@ var WorkspaceDirectoryService = class {
26979
27999
  }
26980
28000
  }
26981
28001
  entries.sort((a, b) => a.name.localeCompare(b.name));
26982
- const parent = dirname4(target);
28002
+ const parent = dirname5(target);
26983
28003
  return new WorkspaceDirectoryListing(
26984
28004
  id,
26985
28005
  this.label(target),
@@ -27094,7 +28114,8 @@ function decodeHistory(thread, value) {
27094
28114
  status: "available",
27095
28115
  messages,
27096
28116
  truncated,
27097
- coveredCommandIds: []
28117
+ coveredCommandIds: [],
28118
+ coveredMessageIds: []
27098
28119
  }
27099
28120
  };
27100
28121
  }
@@ -27771,7 +28792,7 @@ var RelayConnectionLiveness = class {
27771
28792
 
27772
28793
  // src/relay-connection/session-event-outbox.ts
27773
28794
  import { mkdirSync as mkdirSync3 } from "node:fs";
27774
- import { dirname as dirname5 } from "node:path";
28795
+ import { dirname as dirname6 } from "node:path";
27775
28796
  import { DatabaseSync as DatabaseSync3 } from "node:sqlite";
27776
28797
  function readPendingEnvelope(row) {
27777
28798
  if (typeof row !== "object" || row === null || Array.isArray(row)) {
@@ -27786,7 +28807,7 @@ function readPendingEnvelope(row) {
27786
28807
  var SessionEventOutbox = class {
27787
28808
  #database;
27788
28809
  constructor(path2) {
27789
- mkdirSync3(dirname5(path2), { recursive: true });
28810
+ mkdirSync3(dirname6(path2), { recursive: true });
27790
28811
  this.#database = new DatabaseSync3(path2);
27791
28812
  this.#database.exec(`
27792
28813
  CREATE TABLE IF NOT EXISTS relay_session_event_outbox (
@@ -28530,10 +29551,11 @@ function waitForRelayRetry(signal, timer) {
28530
29551
  signal.addEventListener("abort", finish, { once: true });
28531
29552
  });
28532
29553
  }
28533
- async function runRelayConnection(config2, directories, audit, sessions, installations, installationObserver, nativeSessions, outbox, signal, timer) {
29554
+ async function runRelayConnection(config2, directories, audit, sessions, installations, installationObserver, nativeSessions, outbox, onConnected, signal, timer) {
28534
29555
  const relayUrl = new URL(config2.relayUrl);
28535
29556
  relayUrl.searchParams.set("liveness", "1");
28536
29557
  const socket = await connectRelay(relayUrl, signal);
29558
+ onConnected();
28537
29559
  const activeTurns = /* @__PURE__ */ new Map();
28538
29560
  const activeAttemptIds = /* @__PURE__ */ new Map();
28539
29561
  const connectionController = new AbortController();
@@ -28968,6 +29990,24 @@ async function runDaemon(config2, audit, signal, timer = systemDaemonTimer) {
28968
29990
  installationAudit
28969
29991
  );
28970
29992
  let retryAnnounced = false;
29993
+ let connectionAnnounced = false;
29994
+ const announceConnection = () => {
29995
+ if (connectionAnnounced) {
29996
+ return;
29997
+ }
29998
+ connectionAnnounced = true;
29999
+ const reconnectCommand = `npx --yes @moxt-ai/mobius start --channel ${config2.channelId}`;
30000
+ process.stdout.write("Mobius daemon connected to the relay.\n\n");
30001
+ process.stdout.write(
30002
+ `${styleText(
30003
+ ["bold", "yellow"],
30004
+ `Reconnect this channel later:
30005
+ ${reconnectCommand}`
30006
+ )}
30007
+
30008
+ `
30009
+ );
30010
+ };
28971
30011
  try {
28972
30012
  while (!signal.aborted) {
28973
30013
  try {
@@ -28981,6 +30021,7 @@ async function runDaemon(config2, audit, signal, timer = systemDaemonTimer) {
28981
30021
  installationObserver,
28982
30022
  nativeSessions,
28983
30023
  outbox,
30024
+ announceConnection,
28984
30025
  signal,
28985
30026
  timer
28986
30027
  );