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