@moxt-ai/mobius 0.0.10 → 0.0.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 +99 -24
- 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 +1 -1
- 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 -101
- package/dist/agent-catalog/discover-local-agents.d.ts.map +1 -1
- package/dist/agent-catalog/discover-local-agents.js +11 -564
- 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-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 +18 -0
- package/dist/agent-installation/fixed-agent-install-recipes.d.ts.map +1 -1
- package/dist/agent-installation/fixed-agent-install-recipes.js +97 -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 +17 -3
- package/dist/agent-installation/fixed-installation-executor.js.map +1 -1
- package/dist/agent-installation/managed-adapter-installer.d.ts +4 -4
- package/dist/agent-installation/managed-adapter-installer.d.ts.map +1 -1
- 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 +3 -0
- package/dist/agent-installation/managed-npm-package.d.ts.map +1 -1
- package/dist/agent-installation/managed-npm-package.js +55 -24
- package/dist/agent-installation/managed-npm-package.js.map +1 -1
- 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/cli.js +2353 -1314
- package/dist/cli.js.map +4 -4
- package/dist/config.js +1 -1
- package/dist/config.js.map +1 -1
- package/dist/index.js +1802 -761
- 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/pairing/pair-local-machine.js +2 -2
- package/dist/pairing/pair-local-machine.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/dist/run-daemon.d.ts.map +1 -1
- package/dist/run-daemon.js +14 -2
- package/dist/run-daemon.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"
|
|
@@ -499,7 +628,7 @@ function createDaemonConfig(connection, agents = [], installableAgents = []) {
|
|
|
499
628
|
function loadDaemonConfig() {
|
|
500
629
|
const relayUrl = new URL(
|
|
501
630
|
// biome-ignore lint/complexity/useLiteralKeys: Environment variables use an index signature.
|
|
502
|
-
process.env["MOBIUS_RELAY_URL"] ?? "ws://127.0.0.1:8787/api/channels/local/daemon"
|
|
631
|
+
process.env["MOBIUS_RELAY_URL"] ?? "ws://127.0.0.1:8787/mobius/api/channels/local/daemon"
|
|
503
632
|
);
|
|
504
633
|
relayUrl.searchParams.set(
|
|
505
634
|
"token",
|
|
@@ -532,7 +661,8 @@ import { spawn as spawn2 } from "node:child_process";
|
|
|
532
661
|
import {
|
|
533
662
|
methods as methods2,
|
|
534
663
|
ndJsonStream,
|
|
535
|
-
PROTOCOL_VERSION
|
|
664
|
+
PROTOCOL_VERSION,
|
|
665
|
+
RequestError
|
|
536
666
|
} from "@agentclientprotocol/sdk";
|
|
537
667
|
|
|
538
668
|
// ../../node_modules/.pnpm/zod@4.5.4/node_modules/zod/v4/classic/external.js
|
|
@@ -20307,7 +20437,10 @@ var sessionHistorySchema = external_exports.discriminatedUnion("status", [
|
|
|
20307
20437
|
status: external_exports.literal("available"),
|
|
20308
20438
|
messages: external_exports.array(historyMessage).max(SESSION_HISTORY_MESSAGE_LIMIT).readonly(),
|
|
20309
20439
|
truncated: external_exports.boolean(),
|
|
20310
|
-
coveredCommandIds: external_exports.array(external_exports.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/)).max(1e4).readonly()
|
|
20440
|
+
coveredCommandIds: external_exports.array(external_exports.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/)).max(1e4).readonly(),
|
|
20441
|
+
coveredMessageIds: external_exports.array(
|
|
20442
|
+
external_exports.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}:(?:user|agent)$/)
|
|
20443
|
+
).max(2e4).readonly().default([])
|
|
20311
20444
|
}).readonly(),
|
|
20312
20445
|
external_exports.strictObject({ status: external_exports.literal("unavailable") }).readonly()
|
|
20313
20446
|
]).refine(
|
|
@@ -21546,7 +21679,8 @@ var AcpHistoryReplay = class {
|
|
|
21546
21679
|
status: "available",
|
|
21547
21680
|
messages: [...this.#messages],
|
|
21548
21681
|
truncated: this.#truncated,
|
|
21549
|
-
coveredCommandIds: []
|
|
21682
|
+
coveredCommandIds: [],
|
|
21683
|
+
coveredMessageIds: []
|
|
21550
21684
|
});
|
|
21551
21685
|
};
|
|
21552
21686
|
|
|
@@ -21762,6 +21896,8 @@ var SqliteAcpSessionStore = class {
|
|
|
21762
21896
|
|
|
21763
21897
|
// src/acp/session-manager.ts
|
|
21764
21898
|
var PROCESS_STOP_TIMEOUT_MILLISECONDS = 1e3;
|
|
21899
|
+
var MAX_PRE_SESSION_UPDATES = 100;
|
|
21900
|
+
var MAX_PRE_SESSION_UPDATE_BYTES = 1024 * 1024;
|
|
21765
21901
|
var SESSION_CONTROL_COMMAND_ID = "session-control";
|
|
21766
21902
|
var NullAcpSessionObserver = class {
|
|
21767
21903
|
onCommands = () => Promise.resolve();
|
|
@@ -22370,8 +22506,11 @@ var AcpProcessSession = class _AcpProcessSession {
|
|
|
22370
22506
|
#mobiusSessionId;
|
|
22371
22507
|
#pendingElicitations = /* @__PURE__ */ new Map();
|
|
22372
22508
|
#pendingPermissions = /* @__PURE__ */ new Map();
|
|
22509
|
+
#preSessionUpdates = [];
|
|
22373
22510
|
#processExit;
|
|
22374
22511
|
#store;
|
|
22512
|
+
#verifiedAgentVersion;
|
|
22513
|
+
#preSessionUpdateBytes = 0;
|
|
22375
22514
|
#agentName = "";
|
|
22376
22515
|
#agentVersion = "";
|
|
22377
22516
|
#capabilities = {
|
|
@@ -22405,6 +22544,7 @@ var AcpProcessSession = class _AcpProcessSession {
|
|
|
22405
22544
|
this.#getObserver = getObserver;
|
|
22406
22545
|
this.#mobiusSessionId = mobiusSessionId;
|
|
22407
22546
|
this.#store = store;
|
|
22547
|
+
this.#verifiedAgentVersion = agent.agentVersion;
|
|
22408
22548
|
this.#child = spawn2(agent.adapterPath, [...agent.arguments], {
|
|
22409
22549
|
cwd,
|
|
22410
22550
|
detached: process.platform !== "win32",
|
|
@@ -22560,7 +22700,10 @@ var AcpProcessSession = class _AcpProcessSession {
|
|
|
22560
22700
|
initialized.agentInfo?.title ?? initialized.agentInfo?.name ?? this.#agentId,
|
|
22561
22701
|
255
|
|
22562
22702
|
);
|
|
22563
|
-
this.#agentVersion = truncate2(
|
|
22703
|
+
this.#agentVersion = truncate2(
|
|
22704
|
+
this.#verifiedAgentVersion.length > 0 ? this.#verifiedAgentVersion : initialized.agentInfo?.version ?? "",
|
|
22705
|
+
128
|
|
22706
|
+
);
|
|
22564
22707
|
}
|
|
22565
22708
|
initialize = async (signal, origin) => {
|
|
22566
22709
|
await this.#initializeAgent(signal);
|
|
@@ -22606,7 +22749,7 @@ var AcpProcessSession = class _AcpProcessSession {
|
|
|
22606
22749
|
"ACP agent exited while forking a session",
|
|
22607
22750
|
signal
|
|
22608
22751
|
);
|
|
22609
|
-
this
|
|
22752
|
+
this.selectNativeSession(forked.sessionId);
|
|
22610
22753
|
if (this.#nativeSessionId === origin.nativeSessionId || this.#store.findNative(this.#agentId, this.#nativeSessionId).length > 0) {
|
|
22611
22754
|
throw new AcpExecutionError(
|
|
22612
22755
|
"The Agent did not create an independent fork",
|
|
@@ -22621,7 +22764,7 @@ var AcpProcessSession = class _AcpProcessSession {
|
|
|
22621
22764
|
stored.session.additionalDirectories,
|
|
22622
22765
|
this.#additionalDirectories
|
|
22623
22766
|
)) {
|
|
22624
|
-
this
|
|
22767
|
+
this.selectNativeSession(stored.session.nativeSessionId);
|
|
22625
22768
|
this.#prompted = stored.session.prompted;
|
|
22626
22769
|
this.#restored = true;
|
|
22627
22770
|
if (this.#capabilities.resumeSession) {
|
|
@@ -22691,7 +22834,7 @@ var AcpProcessSession = class _AcpProcessSession {
|
|
|
22691
22834
|
"ACP agent exited while starting a session",
|
|
22692
22835
|
signal
|
|
22693
22836
|
);
|
|
22694
|
-
this
|
|
22837
|
+
this.selectNativeSession(created.sessionId);
|
|
22695
22838
|
lifecycleResponse = created;
|
|
22696
22839
|
}
|
|
22697
22840
|
const lifecycleRecord = isRecord3(lifecycleResponse) ? lifecycleResponse : {};
|
|
@@ -22953,13 +23096,17 @@ var AcpProcessSession = class _AcpProcessSession {
|
|
|
22953
23096
|
}
|
|
22954
23097
|
};
|
|
22955
23098
|
cancel = async () => {
|
|
22956
|
-
await this
|
|
22957
|
-
|
|
22958
|
-
|
|
23099
|
+
const capturedProcesses = await captureProcessTree(this.#child);
|
|
23100
|
+
try {
|
|
23101
|
+
await this.cancelPendingInteractions();
|
|
23102
|
+
if (this.#turn.running) {
|
|
23103
|
+
await this.#connection.agent.notify(methods2.agent.session.cancel, {
|
|
23104
|
+
sessionId: this.#nativeSessionId
|
|
23105
|
+
});
|
|
23106
|
+
}
|
|
23107
|
+
} finally {
|
|
23108
|
+
await this.closeProcess(capturedProcesses);
|
|
22959
23109
|
}
|
|
22960
|
-
await this.#connection.agent.notify(methods2.agent.session.cancel, {
|
|
22961
|
-
sessionId: this.#nativeSessionId
|
|
22962
|
-
});
|
|
22963
23110
|
};
|
|
22964
23111
|
respondPermission = async (options) => {
|
|
22965
23112
|
const pending = this.#pendingPermissions.get(options.interactionId);
|
|
@@ -23146,11 +23293,45 @@ var AcpProcessSession = class _AcpProcessSession {
|
|
|
23146
23293
|
});
|
|
23147
23294
|
};
|
|
23148
23295
|
onUpdate = (notification) => {
|
|
23296
|
+
if (this.#nativeSessionId.length === 0) {
|
|
23297
|
+
const notificationBytes = Buffer.byteLength(JSON.stringify(notification));
|
|
23298
|
+
if (this.#preSessionUpdates.length >= MAX_PRE_SESSION_UPDATES || this.#preSessionUpdateBytes + notificationBytes > MAX_PRE_SESSION_UPDATE_BYTES) {
|
|
23299
|
+
return Promise.reject(
|
|
23300
|
+
new AcpExecutionError(
|
|
23301
|
+
"ACP agent sent too many updates before creating its session",
|
|
23302
|
+
{},
|
|
23303
|
+
"agent_update_limit"
|
|
23304
|
+
)
|
|
23305
|
+
);
|
|
23306
|
+
}
|
|
23307
|
+
this.#preSessionUpdates.push(notification);
|
|
23308
|
+
this.#preSessionUpdateBytes += notificationBytes;
|
|
23309
|
+
return Promise.resolve();
|
|
23310
|
+
}
|
|
23311
|
+
return this.enqueueUpdate(notification);
|
|
23312
|
+
};
|
|
23313
|
+
enqueueUpdate = (notification) => {
|
|
23149
23314
|
this.#updateTail = this.#updateTail.then(
|
|
23150
23315
|
async () => await this.processUpdate(notification)
|
|
23151
23316
|
);
|
|
23152
23317
|
return this.#updateTail;
|
|
23153
23318
|
};
|
|
23319
|
+
selectNativeSession = (sessionId) => {
|
|
23320
|
+
const selected = nativeSessionIdSchema.parse(sessionId);
|
|
23321
|
+
if (this.#nativeSessionId.length > 0 && this.#nativeSessionId !== selected) {
|
|
23322
|
+
throw new AcpExecutionError(
|
|
23323
|
+
"ACP agent attempted to replace the selected session",
|
|
23324
|
+
{},
|
|
23325
|
+
"invalid_agent_session"
|
|
23326
|
+
);
|
|
23327
|
+
}
|
|
23328
|
+
this.#nativeSessionId = selected;
|
|
23329
|
+
const pending = this.#preSessionUpdates.splice(0);
|
|
23330
|
+
this.#preSessionUpdateBytes = 0;
|
|
23331
|
+
for (const notification of pending) {
|
|
23332
|
+
void this.enqueueUpdate(notification);
|
|
23333
|
+
}
|
|
23334
|
+
};
|
|
23154
23335
|
processUpdate = async (notification) => {
|
|
23155
23336
|
this.assertNativeSession(notification.sessionId);
|
|
23156
23337
|
const update = notification.update;
|
|
@@ -23288,9 +23469,12 @@ var AcpProcessSession = class _AcpProcessSession {
|
|
|
23288
23469
|
}
|
|
23289
23470
|
await this.closeProcess();
|
|
23290
23471
|
};
|
|
23291
|
-
closeProcess = async () => {
|
|
23292
|
-
|
|
23293
|
-
|
|
23472
|
+
closeProcess = async (capturedProcesses = []) => {
|
|
23473
|
+
try {
|
|
23474
|
+
await stopProcessTree(this.#child, capturedProcesses);
|
|
23475
|
+
} finally {
|
|
23476
|
+
this.#connection.close();
|
|
23477
|
+
}
|
|
23294
23478
|
};
|
|
23295
23479
|
race = async (operation, exitMessage, signal) => {
|
|
23296
23480
|
signal.throwIfAborted();
|
|
@@ -23306,13 +23490,25 @@ var AcpProcessSession = class _AcpProcessSession {
|
|
|
23306
23490
|
};
|
|
23307
23491
|
});
|
|
23308
23492
|
try {
|
|
23309
|
-
|
|
23310
|
-
|
|
23311
|
-
|
|
23312
|
-
|
|
23313
|
-
|
|
23314
|
-
|
|
23315
|
-
|
|
23493
|
+
try {
|
|
23494
|
+
return await Promise.race([
|
|
23495
|
+
operation,
|
|
23496
|
+
this.#processExit.then(() => {
|
|
23497
|
+
throw new AcpExecutionError(exitMessage);
|
|
23498
|
+
}),
|
|
23499
|
+
aborted2
|
|
23500
|
+
]);
|
|
23501
|
+
} catch (error61) {
|
|
23502
|
+
signal.throwIfAborted();
|
|
23503
|
+
if (error61 instanceof RequestError && error61.code === -32e3) {
|
|
23504
|
+
throw new AcpExecutionError(
|
|
23505
|
+
"Agent authentication is required",
|
|
23506
|
+
{ cause: error61 },
|
|
23507
|
+
"authentication_required"
|
|
23508
|
+
);
|
|
23509
|
+
}
|
|
23510
|
+
throw error61;
|
|
23511
|
+
}
|
|
23316
23512
|
} finally {
|
|
23317
23513
|
removeAbortListener();
|
|
23318
23514
|
}
|
|
@@ -23571,7 +23767,13 @@ var AcpSessionManager = class {
|
|
|
23571
23767
|
this.#cancellationRequests.add(sessionId);
|
|
23572
23768
|
const runtime = this.#sessions.get(sessionId);
|
|
23573
23769
|
if (runtime !== void 0) {
|
|
23574
|
-
|
|
23770
|
+
try {
|
|
23771
|
+
await runtime.cancel();
|
|
23772
|
+
} finally {
|
|
23773
|
+
if (this.#sessions.get(sessionId) === runtime) {
|
|
23774
|
+
this.#sessions.delete(sessionId);
|
|
23775
|
+
}
|
|
23776
|
+
}
|
|
23575
23777
|
}
|
|
23576
23778
|
};
|
|
23577
23779
|
runPrompt = async (options) => {
|
|
@@ -23624,7 +23826,19 @@ var AcpSessionManager = class {
|
|
|
23624
23826
|
if (this.#cancellationRequests.has(options.sessionId)) {
|
|
23625
23827
|
return { stopReason: "cancelled" };
|
|
23626
23828
|
}
|
|
23627
|
-
|
|
23829
|
+
try {
|
|
23830
|
+
const result = await runtime.prompt(boundedOptions);
|
|
23831
|
+
return this.#cancellationRequests.has(options.sessionId) ? { stopReason: "cancelled" } : result;
|
|
23832
|
+
} catch (error61) {
|
|
23833
|
+
if (this.#cancellationRequests.has(options.sessionId)) {
|
|
23834
|
+
if (this.#sessions.get(options.sessionId) === runtime) {
|
|
23835
|
+
this.#sessions.delete(options.sessionId);
|
|
23836
|
+
}
|
|
23837
|
+
await runtime.closeProcess();
|
|
23838
|
+
return { stopReason: "cancelled" };
|
|
23839
|
+
}
|
|
23840
|
+
throw error61;
|
|
23841
|
+
}
|
|
23628
23842
|
} catch (error61) {
|
|
23629
23843
|
const failedRuntime = this.#sessions.get(options.sessionId);
|
|
23630
23844
|
if (failedRuntime !== void 0) {
|
|
@@ -23932,26 +24146,16 @@ var LocalAuthorizationError = class extends Error {
|
|
|
23932
24146
|
// src/pairing/pair-local-machine.ts
|
|
23933
24147
|
import { randomUUID } from "node:crypto";
|
|
23934
24148
|
import {
|
|
23935
|
-
mkdir as
|
|
23936
|
-
open as
|
|
23937
|
-
realpath as
|
|
23938
|
-
rename as
|
|
23939
|
-
stat as
|
|
23940
|
-
writeFile
|
|
24149
|
+
mkdir as mkdir3,
|
|
24150
|
+
open as open6,
|
|
24151
|
+
realpath as realpath5,
|
|
24152
|
+
rename as rename3,
|
|
24153
|
+
stat as stat5,
|
|
24154
|
+
writeFile as writeFile2
|
|
23941
24155
|
} from "node:fs/promises";
|
|
23942
24156
|
import { hostname as hostname3 } from "node:os";
|
|
23943
|
-
import { basename, join as
|
|
23944
|
-
import { fetch } from "undici";
|
|
23945
|
-
|
|
23946
|
-
// src/agent-catalog/discover-local-agents.ts
|
|
23947
|
-
import { spawn as spawn3 } from "node:child_process";
|
|
23948
|
-
import { isAbsolute as isAbsolute2, join as join7 } from "node:path";
|
|
23949
|
-
import {
|
|
23950
|
-
methods as methods3,
|
|
23951
|
-
ndJsonStream as ndJsonStream2,
|
|
23952
|
-
PROTOCOL_VERSION as PROTOCOL_VERSION2,
|
|
23953
|
-
RequestError
|
|
23954
|
-
} from "@agentclientprotocol/sdk";
|
|
24157
|
+
import { basename, join as join13, resolve as resolve3 } from "node:path";
|
|
24158
|
+
import { fetch as fetch2 } from "undici";
|
|
23955
24159
|
|
|
23956
24160
|
// src/agent-installation/installation-grants.ts
|
|
23957
24161
|
import { open as open2 } from "node:fs/promises";
|
|
@@ -23995,8 +24199,102 @@ async function readGrantedAgents(stateDirectory) {
|
|
|
23995
24199
|
}
|
|
23996
24200
|
}
|
|
23997
24201
|
|
|
23998
|
-
// src/agent-
|
|
23999
|
-
|
|
24202
|
+
// src/agent-catalog/agent-discovery.ts
|
|
24203
|
+
var AgentDiscovery = class {
|
|
24204
|
+
specification;
|
|
24205
|
+
constructor(specification) {
|
|
24206
|
+
this.specification = specification;
|
|
24207
|
+
}
|
|
24208
|
+
};
|
|
24209
|
+
var AvailableAgent = class extends AgentDiscovery {
|
|
24210
|
+
agent;
|
|
24211
|
+
status = "ready";
|
|
24212
|
+
constructor(specification, agent) {
|
|
24213
|
+
super(specification);
|
|
24214
|
+
this.agent = agent;
|
|
24215
|
+
}
|
|
24216
|
+
};
|
|
24217
|
+
var UnavailableAgent = class extends AgentDiscovery {
|
|
24218
|
+
};
|
|
24219
|
+
var MissingAdapter = class extends UnavailableAgent {
|
|
24220
|
+
code = "adapter_not_found";
|
|
24221
|
+
message = "ACP adapter not found";
|
|
24222
|
+
status = "missing_adapter";
|
|
24223
|
+
constructor(specification) {
|
|
24224
|
+
super(specification);
|
|
24225
|
+
}
|
|
24226
|
+
};
|
|
24227
|
+
var MissingAgent = class extends UnavailableAgent {
|
|
24228
|
+
code = "agent_not_found";
|
|
24229
|
+
message = "Agent executable not found";
|
|
24230
|
+
status = "missing_agent";
|
|
24231
|
+
constructor(specification) {
|
|
24232
|
+
super(specification);
|
|
24233
|
+
}
|
|
24234
|
+
};
|
|
24235
|
+
var ProbeFailed = class extends UnavailableAgent {
|
|
24236
|
+
code;
|
|
24237
|
+
message;
|
|
24238
|
+
status = "probe_failed";
|
|
24239
|
+
constructor(specification, code, message) {
|
|
24240
|
+
super(specification);
|
|
24241
|
+
this.code = code;
|
|
24242
|
+
this.message = message;
|
|
24243
|
+
}
|
|
24244
|
+
};
|
|
24245
|
+
var IncompatibleAdapter = class extends UnavailableAgent {
|
|
24246
|
+
code = "acp_incompatible";
|
|
24247
|
+
message = "ACP adapter is incompatible";
|
|
24248
|
+
status = "incompatible_adapter";
|
|
24249
|
+
constructor(specification) {
|
|
24250
|
+
super(specification);
|
|
24251
|
+
}
|
|
24252
|
+
};
|
|
24253
|
+
var AuthenticationRequiredAgent = class extends UnavailableAgent {
|
|
24254
|
+
code = "authentication_required";
|
|
24255
|
+
message = "Agent authentication is required";
|
|
24256
|
+
status = "authentication_required";
|
|
24257
|
+
constructor(specification) {
|
|
24258
|
+
super(specification);
|
|
24259
|
+
}
|
|
24260
|
+
};
|
|
24261
|
+
var LocalAgentInventory = class {
|
|
24262
|
+
available;
|
|
24263
|
+
discoveries;
|
|
24264
|
+
installable;
|
|
24265
|
+
unavailable;
|
|
24266
|
+
constructor(discoveries, grantedAgents = /* @__PURE__ */ new Set(), platform = process.platform, architecture = process.arch) {
|
|
24267
|
+
const available = [];
|
|
24268
|
+
const unavailable = [];
|
|
24269
|
+
for (const discovery of discoveries) {
|
|
24270
|
+
if (discovery instanceof AvailableAgent) {
|
|
24271
|
+
available.push(discovery);
|
|
24272
|
+
} else if (discovery instanceof UnavailableAgent) {
|
|
24273
|
+
unavailable.push(discovery);
|
|
24274
|
+
} else {
|
|
24275
|
+
throw new Error("Unsupported Agent discovery outcome");
|
|
24276
|
+
}
|
|
24277
|
+
}
|
|
24278
|
+
this.available = Object.freeze(available);
|
|
24279
|
+
this.discoveries = Object.freeze([...discoveries]);
|
|
24280
|
+
this.installable = Object.freeze(
|
|
24281
|
+
unavailable.filter(
|
|
24282
|
+
(discovery) => !(discovery instanceof AuthenticationRequiredAgent) && discovery.specification.supportsInstallation(
|
|
24283
|
+
platform,
|
|
24284
|
+
architecture
|
|
24285
|
+
)
|
|
24286
|
+
).map(
|
|
24287
|
+
(discovery) => new InstallableAgentDefinition(
|
|
24288
|
+
discovery.specification.id,
|
|
24289
|
+
discovery.specification.label,
|
|
24290
|
+
!grantedAgents.has(discovery.specification.id)
|
|
24291
|
+
)
|
|
24292
|
+
)
|
|
24293
|
+
);
|
|
24294
|
+
this.unavailable = Object.freeze(unavailable);
|
|
24295
|
+
}
|
|
24296
|
+
readyAgents = () => this.available.map((discovery) => discovery.agent);
|
|
24297
|
+
};
|
|
24000
24298
|
|
|
24001
24299
|
// src/agent-installation/managed-npm-package.ts
|
|
24002
24300
|
import {
|
|
@@ -24013,9 +24311,12 @@ var INSTALL_TIMEOUT_MILLISECONDS = 5 * 60 * 1e3;
|
|
|
24013
24311
|
var PACKAGE_METADATA_LIMIT_BYTES = 64 * 1024;
|
|
24014
24312
|
var PACKAGE_LOCK_LIMIT_BYTES = 8 * 1024 * 1024;
|
|
24015
24313
|
var ManagedNpmPackageDefinition = class {
|
|
24314
|
+
dependencyResolutionArguments = Object.freeze([]);
|
|
24016
24315
|
executableName;
|
|
24316
|
+
includeOptionalDependencies = false;
|
|
24017
24317
|
packageName;
|
|
24018
24318
|
version;
|
|
24319
|
+
verifyDependencyClosure = false;
|
|
24019
24320
|
constructor(packageName, version2, executableName) {
|
|
24020
24321
|
this.executableName = executableName;
|
|
24021
24322
|
this.packageName = packageName;
|
|
@@ -24116,6 +24417,27 @@ function verifyPackageLock(lock, definition) {
|
|
|
24116
24417
|
let matches = 0;
|
|
24117
24418
|
for (const [key, candidate] of Object.entries(packages)) {
|
|
24118
24419
|
const normalizedKey = key.replaceAll("\\", "/");
|
|
24420
|
+
if (definition.verifyDependencyClosure && normalizedKey.length > 0) {
|
|
24421
|
+
let resolved;
|
|
24422
|
+
try {
|
|
24423
|
+
if (!normalizedKey.split("/").includes("node_modules") || !isRecord5(candidate) || typeof candidate["version"] !== "string" || candidate["version"].length === 0 || typeof candidate["integrity"] !== "string" || !/^sha512-[A-Za-z0-9+/]{86}==$/.test(candidate["integrity"]) || typeof candidate["resolved"] !== "string") {
|
|
24424
|
+
throw new Error("Invalid locked dependency");
|
|
24425
|
+
}
|
|
24426
|
+
resolved = new URL(candidate["resolved"]);
|
|
24427
|
+
} catch (error61) {
|
|
24428
|
+
throw new ManagedNpmPackageError(
|
|
24429
|
+
"managed_package_verification_failed",
|
|
24430
|
+
"The managed npm dependency closure is invalid",
|
|
24431
|
+
{ cause: error61 }
|
|
24432
|
+
);
|
|
24433
|
+
}
|
|
24434
|
+
if (resolved.protocol !== "https:" || resolved.hostname !== "registry.npmjs.org" || resolved.port.length > 0 || resolved.username.length > 0 || resolved.password.length > 0) {
|
|
24435
|
+
throw new ManagedNpmPackageError(
|
|
24436
|
+
"managed_package_verification_failed",
|
|
24437
|
+
"The managed npm dependency closure is invalid"
|
|
24438
|
+
);
|
|
24439
|
+
}
|
|
24440
|
+
}
|
|
24119
24441
|
if (normalizedKey === suffix || normalizedKey.endsWith(`/${suffix}`)) {
|
|
24120
24442
|
entry = candidate;
|
|
24121
24443
|
matches += 1;
|
|
@@ -24213,33 +24535,42 @@ var ManagedNpmPackageInstaller = class {
|
|
|
24213
24535
|
"A supported npm executable is required to install the managed package"
|
|
24214
24536
|
);
|
|
24215
24537
|
}
|
|
24538
|
+
const installArguments = ["install", "--prefix", staging];
|
|
24539
|
+
installArguments.push(...definition.dependencyResolutionArguments);
|
|
24540
|
+
if (definition.includeOptionalDependencies) {
|
|
24541
|
+
installArguments.push("--include=optional");
|
|
24542
|
+
} else {
|
|
24543
|
+
installArguments.push("--omit=optional");
|
|
24544
|
+
}
|
|
24545
|
+
installArguments.push(
|
|
24546
|
+
"--ignore-scripts",
|
|
24547
|
+
"--no-audit",
|
|
24548
|
+
"--no-fund",
|
|
24549
|
+
"--package-lock=true",
|
|
24550
|
+
"--save-exact",
|
|
24551
|
+
"--registry=https://registry.npmjs.org/",
|
|
24552
|
+
`${definition.packageName}@${definition.version}`
|
|
24553
|
+
);
|
|
24554
|
+
const installEnvironment = {
|
|
24555
|
+
HOME: join5(staging, "home"),
|
|
24556
|
+
NPM_CONFIG_AUDIT: "false",
|
|
24557
|
+
NPM_CONFIG_CACHE: join5(staging, ".npm-cache"),
|
|
24558
|
+
NPM_CONFIG_FUND: "false",
|
|
24559
|
+
NPM_CONFIG_IGNORE_SCRIPTS: "true",
|
|
24560
|
+
NPM_CONFIG_PACKAGE_LOCK: "true",
|
|
24561
|
+
NPM_CONFIG_REGISTRY: "https://registry.npmjs.org/",
|
|
24562
|
+
PATH: `${dirname3(process.execPath)}${delimiter}/usr/bin${delimiter}/bin`
|
|
24563
|
+
};
|
|
24564
|
+
if (definition.includeOptionalDependencies) {
|
|
24565
|
+
installEnvironment["NPM_CONFIG_INCLUDE"] = "optional";
|
|
24566
|
+
} else {
|
|
24567
|
+
installEnvironment["NPM_CONFIG_OMIT"] = "optional";
|
|
24568
|
+
}
|
|
24216
24569
|
await runBoundedProcess({
|
|
24217
|
-
arguments:
|
|
24218
|
-
"install",
|
|
24219
|
-
"--prefix",
|
|
24220
|
-
staging,
|
|
24221
|
-
"--omit=optional",
|
|
24222
|
-
"--ignore-scripts",
|
|
24223
|
-
"--no-audit",
|
|
24224
|
-
"--no-fund",
|
|
24225
|
-
"--package-lock=true",
|
|
24226
|
-
"--save-exact",
|
|
24227
|
-
"--registry=https://registry.npmjs.org/",
|
|
24228
|
-
`${definition.packageName}@${definition.version}`
|
|
24229
|
-
],
|
|
24570
|
+
arguments: installArguments,
|
|
24230
24571
|
command: npm.path,
|
|
24231
24572
|
cwd: staging,
|
|
24232
|
-
environment:
|
|
24233
|
-
HOME: join5(staging, "home"),
|
|
24234
|
-
NPM_CONFIG_AUDIT: "false",
|
|
24235
|
-
NPM_CONFIG_CACHE: join5(staging, ".npm-cache"),
|
|
24236
|
-
NPM_CONFIG_FUND: "false",
|
|
24237
|
-
NPM_CONFIG_IGNORE_SCRIPTS: "true",
|
|
24238
|
-
NPM_CONFIG_OMIT: "optional",
|
|
24239
|
-
NPM_CONFIG_PACKAGE_LOCK: "true",
|
|
24240
|
-
NPM_CONFIG_REGISTRY: "https://registry.npmjs.org/",
|
|
24241
|
-
PATH: `${dirname3(process.execPath)}${delimiter}/usr/bin${delimiter}/bin`
|
|
24242
|
-
},
|
|
24573
|
+
environment: installEnvironment,
|
|
24243
24574
|
outputLimitBytes: 64 * 1024,
|
|
24244
24575
|
signal,
|
|
24245
24576
|
timeoutMilliseconds: INSTALL_TIMEOUT_MILLISECONDS
|
|
@@ -24281,144 +24612,101 @@ var ManagedNpmPackageInstaller = class {
|
|
|
24281
24612
|
};
|
|
24282
24613
|
};
|
|
24283
24614
|
|
|
24284
|
-
// src/agent-
|
|
24285
|
-
|
|
24286
|
-
code;
|
|
24287
|
-
constructor(code, message, options = {}) {
|
|
24288
|
-
super(message, options);
|
|
24289
|
-
this.code = code;
|
|
24290
|
-
this.name = "ManagedAdapterInstallError";
|
|
24291
|
-
}
|
|
24292
|
-
};
|
|
24293
|
-
function translateError(error61) {
|
|
24294
|
-
if (error61 instanceof ManagedAdapterInstallError) {
|
|
24295
|
-
return error61;
|
|
24296
|
-
}
|
|
24297
|
-
if (error61 instanceof ManagedNpmPackageError) {
|
|
24298
|
-
if (error61.code === "package_manager_not_found") {
|
|
24299
|
-
return new ManagedAdapterInstallError(
|
|
24300
|
-
error61.code,
|
|
24301
|
-
"A supported npm executable is required to install the ACP adapter",
|
|
24302
|
-
{ cause: error61 }
|
|
24303
|
-
);
|
|
24304
|
-
}
|
|
24305
|
-
if (error61.code === "managed_package_verification_failed") {
|
|
24306
|
-
return new ManagedAdapterInstallError(
|
|
24307
|
-
"adapter_verification_failed",
|
|
24308
|
-
"The managed adapter did not match its pinned artifact",
|
|
24309
|
-
{ cause: error61 }
|
|
24310
|
-
);
|
|
24311
|
-
}
|
|
24312
|
-
if (error61.code === "managed_package_publish_failed") {
|
|
24313
|
-
return new ManagedAdapterInstallError(
|
|
24314
|
-
"adapter_publish_failed",
|
|
24315
|
-
"The managed adapter could not be published",
|
|
24316
|
-
{ cause: error61 }
|
|
24317
|
-
);
|
|
24318
|
-
}
|
|
24319
|
-
}
|
|
24320
|
-
return new ManagedAdapterInstallError(
|
|
24321
|
-
"adapter_install_failed",
|
|
24322
|
-
"The pinned ACP adapter could not be installed",
|
|
24323
|
-
{ cause: error61 }
|
|
24324
|
-
);
|
|
24325
|
-
}
|
|
24326
|
-
async function validateManagedAdapter(root, specification) {
|
|
24327
|
-
try {
|
|
24328
|
-
return await validateManagedNpmPackage(
|
|
24329
|
-
root,
|
|
24330
|
-
specification.adapterPackageDefinition
|
|
24331
|
-
);
|
|
24332
|
-
} catch (error61) {
|
|
24333
|
-
throw translateError(error61);
|
|
24334
|
-
}
|
|
24335
|
-
}
|
|
24336
|
-
var ManagedAdapterInstaller = class {
|
|
24337
|
-
#environment;
|
|
24338
|
-
#npmInstaller;
|
|
24339
|
-
#stateDirectory;
|
|
24340
|
-
constructor(options, npmInstaller = new ManagedNpmPackageInstaller()) {
|
|
24341
|
-
this.#environment = options.environment;
|
|
24342
|
-
this.#npmInstaller = npmInstaller;
|
|
24343
|
-
this.#stateDirectory = options.stateDirectory;
|
|
24344
|
-
}
|
|
24345
|
-
install = async (specification, signal) => {
|
|
24346
|
-
const root = join6(
|
|
24347
|
-
this.#stateDirectory,
|
|
24348
|
-
"adapters",
|
|
24349
|
-
specification.id,
|
|
24350
|
-
specification.adapterVersion
|
|
24351
|
-
);
|
|
24352
|
-
try {
|
|
24353
|
-
return await this.#npmInstaller.install(
|
|
24354
|
-
root,
|
|
24355
|
-
specification.adapterPackageDefinition,
|
|
24356
|
-
this.#environment,
|
|
24357
|
-
signal
|
|
24358
|
-
);
|
|
24359
|
-
} catch (error61) {
|
|
24360
|
-
if (signal.aborted) {
|
|
24361
|
-
signal.throwIfAborted();
|
|
24362
|
-
}
|
|
24363
|
-
throw translateError(error61);
|
|
24364
|
-
}
|
|
24365
|
-
};
|
|
24366
|
-
};
|
|
24367
|
-
|
|
24368
|
-
// src/agent-installation/pi-managed-packages.ts
|
|
24369
|
-
var PI_ACP_PACKAGE = new SriManagedNpmPackageDefinition(
|
|
24370
|
-
"pi-acp",
|
|
24371
|
-
"0.0.33",
|
|
24372
|
-
"pi-acp",
|
|
24373
|
-
"sha512-vX9kY1tK14E72G4dBAx+RGCk/k7XPjTHls6dLUxA8WSkBav6B6JHuSBv3eusp50LCR/GTRsR2kIKsG0Z5jANzw==",
|
|
24374
|
-
"https://registry.npmjs.org/pi-acp/-/pi-acp-0.0.33.tgz"
|
|
24375
|
-
);
|
|
24376
|
-
var PI_AGENT_PACKAGE = new SriManagedNpmPackageDefinition(
|
|
24377
|
-
"@earendil-works/pi-coding-agent",
|
|
24378
|
-
"0.85.0",
|
|
24379
|
-
"pi",
|
|
24380
|
-
"sha512-INxVkLAVfAMju5MojJpmyu/0bMP+r+ffZuS7UqVv32E2JwHBRbcHfELDfmFNvapEbgYfKN2r9OYO1p3TqDBR+g==",
|
|
24381
|
-
"https://registry.npmjs.org/@earendil-works/pi-coding-agent/-/pi-coding-agent-0.85.0.tgz"
|
|
24382
|
-
);
|
|
24383
|
-
|
|
24384
|
-
// src/agent-catalog/discover-local-agents.ts
|
|
24615
|
+
// src/agent-catalog/agent-specification.ts
|
|
24616
|
+
import { join as join6 } from "node:path";
|
|
24385
24617
|
var VERSION_PROBE_TIMEOUT_MILLISECONDS = 3e3;
|
|
24386
24618
|
var ACP_PROBE_TIMEOUT_MILLISECONDS = 5e3;
|
|
24387
|
-
var ACP_OUTPUT_LIMIT_BYTES = 1024 * 1024;
|
|
24388
24619
|
var DEFAULT_PROMPT_TIMEOUT_MILLISECONDS = 30 * 60 * 1e3;
|
|
24389
|
-
var PI_ACP_PROBE_TIMEOUT_MILLISECONDS = 3e4;
|
|
24390
|
-
var PI_PROMPT_TIMEOUT_MILLISECONDS = 5 * 60 * 1e3;
|
|
24391
24620
|
var LocalAgentSpecification = class {
|
|
24392
24621
|
acpProbeTimeoutMilliseconds = ACP_PROBE_TIMEOUT_MILLISECONDS;
|
|
24393
24622
|
authenticationCommand = () => "";
|
|
24394
24623
|
adapterVersionArguments = ["--version"];
|
|
24395
24624
|
agentVersionArguments = ["--version"];
|
|
24396
24625
|
promptTimeoutMilliseconds = DEFAULT_PROMPT_TIMEOUT_MILLISECONDS;
|
|
24397
|
-
|
|
24398
|
-
|
|
24399
|
-
|
|
24400
|
-
get adapterPackage() {
|
|
24401
|
-
return this.adapterPackageDefinition.packageName;
|
|
24402
|
-
}
|
|
24403
|
-
get adapterVersion() {
|
|
24404
|
-
return this.adapterPackageDefinition.version;
|
|
24405
|
-
}
|
|
24406
|
-
resolveManagedAgent = async (stateDirectory, platform) => {
|
|
24626
|
+
versionProbeTimeoutMilliseconds = VERSION_PROBE_TIMEOUT_MILLISECONDS;
|
|
24627
|
+
resolveManagedAgent = async (stateDirectory, platform, signal) => {
|
|
24628
|
+
signal.throwIfAborted();
|
|
24407
24629
|
const executable = await resolveExecutablePath(
|
|
24408
|
-
|
|
24630
|
+
join6(stateDirectory, ...this.managedAgentExecutablePath),
|
|
24409
24631
|
platform
|
|
24410
24632
|
);
|
|
24633
|
+
signal.throwIfAborted();
|
|
24411
24634
|
if (executable === null) {
|
|
24412
24635
|
throw new Error("The managed Agent executable is unavailable");
|
|
24413
24636
|
}
|
|
24414
24637
|
return executable;
|
|
24415
24638
|
};
|
|
24416
|
-
|
|
24639
|
+
createLaunchEnvironment = async (_agent, _context) => Object.freeze({});
|
|
24640
|
+
recoveryCommand = () => "";
|
|
24417
24641
|
supportsInstallation = (platform, architecture) => (platform === "darwin" || platform === "linux") && (architecture === "arm64" || architecture === "x64");
|
|
24418
24642
|
verifyAcp = (_connection, _initialized, _defaultWorkspace, _signal) => Promise.resolve();
|
|
24419
24643
|
};
|
|
24644
|
+
var DirectAcpAgentDefinition = class extends LocalAgentSpecification {
|
|
24645
|
+
adapterOverrideVariable;
|
|
24646
|
+
agentOverrideVariable;
|
|
24647
|
+
launchArguments;
|
|
24648
|
+
managedAdapterExecutablePath;
|
|
24649
|
+
managedAgentExecutablePath;
|
|
24650
|
+
constructor(executableOverrideVariable, launchArguments, managedExecutablePath) {
|
|
24651
|
+
super();
|
|
24652
|
+
this.adapterOverrideVariable = executableOverrideVariable;
|
|
24653
|
+
this.agentOverrideVariable = executableOverrideVariable;
|
|
24654
|
+
this.launchArguments = Object.freeze([...launchArguments]);
|
|
24655
|
+
this.managedAdapterExecutablePath = Object.freeze([
|
|
24656
|
+
...managedExecutablePath
|
|
24657
|
+
]);
|
|
24658
|
+
this.managedAgentExecutablePath = this.managedAdapterExecutablePath;
|
|
24659
|
+
}
|
|
24660
|
+
};
|
|
24420
24661
|
var BridgedAcpAgentDefinition = class extends LocalAgentSpecification {
|
|
24662
|
+
launchArguments = Object.freeze([]);
|
|
24663
|
+
get adapterExecutable() {
|
|
24664
|
+
return this.adapterPackageDefinition.executableName;
|
|
24665
|
+
}
|
|
24666
|
+
get adapterPackage() {
|
|
24667
|
+
return this.adapterPackageDefinition.packageName;
|
|
24668
|
+
}
|
|
24669
|
+
get adapterVersion() {
|
|
24670
|
+
return this.adapterPackageDefinition.version;
|
|
24671
|
+
}
|
|
24672
|
+
createLaunchEnvironment = async (agent, _context) => Object.freeze({ [this.adapterEnvironmentVariable]: agent.path });
|
|
24673
|
+
recoveryCommand = () => `npm install -g --omit=optional ${this.adapterPackage}@${this.adapterVersion}`;
|
|
24674
|
+
};
|
|
24675
|
+
|
|
24676
|
+
// src/agent-catalog/agents/claude-code-agent.ts
|
|
24677
|
+
var ClaudeCodeAgentSpecification = class extends BridgedAcpAgentDefinition {
|
|
24678
|
+
adapterEnvironmentVariable = "CLAUDE_CODE_EXECUTABLE";
|
|
24679
|
+
adapterOverrideVariable = "MOBIUS_CLAUDE_ACP_PATH";
|
|
24680
|
+
adapterPackageDefinition = new ManagedNpmPackageDefinition(
|
|
24681
|
+
"@agentclientprotocol/claude-agent-acp",
|
|
24682
|
+
"0.73.0",
|
|
24683
|
+
"claude-agent-acp"
|
|
24684
|
+
);
|
|
24685
|
+
agentExecutable = "claude";
|
|
24686
|
+
agentOverrideVariable = "MOBIUS_CLAUDE_PATH";
|
|
24687
|
+
id = "claude";
|
|
24688
|
+
label = "Claude Code";
|
|
24689
|
+
managedAdapterExecutablePath = [
|
|
24690
|
+
"adapters",
|
|
24691
|
+
"claude",
|
|
24692
|
+
"0.73.0",
|
|
24693
|
+
"node_modules",
|
|
24694
|
+
"@agentclientprotocol",
|
|
24695
|
+
"claude-agent-acp",
|
|
24696
|
+
"dist",
|
|
24697
|
+
"index.js"
|
|
24698
|
+
];
|
|
24699
|
+
managedAgentExecutablePath = [
|
|
24700
|
+
"agents",
|
|
24701
|
+
"claude",
|
|
24702
|
+
"home",
|
|
24703
|
+
".local",
|
|
24704
|
+
"bin",
|
|
24705
|
+
"claude"
|
|
24706
|
+
];
|
|
24421
24707
|
};
|
|
24708
|
+
|
|
24709
|
+
// src/agent-catalog/agents/codex-agent.ts
|
|
24422
24710
|
var CodexAgentSpecification = class extends BridgedAcpAgentDefinition {
|
|
24423
24711
|
adapterEnvironmentVariable = "CODEX_PATH";
|
|
24424
24712
|
adapterOverrideVariable = "MOBIUS_CODEX_ACP_PATH";
|
|
@@ -24443,39 +24731,769 @@ var CodexAgentSpecification = class extends BridgedAcpAgentDefinition {
|
|
|
24443
24731
|
];
|
|
24444
24732
|
managedAgentExecutablePath = ["agents", "codex", "bin", "codex"];
|
|
24445
24733
|
};
|
|
24446
|
-
|
|
24447
|
-
|
|
24448
|
-
|
|
24449
|
-
|
|
24450
|
-
|
|
24451
|
-
|
|
24452
|
-
|
|
24734
|
+
|
|
24735
|
+
// src/agent-catalog/agents/deepseek-harness-agent.ts
|
|
24736
|
+
import { realpath as realpath3, stat as stat3 } from "node:fs/promises";
|
|
24737
|
+
import { isAbsolute as isAbsolute2, join as join7, normalize } from "node:path";
|
|
24738
|
+
|
|
24739
|
+
// src/agent-installation/deepseek-managed-package.ts
|
|
24740
|
+
var DeepSeekHarnessManagedPackage = class extends SriManagedNpmPackageDefinition {
|
|
24741
|
+
dependencyResolutionArguments = Object.freeze([
|
|
24742
|
+
"--before=2026-09-03T06:31:52.107Z"
|
|
24743
|
+
]);
|
|
24744
|
+
includeOptionalDependencies = true;
|
|
24745
|
+
verifyDependencyClosure = true;
|
|
24746
|
+
};
|
|
24747
|
+
var DEEPSEEK_HARNESS_PACKAGE = new DeepSeekHarnessManagedPackage(
|
|
24748
|
+
"@deepseek-ai/dsh",
|
|
24749
|
+
"0.1.2-rc.1",
|
|
24750
|
+
"dsh",
|
|
24751
|
+
"sha512-RPq48TzxvwpdT9/7W1tbhZDBMmeK+bxDrX9cqQC27Wx/LqtgJF8PSa3b3xriU8oxtvhwYmk21w2cej3uMQrnVA==",
|
|
24752
|
+
"https://registry.npmjs.org/@deepseek-ai/dsh/-/dsh-0.1.2-rc.1.tgz"
|
|
24753
|
+
);
|
|
24754
|
+
|
|
24755
|
+
// src/agent-catalog/agent-probe-error.ts
|
|
24756
|
+
var AgentProbeError = class extends Error {
|
|
24757
|
+
code;
|
|
24758
|
+
constructor(code, message, options = {}) {
|
|
24759
|
+
super(message, options);
|
|
24760
|
+
this.code = code;
|
|
24761
|
+
this.name = "AgentProbeError";
|
|
24762
|
+
}
|
|
24763
|
+
};
|
|
24764
|
+
|
|
24765
|
+
// src/agent-catalog/agents/deepseek-harness-agent.ts
|
|
24766
|
+
async function validateAgentHome(path2) {
|
|
24767
|
+
if (!isAbsolute2(path2) || normalize(path2) !== path2) {
|
|
24768
|
+
throw new AgentProbeError(
|
|
24769
|
+
"agent_environment_invalid",
|
|
24770
|
+
"The configured Agent home is invalid"
|
|
24771
|
+
);
|
|
24772
|
+
}
|
|
24773
|
+
try {
|
|
24774
|
+
const resolved = await realpath3(path2);
|
|
24775
|
+
const metadata = await stat3(resolved);
|
|
24776
|
+
if (!metadata.isDirectory() || typeof process.getuid === "function" && metadata.uid !== process.getuid()) {
|
|
24777
|
+
throw new Error("Agent home is not a user-owned directory");
|
|
24778
|
+
}
|
|
24779
|
+
return resolved;
|
|
24780
|
+
} catch (error61) {
|
|
24781
|
+
if (error61 instanceof AgentProbeError) {
|
|
24782
|
+
throw error61;
|
|
24783
|
+
}
|
|
24784
|
+
throw new AgentProbeError(
|
|
24785
|
+
"agent_environment_invalid",
|
|
24786
|
+
"The configured Agent home is invalid",
|
|
24787
|
+
{ cause: error61 }
|
|
24788
|
+
);
|
|
24789
|
+
}
|
|
24790
|
+
}
|
|
24791
|
+
var DeepSeekHarnessAgentSpecification = class extends DirectAcpAgentDefinition {
|
|
24792
|
+
adapterVersion = DEEPSEEK_HARNESS_PACKAGE.version;
|
|
24793
|
+
authenticationCommand = () => "dsh web";
|
|
24794
|
+
agentExecutable = "dsh";
|
|
24795
|
+
id = "deepseek-harness";
|
|
24796
|
+
label = "DeepSeek Harness";
|
|
24797
|
+
constructor() {
|
|
24798
|
+
super(
|
|
24799
|
+
"MOBIUS_DEEPSEEK_HARNESS_PATH",
|
|
24800
|
+
["--profile", "acp"],
|
|
24801
|
+
[
|
|
24802
|
+
"agents",
|
|
24803
|
+
"deepseek-harness",
|
|
24804
|
+
DEEPSEEK_HARNESS_PACKAGE.version,
|
|
24805
|
+
"node_modules",
|
|
24806
|
+
"@deepseek-ai",
|
|
24807
|
+
"dsh",
|
|
24808
|
+
"lib",
|
|
24809
|
+
"bin.js"
|
|
24810
|
+
]
|
|
24811
|
+
);
|
|
24812
|
+
}
|
|
24813
|
+
createLaunchEnvironment = async (agent, context) => {
|
|
24814
|
+
let selectedHome = context.environment["DSH_HOME"];
|
|
24815
|
+
try {
|
|
24816
|
+
const managed = await this.resolveManagedAgent(
|
|
24817
|
+
readStateDirectory(context.environment),
|
|
24818
|
+
context.platform ?? process.platform,
|
|
24819
|
+
context.signal
|
|
24820
|
+
);
|
|
24821
|
+
if (managed.path === agent.path) {
|
|
24822
|
+
selectedHome = join7(
|
|
24823
|
+
readStateDirectory(context.environment),
|
|
24824
|
+
"agents",
|
|
24825
|
+
this.id,
|
|
24826
|
+
"home"
|
|
24827
|
+
);
|
|
24828
|
+
}
|
|
24829
|
+
} catch {
|
|
24830
|
+
context.signal.throwIfAborted();
|
|
24831
|
+
}
|
|
24832
|
+
if (selectedHome === void 0 || selectedHome.length === 0) {
|
|
24833
|
+
return Object.freeze({ DSH_PERMISSION_MODE: "workspace-write" });
|
|
24834
|
+
}
|
|
24835
|
+
return Object.freeze({
|
|
24836
|
+
DSH_HOME: await validateAgentHome(selectedHome),
|
|
24837
|
+
DSH_PERMISSION_MODE: "workspace-write"
|
|
24838
|
+
});
|
|
24839
|
+
};
|
|
24840
|
+
resolveManagedAgent = async (stateDirectory, _platform, signal) => {
|
|
24841
|
+
signal.throwIfAborted();
|
|
24842
|
+
const executable = await validateManagedNpmPackage(
|
|
24843
|
+
join7(stateDirectory, "agents", this.id, DEEPSEEK_HARNESS_PACKAGE.version),
|
|
24844
|
+
DEEPSEEK_HARNESS_PACKAGE
|
|
24845
|
+
);
|
|
24846
|
+
signal.throwIfAborted();
|
|
24847
|
+
return executable;
|
|
24848
|
+
};
|
|
24849
|
+
verifyAcp = (_connection, initialized, _defaultWorkspace, _signal) => {
|
|
24850
|
+
const capabilities = initialized.agentCapabilities ?? {};
|
|
24851
|
+
const session = capabilities.sessionCapabilities;
|
|
24852
|
+
const prompt = capabilities.promptCapabilities;
|
|
24853
|
+
if ((initialized.authMethods ?? []).length !== 0 || capabilities.loadSession === true || capabilities.mcpCapabilities?.http !== true || session?.close == null || session.list == null || session.resume == null || session.additionalDirectories != null || session.delete != null || session.fork != null || prompt?.audio === true || prompt?.embeddedContext === true || prompt?.image === true) {
|
|
24854
|
+
throw new AgentProbeError(
|
|
24855
|
+
"acp_incompatible",
|
|
24856
|
+
"DeepSeek Harness reported an unsupported ACP capability set"
|
|
24857
|
+
);
|
|
24858
|
+
}
|
|
24859
|
+
return Promise.resolve();
|
|
24860
|
+
};
|
|
24861
|
+
};
|
|
24862
|
+
|
|
24863
|
+
// src/agent-catalog/agents/opencode-agent.ts
|
|
24864
|
+
import { join as join9 } from "node:path";
|
|
24865
|
+
|
|
24866
|
+
// src/agent-installation/managed-agent-archive.ts
|
|
24867
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
24868
|
+
import { createReadStream } from "node:fs";
|
|
24869
|
+
import {
|
|
24870
|
+
chmod,
|
|
24871
|
+
copyFile,
|
|
24872
|
+
mkdir as mkdir2,
|
|
24873
|
+
mkdtemp as mkdtemp2,
|
|
24874
|
+
open as open5,
|
|
24875
|
+
realpath as realpath4,
|
|
24876
|
+
rename as rename2,
|
|
24877
|
+
rm as rm2,
|
|
24878
|
+
stat as stat4,
|
|
24879
|
+
writeFile
|
|
24880
|
+
} from "node:fs/promises";
|
|
24881
|
+
import { dirname as dirname4, isAbsolute as isAbsolute3, join as join8, relative as relative2, sep as sep2 } from "node:path";
|
|
24882
|
+
|
|
24883
|
+
// src/agent-installation/verified-download.ts
|
|
24884
|
+
import { createHash } from "node:crypto";
|
|
24885
|
+
import { open as open4, unlink } from "node:fs/promises";
|
|
24886
|
+
import { fetch } from "undici";
|
|
24887
|
+
|
|
24888
|
+
// src/network/environment-proxy.ts
|
|
24889
|
+
import { EnvHttpProxyAgent } from "undici";
|
|
24890
|
+
var environmentProxyDispatcher = new EnvHttpProxyAgent();
|
|
24891
|
+
|
|
24892
|
+
// src/agent-installation/verified-download.ts
|
|
24893
|
+
var MAX_REDIRECTS = 4;
|
|
24894
|
+
var REDIRECT_STATUSES = /* @__PURE__ */ new Set([301, 302, 303, 307, 308]);
|
|
24895
|
+
var InstallerDownloadError = class extends Error {
|
|
24896
|
+
code;
|
|
24897
|
+
constructor(code, message, options = {}) {
|
|
24898
|
+
super(message, options);
|
|
24899
|
+
this.code = code;
|
|
24900
|
+
this.name = "InstallerDownloadError";
|
|
24901
|
+
}
|
|
24902
|
+
};
|
|
24903
|
+
var VerifiedDownload = class {
|
|
24904
|
+
bytes;
|
|
24905
|
+
sha256;
|
|
24906
|
+
url;
|
|
24907
|
+
constructor(url2, bytes, sha256) {
|
|
24908
|
+
this.bytes = bytes;
|
|
24909
|
+
this.sha256 = sha256;
|
|
24910
|
+
this.url = url2;
|
|
24911
|
+
}
|
|
24912
|
+
};
|
|
24913
|
+
var UndiciInstallerDownloadTransport = class {
|
|
24914
|
+
get = async (url2, signal) => await fetch(url2, {
|
|
24915
|
+
dispatcher: environmentProxyDispatcher,
|
|
24916
|
+
headers: {
|
|
24917
|
+
accept: "text/plain, application/octet-stream;q=0.9",
|
|
24918
|
+
"user-agent": "Mobius-Agent-Installer/0.0.3"
|
|
24919
|
+
},
|
|
24920
|
+
method: "GET",
|
|
24921
|
+
redirect: "manual",
|
|
24922
|
+
signal
|
|
24923
|
+
});
|
|
24924
|
+
};
|
|
24925
|
+
function validateUrl(url2, allowedHosts) {
|
|
24926
|
+
if (url2.protocol !== "https:" || url2.username.length > 0 || url2.password.length > 0 || url2.port.length > 0 || !allowedHosts.has(url2.hostname)) {
|
|
24927
|
+
throw new InstallerDownloadError(
|
|
24928
|
+
"installer_host_not_allowed",
|
|
24929
|
+
"The installer download target is not allowed"
|
|
24930
|
+
);
|
|
24931
|
+
}
|
|
24932
|
+
}
|
|
24933
|
+
async function fetchInstaller(options, signal, transport) {
|
|
24934
|
+
let url2 = new URL(options.url);
|
|
24935
|
+
for (let redirectCount = 0; redirectCount <= MAX_REDIRECTS; redirectCount += 1) {
|
|
24936
|
+
validateUrl(url2, options.allowedHosts);
|
|
24937
|
+
const response = await transport.get(url2, signal);
|
|
24938
|
+
if (!REDIRECT_STATUSES.has(response.status)) {
|
|
24939
|
+
return { response, url: url2 };
|
|
24940
|
+
}
|
|
24941
|
+
await response.body?.cancel();
|
|
24942
|
+
const location = response.headers.get("location");
|
|
24943
|
+
if (location === null || redirectCount === MAX_REDIRECTS) {
|
|
24944
|
+
throw new InstallerDownloadError(
|
|
24945
|
+
"installer_redirect_invalid",
|
|
24946
|
+
"The installer returned an invalid redirect"
|
|
24947
|
+
);
|
|
24948
|
+
}
|
|
24949
|
+
let redirected;
|
|
24950
|
+
try {
|
|
24951
|
+
redirected = new URL(location, url2);
|
|
24952
|
+
} catch (error61) {
|
|
24953
|
+
throw new InstallerDownloadError(
|
|
24954
|
+
"installer_redirect_invalid",
|
|
24955
|
+
"The installer returned an invalid redirect",
|
|
24956
|
+
{ cause: error61 }
|
|
24957
|
+
);
|
|
24958
|
+
}
|
|
24959
|
+
try {
|
|
24960
|
+
validateUrl(redirected, options.allowedHosts);
|
|
24961
|
+
} catch (error61) {
|
|
24962
|
+
throw new InstallerDownloadError(
|
|
24963
|
+
"installer_redirect_not_allowed",
|
|
24964
|
+
"The installer redirect left the approved host allowlist",
|
|
24965
|
+
{ cause: error61 }
|
|
24966
|
+
);
|
|
24967
|
+
}
|
|
24968
|
+
url2 = redirected;
|
|
24969
|
+
}
|
|
24970
|
+
throw new InstallerDownloadError(
|
|
24971
|
+
"installer_redirect_invalid",
|
|
24972
|
+
"The installer returned too many redirects"
|
|
24973
|
+
);
|
|
24974
|
+
}
|
|
24975
|
+
async function writeCompleteChunk(handle, chunk) {
|
|
24976
|
+
let offset = 0;
|
|
24977
|
+
while (offset < chunk.byteLength) {
|
|
24978
|
+
const written = await handle.write(
|
|
24979
|
+
chunk,
|
|
24980
|
+
offset,
|
|
24981
|
+
chunk.byteLength - offset
|
|
24982
|
+
);
|
|
24983
|
+
if (written.bytesWritten < 1) {
|
|
24984
|
+
throw new InstallerDownloadError(
|
|
24985
|
+
"installer_write_failed",
|
|
24986
|
+
"The verified installer could not be stored"
|
|
24987
|
+
);
|
|
24988
|
+
}
|
|
24989
|
+
offset += written.bytesWritten;
|
|
24990
|
+
}
|
|
24991
|
+
}
|
|
24992
|
+
async function downloadVerifiedFile(options, transport = new UndiciInstallerDownloadTransport()) {
|
|
24993
|
+
options.signal.throwIfAborted();
|
|
24994
|
+
const timeoutSignal = AbortSignal.timeout(options.timeoutMilliseconds);
|
|
24995
|
+
const signal = AbortSignal.any([options.signal, timeoutSignal]);
|
|
24996
|
+
let handle = null;
|
|
24997
|
+
let responseBody = null;
|
|
24998
|
+
try {
|
|
24999
|
+
const fetched = await fetchInstaller(options, signal, transport);
|
|
25000
|
+
responseBody = fetched.response.body;
|
|
25001
|
+
if (!fetched.response.ok || fetched.response.body === null) {
|
|
25002
|
+
throw new InstallerDownloadError(
|
|
25003
|
+
"installer_download_failed",
|
|
25004
|
+
"The approved installer could not be downloaded"
|
|
25005
|
+
);
|
|
25006
|
+
}
|
|
25007
|
+
const contentLength = fetched.response.headers.get("content-length");
|
|
25008
|
+
if (contentLength !== null) {
|
|
25009
|
+
const declaredLength = Number(contentLength);
|
|
25010
|
+
if (!Number.isSafeInteger(declaredLength) || declaredLength < 1 || declaredLength > options.maximumBytes) {
|
|
25011
|
+
throw new InstallerDownloadError(
|
|
25012
|
+
"installer_size_invalid",
|
|
25013
|
+
"The installer size is outside the approved limit"
|
|
25014
|
+
);
|
|
25015
|
+
}
|
|
25016
|
+
}
|
|
25017
|
+
handle = await open4(options.destination, "wx", 384);
|
|
25018
|
+
const digest = createHash("sha256");
|
|
25019
|
+
const reader = fetched.response.body.getReader();
|
|
25020
|
+
let bytes = 0;
|
|
25021
|
+
try {
|
|
25022
|
+
while (true) {
|
|
25023
|
+
signal.throwIfAborted();
|
|
25024
|
+
const chunk = await reader.read();
|
|
25025
|
+
if (chunk.done) {
|
|
25026
|
+
break;
|
|
25027
|
+
}
|
|
25028
|
+
bytes += chunk.value.byteLength;
|
|
25029
|
+
if (bytes > options.maximumBytes) {
|
|
25030
|
+
throw new InstallerDownloadError(
|
|
25031
|
+
"installer_size_invalid",
|
|
25032
|
+
"The installer exceeded the approved size limit"
|
|
25033
|
+
);
|
|
25034
|
+
}
|
|
25035
|
+
digest.update(chunk.value);
|
|
25036
|
+
await writeCompleteChunk(handle, chunk.value);
|
|
25037
|
+
}
|
|
25038
|
+
} finally {
|
|
25039
|
+
await reader.cancel().catch(() => void 0);
|
|
25040
|
+
reader.releaseLock();
|
|
25041
|
+
}
|
|
25042
|
+
if (bytes === 0) {
|
|
25043
|
+
throw new InstallerDownloadError(
|
|
25044
|
+
"installer_verification_failed",
|
|
25045
|
+
"The downloaded installer is empty"
|
|
25046
|
+
);
|
|
25047
|
+
}
|
|
25048
|
+
await handle.sync();
|
|
25049
|
+
await handle.close();
|
|
25050
|
+
handle = null;
|
|
25051
|
+
return new VerifiedDownload(fetched.url, bytes, digest.digest("hex"));
|
|
25052
|
+
} catch (error61) {
|
|
25053
|
+
if (handle !== null) {
|
|
25054
|
+
await handle.close().catch(() => void 0);
|
|
25055
|
+
}
|
|
25056
|
+
await unlink(options.destination).catch(() => void 0);
|
|
25057
|
+
if (options.signal.aborted) {
|
|
25058
|
+
options.signal.throwIfAborted();
|
|
25059
|
+
}
|
|
25060
|
+
if (timeoutSignal.aborted) {
|
|
25061
|
+
throw new InstallerDownloadError(
|
|
25062
|
+
"installer_download_timeout",
|
|
25063
|
+
"The installer download timed out",
|
|
25064
|
+
{ cause: error61 }
|
|
25065
|
+
);
|
|
25066
|
+
}
|
|
25067
|
+
if (error61 instanceof InstallerDownloadError) {
|
|
25068
|
+
throw error61;
|
|
25069
|
+
}
|
|
25070
|
+
throw new InstallerDownloadError(
|
|
25071
|
+
"installer_download_failed",
|
|
25072
|
+
"The approved installer could not be downloaded",
|
|
25073
|
+
{ cause: error61 }
|
|
25074
|
+
);
|
|
25075
|
+
} finally {
|
|
25076
|
+
await responseBody?.cancel().catch(() => void 0);
|
|
25077
|
+
}
|
|
25078
|
+
}
|
|
25079
|
+
|
|
25080
|
+
// src/agent-installation/managed-agent-archive.ts
|
|
25081
|
+
var ARCHIVE_DOWNLOAD_LIMIT_BYTES = 128 * 1024 * 1024;
|
|
25082
|
+
var ARCHIVE_DOWNLOAD_TIMEOUT_MILLISECONDS = 2 * 60 * 1e3;
|
|
25083
|
+
var ARCHIVE_EXTRACTION_TIMEOUT_MILLISECONDS = 6e4;
|
|
25084
|
+
var MANIFEST_LIMIT_BYTES = 16 * 1024;
|
|
25085
|
+
var MINIMAL_PATH = "/usr/bin:/bin";
|
|
25086
|
+
var ManagedAgentArchiveDefinition = class {
|
|
25087
|
+
archiveName;
|
|
25088
|
+
archiveSha256;
|
|
25089
|
+
archiveUrl;
|
|
25090
|
+
executableName;
|
|
25091
|
+
version;
|
|
25092
|
+
constructor(version2, archiveName, archiveUrl, archiveSha256, executableName) {
|
|
25093
|
+
this.archiveName = archiveName;
|
|
25094
|
+
this.archiveSha256 = archiveSha256;
|
|
25095
|
+
this.archiveUrl = new URL(archiveUrl);
|
|
25096
|
+
this.executableName = executableName;
|
|
25097
|
+
this.version = version2;
|
|
25098
|
+
}
|
|
25099
|
+
};
|
|
25100
|
+
var ZipManagedAgentArchiveDefinition = class extends ManagedAgentArchiveDefinition {
|
|
25101
|
+
extractor = "/usr/bin/unzip";
|
|
25102
|
+
extractArguments = (archivePath, destination) => ["-q", archivePath, "-d", destination];
|
|
25103
|
+
listArguments = (archivePath) => [
|
|
25104
|
+
"-Z1",
|
|
25105
|
+
archivePath
|
|
25106
|
+
];
|
|
25107
|
+
};
|
|
25108
|
+
var TarGzipManagedAgentArchiveDefinition = class extends ManagedAgentArchiveDefinition {
|
|
25109
|
+
extractor = "/usr/bin/tar";
|
|
25110
|
+
extractArguments = (archivePath, destination) => ["-xzf", archivePath, "-C", destination];
|
|
25111
|
+
listArguments = (archivePath) => [
|
|
25112
|
+
"-tzf",
|
|
25113
|
+
archivePath
|
|
25114
|
+
];
|
|
25115
|
+
};
|
|
25116
|
+
var ManagedAgentArchiveError = class extends Error {
|
|
25117
|
+
code;
|
|
25118
|
+
constructor(code, message, options = {}) {
|
|
25119
|
+
super(message, options);
|
|
25120
|
+
this.code = code;
|
|
25121
|
+
this.name = "ManagedAgentArchiveError";
|
|
25122
|
+
}
|
|
25123
|
+
};
|
|
25124
|
+
var ManagedAgentArchiveDownloader = class {
|
|
25125
|
+
download = async (options) => await downloadVerifiedFile(options);
|
|
25126
|
+
};
|
|
25127
|
+
function isRecord6(value) {
|
|
25128
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
25129
|
+
}
|
|
25130
|
+
function isContainedPath2(root, candidate) {
|
|
25131
|
+
const difference = relative2(root, candidate);
|
|
25132
|
+
return difference.length > 0 && difference !== ".." && !difference.startsWith(`..${sep2}`) && !isAbsolute3(difference);
|
|
25133
|
+
}
|
|
25134
|
+
async function hashFile(path2, signal) {
|
|
25135
|
+
signal.throwIfAborted();
|
|
25136
|
+
const digest = createHash2("sha256");
|
|
25137
|
+
const stream = createReadStream(path2, { signal });
|
|
25138
|
+
try {
|
|
25139
|
+
for await (const chunk of stream) {
|
|
25140
|
+
signal.throwIfAborted();
|
|
25141
|
+
if (!(chunk instanceof Uint8Array)) {
|
|
25142
|
+
throw new ManagedAgentArchiveError(
|
|
25143
|
+
"managed_archive_verification_failed",
|
|
25144
|
+
"The managed Agent archive produced invalid bytes"
|
|
25145
|
+
);
|
|
25146
|
+
}
|
|
25147
|
+
digest.update(chunk);
|
|
25148
|
+
}
|
|
25149
|
+
return digest.digest("hex");
|
|
25150
|
+
} catch (error61) {
|
|
25151
|
+
if (signal.aborted) {
|
|
25152
|
+
signal.throwIfAborted();
|
|
25153
|
+
}
|
|
25154
|
+
if (error61 instanceof ManagedAgentArchiveError) {
|
|
25155
|
+
throw error61;
|
|
25156
|
+
}
|
|
25157
|
+
throw new ManagedAgentArchiveError(
|
|
25158
|
+
"managed_archive_verification_failed",
|
|
25159
|
+
"The managed Agent artifact could not be verified",
|
|
25160
|
+
{ cause: error61 }
|
|
25161
|
+
);
|
|
25162
|
+
}
|
|
25163
|
+
}
|
|
25164
|
+
async function readManifest(path2) {
|
|
25165
|
+
let handle;
|
|
25166
|
+
try {
|
|
25167
|
+
handle = await open5(path2, "r");
|
|
25168
|
+
} catch (error61) {
|
|
25169
|
+
throw new ManagedAgentArchiveError(
|
|
25170
|
+
"managed_archive_verification_failed",
|
|
25171
|
+
"The managed Agent archive manifest is invalid",
|
|
25172
|
+
{ cause: error61 }
|
|
25173
|
+
);
|
|
25174
|
+
}
|
|
25175
|
+
try {
|
|
25176
|
+
const metadata = await handle.stat();
|
|
25177
|
+
if (!metadata.isFile() || metadata.size > MANIFEST_LIMIT_BYTES) {
|
|
25178
|
+
throw new ManagedAgentArchiveError(
|
|
25179
|
+
"managed_archive_verification_failed",
|
|
25180
|
+
"The managed Agent archive manifest is invalid"
|
|
25181
|
+
);
|
|
25182
|
+
}
|
|
25183
|
+
const parsed = JSON.parse(
|
|
25184
|
+
await handle.readFile({ encoding: "utf8" })
|
|
25185
|
+
);
|
|
25186
|
+
if (!isRecord6(parsed)) {
|
|
25187
|
+
throw new ManagedAgentArchiveError(
|
|
25188
|
+
"managed_archive_verification_failed",
|
|
25189
|
+
"The managed Agent archive manifest is invalid"
|
|
25190
|
+
);
|
|
25191
|
+
}
|
|
25192
|
+
return parsed;
|
|
25193
|
+
} catch (error61) {
|
|
25194
|
+
if (error61 instanceof ManagedAgentArchiveError) {
|
|
25195
|
+
throw error61;
|
|
25196
|
+
}
|
|
25197
|
+
throw new ManagedAgentArchiveError(
|
|
25198
|
+
"managed_archive_verification_failed",
|
|
25199
|
+
"The managed Agent archive manifest is invalid",
|
|
25200
|
+
{ cause: error61 }
|
|
25201
|
+
);
|
|
25202
|
+
} finally {
|
|
25203
|
+
await handle.close();
|
|
25204
|
+
}
|
|
25205
|
+
}
|
|
25206
|
+
async function validateManagedAgentArchive(root, definition, signal) {
|
|
25207
|
+
try {
|
|
25208
|
+
const rootPath = await realpath4(root);
|
|
25209
|
+
const rootMetadata = await stat4(rootPath);
|
|
25210
|
+
if (!rootMetadata.isDirectory() || typeof process.getuid === "function" && rootMetadata.uid !== process.getuid()) {
|
|
25211
|
+
throw new Error("Managed Agent root is not user-owned");
|
|
25212
|
+
}
|
|
25213
|
+
const manifest = await readManifest(join8(rootPath, "archive.json"));
|
|
25214
|
+
if (manifest["archiveSha256"] !== definition.archiveSha256 || manifest["archiveUrl"] !== definition.archiveUrl.toString() || manifest["version"] !== definition.version || typeof manifest["executableSha256"] !== "string") {
|
|
25215
|
+
throw new Error("Managed Agent archive identity is invalid");
|
|
25216
|
+
}
|
|
25217
|
+
const executable = await resolveExecutablePath(
|
|
25218
|
+
join8(rootPath, "bin", definition.executableName)
|
|
25219
|
+
);
|
|
25220
|
+
if (executable === null || !isContainedPath2(rootPath, executable.path) || await hashFile(executable.path, signal) !== manifest["executableSha256"]) {
|
|
25221
|
+
throw new Error("Managed Agent executable is invalid");
|
|
25222
|
+
}
|
|
25223
|
+
return executable;
|
|
25224
|
+
} catch (error61) {
|
|
25225
|
+
if (signal.aborted) {
|
|
25226
|
+
signal.throwIfAborted();
|
|
25227
|
+
}
|
|
25228
|
+
if (error61 instanceof ManagedAgentArchiveError) {
|
|
25229
|
+
throw error61;
|
|
25230
|
+
}
|
|
25231
|
+
throw new ManagedAgentArchiveError(
|
|
25232
|
+
"managed_archive_verification_failed",
|
|
25233
|
+
"The managed Agent archive did not match its pinned artifact",
|
|
25234
|
+
{ cause: error61 }
|
|
25235
|
+
);
|
|
25236
|
+
}
|
|
25237
|
+
}
|
|
25238
|
+
function validateArchiveEntries(output2, definition) {
|
|
25239
|
+
const entries = output2.split(/\r?\n/).map((entry) => entry.trim()).filter((entry) => entry.length > 0);
|
|
25240
|
+
if (entries.length !== 1 || entries[0] !== definition.executableName && entries[0] !== `./${definition.executableName}`) {
|
|
25241
|
+
throw new ManagedAgentArchiveError(
|
|
25242
|
+
"managed_archive_verification_failed",
|
|
25243
|
+
"The managed Agent archive contains unexpected entries"
|
|
25244
|
+
);
|
|
25245
|
+
}
|
|
25246
|
+
}
|
|
25247
|
+
var ManagedAgentArchiveInstaller = class {
|
|
25248
|
+
#downloader;
|
|
25249
|
+
constructor(downloader = new ManagedAgentArchiveDownloader()) {
|
|
25250
|
+
this.#downloader = downloader;
|
|
25251
|
+
}
|
|
25252
|
+
install = async (root, definition, signal) => {
|
|
25253
|
+
signal.throwIfAborted();
|
|
25254
|
+
try {
|
|
25255
|
+
const metadata = await stat4(root);
|
|
25256
|
+
if (metadata.isDirectory()) {
|
|
25257
|
+
return await validateManagedAgentArchive(root, definition, signal);
|
|
25258
|
+
}
|
|
25259
|
+
} catch (error61) {
|
|
25260
|
+
if (error61 instanceof ManagedAgentArchiveError || !(error61 instanceof Error) || !("code" in error61) || error61.code !== "ENOENT") {
|
|
25261
|
+
throw error61;
|
|
25262
|
+
}
|
|
25263
|
+
}
|
|
25264
|
+
const parent = dirname4(root);
|
|
25265
|
+
await mkdir2(parent, { mode: 448, recursive: true });
|
|
25266
|
+
const working = await mkdtemp2(
|
|
25267
|
+
join8(parent, `.${definition.version}.archive-`)
|
|
25268
|
+
);
|
|
25269
|
+
const staging = await mkdtemp2(
|
|
25270
|
+
join8(parent, `.${definition.version}.staging-`)
|
|
25271
|
+
);
|
|
25272
|
+
try {
|
|
25273
|
+
const archivePath = join8(working, definition.archiveName);
|
|
25274
|
+
const extractionRoot = join8(working, "extracted");
|
|
25275
|
+
await mkdir2(extractionRoot, { mode: 448 });
|
|
25276
|
+
const canonicalExtractionRoot = await realpath4(extractionRoot);
|
|
25277
|
+
const download = await this.#downloader.download({
|
|
25278
|
+
allowedHosts: /* @__PURE__ */ new Set([
|
|
25279
|
+
"github.com",
|
|
25280
|
+
"objects.githubusercontent.com",
|
|
25281
|
+
"release-assets.githubusercontent.com"
|
|
25282
|
+
]),
|
|
25283
|
+
destination: archivePath,
|
|
25284
|
+
maximumBytes: ARCHIVE_DOWNLOAD_LIMIT_BYTES,
|
|
25285
|
+
signal,
|
|
25286
|
+
timeoutMilliseconds: ARCHIVE_DOWNLOAD_TIMEOUT_MILLISECONDS,
|
|
25287
|
+
url: definition.archiveUrl
|
|
25288
|
+
});
|
|
25289
|
+
if (download.sha256 !== definition.archiveSha256) {
|
|
25290
|
+
throw new ManagedAgentArchiveError(
|
|
25291
|
+
"managed_archive_verification_failed",
|
|
25292
|
+
"The managed Agent archive checksum is invalid"
|
|
25293
|
+
);
|
|
25294
|
+
}
|
|
25295
|
+
const list = await runBoundedProcess({
|
|
25296
|
+
arguments: definition.listArguments(archivePath),
|
|
25297
|
+
command: definition.extractor,
|
|
25298
|
+
cwd: working,
|
|
25299
|
+
environment: { PATH: MINIMAL_PATH },
|
|
25300
|
+
outputLimitBytes: 64 * 1024,
|
|
25301
|
+
signal,
|
|
25302
|
+
timeoutMilliseconds: ARCHIVE_EXTRACTION_TIMEOUT_MILLISECONDS
|
|
25303
|
+
});
|
|
25304
|
+
validateArchiveEntries(list.stdout, definition);
|
|
25305
|
+
await runBoundedProcess({
|
|
25306
|
+
arguments: definition.extractArguments(archivePath, extractionRoot),
|
|
25307
|
+
command: definition.extractor,
|
|
25308
|
+
cwd: working,
|
|
25309
|
+
environment: { PATH: MINIMAL_PATH },
|
|
25310
|
+
outputLimitBytes: 64 * 1024,
|
|
25311
|
+
signal,
|
|
25312
|
+
timeoutMilliseconds: ARCHIVE_EXTRACTION_TIMEOUT_MILLISECONDS
|
|
25313
|
+
});
|
|
25314
|
+
const extracted = await realpath4(
|
|
25315
|
+
join8(canonicalExtractionRoot, definition.executableName)
|
|
25316
|
+
);
|
|
25317
|
+
const extractedMetadata = await stat4(extracted);
|
|
25318
|
+
if (!isContainedPath2(canonicalExtractionRoot, extracted) || !extractedMetadata.isFile()) {
|
|
25319
|
+
throw new ManagedAgentArchiveError(
|
|
25320
|
+
"managed_archive_verification_failed",
|
|
25321
|
+
"The managed Agent archive executable is invalid"
|
|
25322
|
+
);
|
|
25323
|
+
}
|
|
25324
|
+
const binDirectory = join8(staging, "bin");
|
|
25325
|
+
const executablePath = join8(binDirectory, definition.executableName);
|
|
25326
|
+
await mkdir2(binDirectory, { mode: 448 });
|
|
25327
|
+
await copyFile(extracted, executablePath);
|
|
25328
|
+
await chmod(executablePath, 448);
|
|
25329
|
+
const executableSha256 = await hashFile(executablePath, signal);
|
|
25330
|
+
await writeFile(
|
|
25331
|
+
join8(staging, "archive.json"),
|
|
25332
|
+
`${JSON.stringify({
|
|
25333
|
+
archiveSha256: definition.archiveSha256,
|
|
25334
|
+
archiveUrl: definition.archiveUrl.toString(),
|
|
25335
|
+
executableSha256,
|
|
25336
|
+
version: definition.version
|
|
25337
|
+
})}
|
|
25338
|
+
`,
|
|
25339
|
+
{ mode: 384 }
|
|
25340
|
+
);
|
|
25341
|
+
await validateManagedAgentArchive(staging, definition, signal);
|
|
25342
|
+
try {
|
|
25343
|
+
await rename2(staging, root);
|
|
25344
|
+
} catch (error61) {
|
|
25345
|
+
try {
|
|
25346
|
+
return await validateManagedAgentArchive(root, definition, signal);
|
|
25347
|
+
} catch {
|
|
25348
|
+
throw new ManagedAgentArchiveError(
|
|
25349
|
+
"managed_archive_publish_failed",
|
|
25350
|
+
"The managed Agent archive could not be published",
|
|
25351
|
+
{ cause: error61 }
|
|
25352
|
+
);
|
|
25353
|
+
}
|
|
25354
|
+
}
|
|
25355
|
+
return await validateManagedAgentArchive(root, definition, signal);
|
|
25356
|
+
} catch (error61) {
|
|
25357
|
+
if (signal.aborted) {
|
|
25358
|
+
signal.throwIfAborted();
|
|
25359
|
+
}
|
|
25360
|
+
if (error61 instanceof ManagedAgentArchiveError) {
|
|
25361
|
+
throw error61;
|
|
25362
|
+
}
|
|
25363
|
+
throw new ManagedAgentArchiveError(
|
|
25364
|
+
"managed_archive_install_failed",
|
|
25365
|
+
"The pinned Agent archive could not be installed",
|
|
25366
|
+
{ cause: error61 }
|
|
25367
|
+
);
|
|
25368
|
+
} finally {
|
|
25369
|
+
await Promise.all([
|
|
25370
|
+
rm2(working, { force: true, recursive: true }),
|
|
25371
|
+
rm2(staging, { force: true, recursive: true })
|
|
25372
|
+
]);
|
|
25373
|
+
}
|
|
25374
|
+
};
|
|
25375
|
+
};
|
|
25376
|
+
|
|
25377
|
+
// src/agent-installation/opencode-managed-release.ts
|
|
25378
|
+
var OPENCODE_MANAGED_VERSION = "1.18.29";
|
|
25379
|
+
function releaseUrl(asset) {
|
|
25380
|
+
return new URL(
|
|
25381
|
+
`https://github.com/anomalyco/opencode/releases/download/v${OPENCODE_MANAGED_VERSION}/${asset}`
|
|
24453
25382
|
);
|
|
24454
|
-
|
|
24455
|
-
|
|
24456
|
-
|
|
24457
|
-
|
|
24458
|
-
|
|
24459
|
-
|
|
24460
|
-
|
|
24461
|
-
|
|
24462
|
-
|
|
24463
|
-
|
|
24464
|
-
|
|
24465
|
-
|
|
24466
|
-
|
|
24467
|
-
|
|
24468
|
-
|
|
24469
|
-
|
|
24470
|
-
|
|
24471
|
-
|
|
24472
|
-
|
|
24473
|
-
|
|
24474
|
-
|
|
24475
|
-
|
|
25383
|
+
}
|
|
25384
|
+
function openCodeManagedArchive(platform, architecture) {
|
|
25385
|
+
if (platform === "darwin" && architecture === "arm64") {
|
|
25386
|
+
const asset = "opencode-darwin-arm64.zip";
|
|
25387
|
+
return new ZipManagedAgentArchiveDefinition(
|
|
25388
|
+
OPENCODE_MANAGED_VERSION,
|
|
25389
|
+
asset,
|
|
25390
|
+
releaseUrl(asset),
|
|
25391
|
+
"fe764f7f360c584a83e18dd5f23fb1a6b2725f5ee8854b0252fe558f7798e946",
|
|
25392
|
+
"opencode"
|
|
25393
|
+
);
|
|
25394
|
+
}
|
|
25395
|
+
if (platform === "darwin" && architecture === "x64") {
|
|
25396
|
+
const asset = "opencode-darwin-x64.zip";
|
|
25397
|
+
return new ZipManagedAgentArchiveDefinition(
|
|
25398
|
+
OPENCODE_MANAGED_VERSION,
|
|
25399
|
+
asset,
|
|
25400
|
+
releaseUrl(asset),
|
|
25401
|
+
"9858853e7bacdbbd22c2d70c377e009dc4b354dd04f5588705411e7afb89fd2d",
|
|
25402
|
+
"opencode"
|
|
25403
|
+
);
|
|
25404
|
+
}
|
|
25405
|
+
if (platform === "linux" && architecture === "arm64") {
|
|
25406
|
+
const asset = "opencode-linux-arm64.tar.gz";
|
|
25407
|
+
return new TarGzipManagedAgentArchiveDefinition(
|
|
25408
|
+
OPENCODE_MANAGED_VERSION,
|
|
25409
|
+
asset,
|
|
25410
|
+
releaseUrl(asset),
|
|
25411
|
+
"70baf769395ca4e7a68924026530c390eace194f3b7e4919d4efcb2aa2eed3c0",
|
|
25412
|
+
"opencode"
|
|
25413
|
+
);
|
|
25414
|
+
}
|
|
25415
|
+
if (platform === "linux" && architecture === "x64") {
|
|
25416
|
+
const asset = "opencode-linux-x64.tar.gz";
|
|
25417
|
+
return new TarGzipManagedAgentArchiveDefinition(
|
|
25418
|
+
OPENCODE_MANAGED_VERSION,
|
|
25419
|
+
asset,
|
|
25420
|
+
releaseUrl(asset),
|
|
25421
|
+
"ea800b7ff56226b70952126c9fc1e2517ca4c4b5682fd9d3f9e87449697a1194",
|
|
25422
|
+
"opencode"
|
|
25423
|
+
);
|
|
25424
|
+
}
|
|
25425
|
+
throw new Error(
|
|
25426
|
+
"OpenCode does not publish an approved archive for this platform"
|
|
25427
|
+
);
|
|
25428
|
+
}
|
|
25429
|
+
|
|
25430
|
+
// src/agent-catalog/agents/opencode-agent.ts
|
|
25431
|
+
var OpenCodeAgentSpecification = class extends DirectAcpAgentDefinition {
|
|
25432
|
+
versionProbeTimeoutMilliseconds = 15e3;
|
|
25433
|
+
adapterVersion = OPENCODE_MANAGED_VERSION;
|
|
25434
|
+
authenticationCommand = () => "opencode auth login";
|
|
25435
|
+
agentExecutable = "opencode";
|
|
25436
|
+
id = "opencode";
|
|
25437
|
+
label = "OpenCode";
|
|
25438
|
+
constructor() {
|
|
25439
|
+
super(
|
|
25440
|
+
"MOBIUS_OPENCODE_PATH",
|
|
25441
|
+
["acp"],
|
|
25442
|
+
[
|
|
25443
|
+
"agents",
|
|
25444
|
+
"opencode",
|
|
25445
|
+
OPENCODE_MANAGED_VERSION,
|
|
25446
|
+
"bin",
|
|
25447
|
+
process.platform === "win32" ? "opencode.exe" : "opencode"
|
|
25448
|
+
]
|
|
25449
|
+
);
|
|
25450
|
+
}
|
|
25451
|
+
createLaunchEnvironment = async (_agent, _context) => Object.freeze({ OPENCODE_DISABLE_AUTOUPDATE: "1" });
|
|
25452
|
+
resolveManagedAgent = async (stateDirectory, platform, signal) => await validateManagedAgentArchive(
|
|
25453
|
+
join9(stateDirectory, "agents", this.id, OPENCODE_MANAGED_VERSION),
|
|
25454
|
+
openCodeManagedArchive(platform, process.arch),
|
|
25455
|
+
signal
|
|
25456
|
+
);
|
|
25457
|
+
verifyAcp = (_connection, initialized, _defaultWorkspace, _signal) => {
|
|
25458
|
+
const capabilities = initialized.agentCapabilities ?? {};
|
|
25459
|
+
const session = capabilities.sessionCapabilities;
|
|
25460
|
+
if (capabilities.loadSession !== true || session?.close == null || session.list == null || session.resume == null) {
|
|
25461
|
+
throw new AgentProbeError(
|
|
25462
|
+
"acp_incompatible",
|
|
25463
|
+
"OpenCode does not support the required ACP session lifecycle"
|
|
25464
|
+
);
|
|
25465
|
+
}
|
|
25466
|
+
return Promise.resolve();
|
|
25467
|
+
};
|
|
24476
25468
|
};
|
|
25469
|
+
|
|
25470
|
+
// src/agent-catalog/agents/pi-agent.ts
|
|
25471
|
+
import { join as join10 } from "node:path";
|
|
25472
|
+
import {
|
|
25473
|
+
methods as methods3
|
|
25474
|
+
} from "@agentclientprotocol/sdk";
|
|
25475
|
+
|
|
25476
|
+
// src/agent-installation/pi-managed-packages.ts
|
|
25477
|
+
var PI_ACP_PACKAGE = new SriManagedNpmPackageDefinition(
|
|
25478
|
+
"pi-acp",
|
|
25479
|
+
"0.0.33",
|
|
25480
|
+
"pi-acp",
|
|
25481
|
+
"sha512-vX9kY1tK14E72G4dBAx+RGCk/k7XPjTHls6dLUxA8WSkBav6B6JHuSBv3eusp50LCR/GTRsR2kIKsG0Z5jANzw==",
|
|
25482
|
+
"https://registry.npmjs.org/pi-acp/-/pi-acp-0.0.33.tgz"
|
|
25483
|
+
);
|
|
25484
|
+
var PI_AGENT_PACKAGE = new SriManagedNpmPackageDefinition(
|
|
25485
|
+
"@earendil-works/pi-coding-agent",
|
|
25486
|
+
"0.85.0",
|
|
25487
|
+
"pi",
|
|
25488
|
+
"sha512-INxVkLAVfAMju5MojJpmyu/0bMP+r+ffZuS7UqVv32E2JwHBRbcHfELDfmFNvapEbgYfKN2r9OYO1p3TqDBR+g==",
|
|
25489
|
+
"https://registry.npmjs.org/@earendil-works/pi-coding-agent/-/pi-coding-agent-0.85.0.tgz"
|
|
25490
|
+
);
|
|
25491
|
+
|
|
25492
|
+
// src/agent-catalog/agents/pi-agent.ts
|
|
25493
|
+
var ACP_PROBE_TIMEOUT_MILLISECONDS2 = 3e4;
|
|
25494
|
+
var PROMPT_TIMEOUT_MILLISECONDS = 5 * 60 * 1e3;
|
|
24477
25495
|
var PiAgentSpecification = class extends BridgedAcpAgentDefinition {
|
|
24478
|
-
acpProbeTimeoutMilliseconds =
|
|
25496
|
+
acpProbeTimeoutMilliseconds = ACP_PROBE_TIMEOUT_MILLISECONDS2;
|
|
24479
25497
|
adapterEnvironmentVariable = "PI_ACP_PI_COMMAND";
|
|
24480
25498
|
adapterOverrideVariable = "MOBIUS_PI_ACP_PATH";
|
|
24481
25499
|
adapterPackageDefinition = PI_ACP_PACKAGE;
|
|
@@ -24505,11 +25523,16 @@ var PiAgentSpecification = class extends BridgedAcpAgentDefinition {
|
|
|
24505
25523
|
"bundle",
|
|
24506
25524
|
"cli.js"
|
|
24507
25525
|
];
|
|
24508
|
-
promptTimeoutMilliseconds =
|
|
24509
|
-
resolveManagedAgent = async (stateDirectory, _platform) =>
|
|
24510
|
-
|
|
24511
|
-
|
|
24512
|
-
|
|
25526
|
+
promptTimeoutMilliseconds = PROMPT_TIMEOUT_MILLISECONDS;
|
|
25527
|
+
resolveManagedAgent = async (stateDirectory, _platform, signal) => {
|
|
25528
|
+
signal.throwIfAborted();
|
|
25529
|
+
const executable = await validateManagedNpmPackage(
|
|
25530
|
+
join10(stateDirectory, "agents", this.id, PI_AGENT_PACKAGE.version),
|
|
25531
|
+
PI_AGENT_PACKAGE
|
|
25532
|
+
);
|
|
25533
|
+
signal.throwIfAborted();
|
|
25534
|
+
return executable;
|
|
25535
|
+
};
|
|
24513
25536
|
verifyAcp = async (connection, initialized, defaultWorkspace, signal) => {
|
|
24514
25537
|
const capabilities = initialized.agentCapabilities ?? {};
|
|
24515
25538
|
if (capabilities.loadSession !== true) {
|
|
@@ -24549,138 +25572,134 @@ var PiAgentSpecification = class extends BridgedAcpAgentDefinition {
|
|
|
24549
25572
|
}
|
|
24550
25573
|
};
|
|
24551
25574
|
};
|
|
25575
|
+
|
|
25576
|
+
// src/agent-catalog/agents/supported-agent-specifications.ts
|
|
24552
25577
|
function supportedLocalAgentSpecifications() {
|
|
24553
25578
|
return Object.freeze([
|
|
24554
25579
|
new CodexAgentSpecification(),
|
|
24555
25580
|
new ClaudeCodeAgentSpecification(),
|
|
24556
|
-
new PiAgentSpecification()
|
|
25581
|
+
new PiAgentSpecification(),
|
|
25582
|
+
new DeepSeekHarnessAgentSpecification(),
|
|
25583
|
+
new OpenCodeAgentSpecification()
|
|
24557
25584
|
]);
|
|
24558
25585
|
}
|
|
24559
|
-
|
|
24560
|
-
|
|
24561
|
-
|
|
24562
|
-
|
|
24563
|
-
|
|
24564
|
-
|
|
24565
|
-
|
|
24566
|
-
|
|
24567
|
-
|
|
24568
|
-
|
|
24569
|
-
|
|
24570
|
-
|
|
24571
|
-
|
|
24572
|
-
|
|
24573
|
-
|
|
24574
|
-
|
|
24575
|
-
var MissingAdapter = class extends UnavailableAgent {
|
|
24576
|
-
code = "adapter_not_found";
|
|
24577
|
-
message = "ACP adapter not found";
|
|
24578
|
-
status = "missing_adapter";
|
|
24579
|
-
constructor(specification) {
|
|
24580
|
-
super(specification);
|
|
24581
|
-
}
|
|
24582
|
-
};
|
|
24583
|
-
var MissingAgent = class extends UnavailableAgent {
|
|
24584
|
-
code = "agent_not_found";
|
|
24585
|
-
message = "Agent executable not found";
|
|
24586
|
-
status = "missing_agent";
|
|
24587
|
-
constructor(specification) {
|
|
24588
|
-
super(specification);
|
|
24589
|
-
}
|
|
24590
|
-
};
|
|
24591
|
-
var ProbeFailed = class extends UnavailableAgent {
|
|
25586
|
+
|
|
25587
|
+
// src/agent-catalog/acp-readiness-probe.ts
|
|
25588
|
+
import { spawn as spawn3 } from "node:child_process";
|
|
25589
|
+
import {
|
|
25590
|
+
methods as methods4,
|
|
25591
|
+
ndJsonStream as ndJsonStream2,
|
|
25592
|
+
PROTOCOL_VERSION as PROTOCOL_VERSION2,
|
|
25593
|
+
RequestError as RequestError2
|
|
25594
|
+
} from "@agentclientprotocol/sdk";
|
|
25595
|
+
|
|
25596
|
+
// src/agent-catalog/executable-discovery.ts
|
|
25597
|
+
import { isAbsolute as isAbsolute4, join as join12 } from "node:path";
|
|
25598
|
+
|
|
25599
|
+
// src/agent-installation/managed-adapter-installer.ts
|
|
25600
|
+
import { join as join11 } from "node:path";
|
|
25601
|
+
var ManagedAdapterInstallError = class extends Error {
|
|
24592
25602
|
code;
|
|
24593
|
-
message
|
|
24594
|
-
|
|
24595
|
-
constructor(specification, code, message) {
|
|
24596
|
-
super(specification);
|
|
25603
|
+
constructor(code, message, options = {}) {
|
|
25604
|
+
super(message, options);
|
|
24597
25605
|
this.code = code;
|
|
24598
|
-
this.
|
|
24599
|
-
}
|
|
24600
|
-
};
|
|
24601
|
-
var IncompatibleAdapter = class extends UnavailableAgent {
|
|
24602
|
-
code = "acp_incompatible";
|
|
24603
|
-
message = "ACP adapter is incompatible";
|
|
24604
|
-
status = "incompatible_adapter";
|
|
24605
|
-
constructor(specification) {
|
|
24606
|
-
super(specification);
|
|
25606
|
+
this.name = "ManagedAdapterInstallError";
|
|
24607
25607
|
}
|
|
24608
25608
|
};
|
|
24609
|
-
|
|
24610
|
-
|
|
24611
|
-
|
|
24612
|
-
status = "authentication_required";
|
|
24613
|
-
constructor(specification) {
|
|
24614
|
-
super(specification);
|
|
25609
|
+
function translateError(error61) {
|
|
25610
|
+
if (error61 instanceof ManagedAdapterInstallError) {
|
|
25611
|
+
return error61;
|
|
24615
25612
|
}
|
|
24616
|
-
|
|
24617
|
-
|
|
24618
|
-
|
|
24619
|
-
|
|
24620
|
-
|
|
24621
|
-
|
|
24622
|
-
|
|
24623
|
-
const available = [];
|
|
24624
|
-
const unavailable = [];
|
|
24625
|
-
for (const discovery of discoveries) {
|
|
24626
|
-
if (discovery instanceof AvailableAgent) {
|
|
24627
|
-
available.push(discovery);
|
|
24628
|
-
} else if (discovery instanceof UnavailableAgent) {
|
|
24629
|
-
unavailable.push(discovery);
|
|
24630
|
-
} else {
|
|
24631
|
-
throw new Error("Unsupported Agent discovery outcome");
|
|
24632
|
-
}
|
|
25613
|
+
if (error61 instanceof ManagedNpmPackageError) {
|
|
25614
|
+
if (error61.code === "package_manager_not_found") {
|
|
25615
|
+
return new ManagedAdapterInstallError(
|
|
25616
|
+
error61.code,
|
|
25617
|
+
"A supported npm executable is required to install the ACP adapter",
|
|
25618
|
+
{ cause: error61 }
|
|
25619
|
+
);
|
|
24633
25620
|
}
|
|
24634
|
-
|
|
24635
|
-
|
|
24636
|
-
|
|
24637
|
-
|
|
24638
|
-
|
|
24639
|
-
|
|
24640
|
-
|
|
24641
|
-
|
|
24642
|
-
|
|
24643
|
-
|
|
24644
|
-
|
|
24645
|
-
|
|
24646
|
-
|
|
24647
|
-
|
|
24648
|
-
|
|
25621
|
+
if (error61.code === "managed_package_verification_failed") {
|
|
25622
|
+
return new ManagedAdapterInstallError(
|
|
25623
|
+
"adapter_verification_failed",
|
|
25624
|
+
"The managed adapter did not match its pinned artifact",
|
|
25625
|
+
{ cause: error61 }
|
|
25626
|
+
);
|
|
25627
|
+
}
|
|
25628
|
+
if (error61.code === "managed_package_publish_failed") {
|
|
25629
|
+
return new ManagedAdapterInstallError(
|
|
25630
|
+
"adapter_publish_failed",
|
|
25631
|
+
"The managed adapter could not be published",
|
|
25632
|
+
{ cause: error61 }
|
|
25633
|
+
);
|
|
25634
|
+
}
|
|
25635
|
+
}
|
|
25636
|
+
return new ManagedAdapterInstallError(
|
|
25637
|
+
"adapter_install_failed",
|
|
25638
|
+
"The pinned ACP adapter could not be installed",
|
|
25639
|
+
{ cause: error61 }
|
|
25640
|
+
);
|
|
25641
|
+
}
|
|
25642
|
+
async function validateManagedAdapter(root, specification) {
|
|
25643
|
+
try {
|
|
25644
|
+
return await validateManagedNpmPackage(
|
|
25645
|
+
root,
|
|
25646
|
+
specification.adapterPackageDefinition
|
|
24649
25647
|
);
|
|
24650
|
-
|
|
25648
|
+
} catch (error61) {
|
|
25649
|
+
throw translateError(error61);
|
|
24651
25650
|
}
|
|
24652
|
-
|
|
24653
|
-
|
|
24654
|
-
|
|
24655
|
-
|
|
24656
|
-
|
|
24657
|
-
|
|
24658
|
-
this
|
|
24659
|
-
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;
|
|
24660
25660
|
}
|
|
25661
|
+
install = async (specification, signal) => {
|
|
25662
|
+
const root = join11(
|
|
25663
|
+
this.#stateDirectory,
|
|
25664
|
+
"adapters",
|
|
25665
|
+
specification.id,
|
|
25666
|
+
specification.adapterVersion
|
|
25667
|
+
);
|
|
25668
|
+
try {
|
|
25669
|
+
return await this.#npmInstaller.install(
|
|
25670
|
+
root,
|
|
25671
|
+
specification.adapterPackageDefinition,
|
|
25672
|
+
this.#environment,
|
|
25673
|
+
signal
|
|
25674
|
+
);
|
|
25675
|
+
} catch (error61) {
|
|
25676
|
+
if (signal.aborted) {
|
|
25677
|
+
signal.throwIfAborted();
|
|
25678
|
+
}
|
|
25679
|
+
throw translateError(error61);
|
|
25680
|
+
}
|
|
25681
|
+
};
|
|
24661
25682
|
};
|
|
24662
|
-
|
|
24663
|
-
|
|
24664
|
-
|
|
24665
|
-
onPermission = (_request, _signal) => Promise.reject(new Error("ACP probe does not grant permissions"));
|
|
24666
|
-
onUpdate = (_notification) => Promise.resolve();
|
|
24667
|
-
};
|
|
24668
|
-
async function resolveManagedExecutable(specification, options) {
|
|
25683
|
+
|
|
25684
|
+
// src/agent-catalog/executable-discovery.ts
|
|
25685
|
+
async function resolveManagedExecutable(specification, context) {
|
|
24669
25686
|
try {
|
|
24670
25687
|
return await specification.resolveManagedAgent(
|
|
24671
|
-
readStateDirectory(
|
|
24672
|
-
|
|
25688
|
+
readStateDirectory(context.environment),
|
|
25689
|
+
context.platform ?? process.platform,
|
|
25690
|
+
context.signal
|
|
24673
25691
|
);
|
|
24674
25692
|
} catch {
|
|
25693
|
+
context.signal.throwIfAborted();
|
|
24675
25694
|
return null;
|
|
24676
25695
|
}
|
|
24677
25696
|
}
|
|
24678
|
-
async function resolveManagedAdapterExecutable(specification,
|
|
25697
|
+
async function resolveManagedAdapterExecutable(specification, context) {
|
|
24679
25698
|
let managed;
|
|
24680
25699
|
try {
|
|
24681
25700
|
managed = await validateManagedAdapter(
|
|
24682
|
-
|
|
24683
|
-
readStateDirectory(
|
|
25701
|
+
join12(
|
|
25702
|
+
readStateDirectory(context.environment),
|
|
24684
25703
|
"adapters",
|
|
24685
25704
|
specification.id,
|
|
24686
25705
|
specification.adapterVersion
|
|
@@ -24692,19 +25711,19 @@ async function resolveManagedAdapterExecutable(specification, options) {
|
|
|
24692
25711
|
}
|
|
24693
25712
|
return managed;
|
|
24694
25713
|
}
|
|
24695
|
-
async function resolveSpecificationExecutables(executableName, overrideVariable, resolveManaged,
|
|
24696
|
-
const override =
|
|
25714
|
+
async function resolveSpecificationExecutables(executableName, overrideVariable, resolveManaged, context) {
|
|
25715
|
+
const override = context.environment[overrideVariable];
|
|
24697
25716
|
if (override !== void 0) {
|
|
24698
|
-
if (override.length === 0 || !
|
|
25717
|
+
if (override.length === 0 || !isAbsolute4(override)) {
|
|
24699
25718
|
return [];
|
|
24700
25719
|
}
|
|
24701
|
-
const executable = await resolveExecutablePath(override,
|
|
25720
|
+
const executable = await resolveExecutablePath(override, context.platform);
|
|
24702
25721
|
return executable === null ? [] : [executable];
|
|
24703
25722
|
}
|
|
24704
25723
|
const external = await findExecutableOnPath(
|
|
24705
25724
|
executableName,
|
|
24706
|
-
|
|
24707
|
-
|
|
25725
|
+
context.environment,
|
|
25726
|
+
context.platform
|
|
24708
25727
|
);
|
|
24709
25728
|
const managed = await resolveManaged();
|
|
24710
25729
|
if (external === null) {
|
|
@@ -24715,41 +25734,47 @@ async function resolveSpecificationExecutables(executableName, overrideVariable,
|
|
|
24715
25734
|
}
|
|
24716
25735
|
return [external, managed];
|
|
24717
25736
|
}
|
|
24718
|
-
async function resolveAgentExecutables(specification,
|
|
25737
|
+
async function resolveAgentExecutables(specification, context) {
|
|
24719
25738
|
return await resolveSpecificationExecutables(
|
|
24720
25739
|
specification.agentExecutable,
|
|
24721
25740
|
specification.agentOverrideVariable,
|
|
24722
|
-
async () => await resolveManagedExecutable(specification,
|
|
24723
|
-
|
|
25741
|
+
async () => await resolveManagedExecutable(specification, context),
|
|
25742
|
+
context
|
|
24724
25743
|
);
|
|
24725
25744
|
}
|
|
24726
|
-
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
|
+
}
|
|
24727
25752
|
return await resolveSpecificationExecutables(
|
|
24728
25753
|
specification.adapterExecutable,
|
|
24729
25754
|
specification.adapterOverrideVariable,
|
|
24730
|
-
async () => await resolveManagedAdapterExecutable(specification,
|
|
24731
|
-
|
|
25755
|
+
async () => await resolveManagedAdapterExecutable(specification, context),
|
|
25756
|
+
context
|
|
24732
25757
|
);
|
|
24733
25758
|
}
|
|
24734
|
-
async function resolveAgentExecutable(specification,
|
|
24735
|
-
const executables = await resolveAgentExecutables(specification,
|
|
25759
|
+
async function resolveAgentExecutable(specification, context) {
|
|
25760
|
+
const executables = await resolveAgentExecutables(specification, context);
|
|
24736
25761
|
return executables[0] ?? null;
|
|
24737
25762
|
}
|
|
24738
|
-
async function resolveAdapterExecutable(specification,
|
|
24739
|
-
const executables = await resolveAdapterExecutables(specification,
|
|
25763
|
+
async function resolveAdapterExecutable(specification, context) {
|
|
25764
|
+
const executables = await resolveAdapterExecutables(specification, context);
|
|
24740
25765
|
return executables[0] ?? null;
|
|
24741
25766
|
}
|
|
24742
25767
|
function normalizedVersion(output2) {
|
|
24743
25768
|
return output2.trim().split(/\r?\n/, 1)[0]?.trim().slice(0, 128) ?? "";
|
|
24744
25769
|
}
|
|
24745
|
-
async function probeVersion(executable, arguments_, environment, defaultWorkspace, signal) {
|
|
25770
|
+
async function probeVersion(executable, arguments_, environment, defaultWorkspace, signal, timeoutMilliseconds) {
|
|
24746
25771
|
const result = await runBoundedProcess({
|
|
24747
25772
|
arguments: arguments_,
|
|
24748
25773
|
command: executable.path,
|
|
24749
25774
|
cwd: defaultWorkspace,
|
|
24750
25775
|
environment,
|
|
24751
25776
|
signal,
|
|
24752
|
-
timeoutMilliseconds
|
|
25777
|
+
timeoutMilliseconds
|
|
24753
25778
|
});
|
|
24754
25779
|
const version2 = normalizedVersion(result.stdout || result.stderr);
|
|
24755
25780
|
if (version2.length === 0) {
|
|
@@ -24768,63 +25793,73 @@ var VerifiedAgentExecutable = class {
|
|
|
24768
25793
|
this.version = version2;
|
|
24769
25794
|
}
|
|
24770
25795
|
};
|
|
24771
|
-
async function findVerifiedAgentExecutable(specification,
|
|
24772
|
-
const executables = await resolveAgentExecutables(specification,
|
|
25796
|
+
async function findVerifiedAgentExecutable(specification, context) {
|
|
25797
|
+
const executables = await resolveAgentExecutables(specification, context);
|
|
24773
25798
|
for (const executable of executables) {
|
|
24774
25799
|
try {
|
|
24775
25800
|
const version2 = await probeVersion(
|
|
24776
25801
|
executable,
|
|
24777
25802
|
specification.agentVersionArguments,
|
|
24778
|
-
|
|
24779
|
-
|
|
24780
|
-
|
|
25803
|
+
context.environment,
|
|
25804
|
+
context.defaultWorkspace,
|
|
25805
|
+
context.signal,
|
|
25806
|
+
specification.versionProbeTimeoutMilliseconds
|
|
24781
25807
|
);
|
|
24782
25808
|
return new VerifiedAgentExecutable(executable, version2);
|
|
24783
25809
|
} catch {
|
|
24784
|
-
if (
|
|
24785
|
-
|
|
25810
|
+
if (context.signal.aborted) {
|
|
25811
|
+
context.signal.throwIfAborted();
|
|
24786
25812
|
}
|
|
24787
25813
|
}
|
|
24788
25814
|
}
|
|
24789
25815
|
return null;
|
|
24790
25816
|
}
|
|
25817
|
+
|
|
25818
|
+
// src/agent-catalog/acp-readiness-probe.ts
|
|
25819
|
+
var ACP_OUTPUT_LIMIT_BYTES = 1024 * 1024;
|
|
25820
|
+
var DiscoveryAcpHandler = class {
|
|
25821
|
+
onElicitation = (_request, _signal) => Promise.reject(new Error("ACP probe does not accept elicitations"));
|
|
25822
|
+
onElicitationComplete = (_notification) => Promise.resolve();
|
|
25823
|
+
onPermission = (_request, _signal) => Promise.reject(new Error("ACP probe does not grant permissions"));
|
|
25824
|
+
onUpdate = (_notification) => Promise.resolve();
|
|
25825
|
+
};
|
|
24791
25826
|
function readableAcpStream(input2) {
|
|
24792
25827
|
let byteLength = 0;
|
|
24793
|
-
let
|
|
25828
|
+
let open7 = true;
|
|
24794
25829
|
return new ReadableStream({
|
|
24795
25830
|
start(controller) {
|
|
24796
25831
|
input2.on("data", (chunk) => {
|
|
24797
|
-
if (!
|
|
25832
|
+
if (!open7) {
|
|
24798
25833
|
return;
|
|
24799
25834
|
}
|
|
24800
25835
|
if (!(chunk instanceof Uint8Array)) {
|
|
24801
|
-
|
|
25836
|
+
open7 = false;
|
|
24802
25837
|
controller.error(new Error("ACP adapter produced invalid output"));
|
|
24803
25838
|
return;
|
|
24804
25839
|
}
|
|
24805
25840
|
byteLength += chunk.byteLength;
|
|
24806
25841
|
if (byteLength > ACP_OUTPUT_LIMIT_BYTES) {
|
|
24807
|
-
|
|
25842
|
+
open7 = false;
|
|
24808
25843
|
controller.error(new Error("ACP adapter output limit exceeded"));
|
|
24809
25844
|
return;
|
|
24810
25845
|
}
|
|
24811
25846
|
controller.enqueue(new Uint8Array(chunk));
|
|
24812
25847
|
});
|
|
24813
25848
|
input2.once("end", () => {
|
|
24814
|
-
if (
|
|
24815
|
-
|
|
25849
|
+
if (open7) {
|
|
25850
|
+
open7 = false;
|
|
24816
25851
|
controller.close();
|
|
24817
25852
|
}
|
|
24818
25853
|
});
|
|
24819
25854
|
input2.once("error", (error61) => {
|
|
24820
|
-
if (
|
|
24821
|
-
|
|
25855
|
+
if (open7) {
|
|
25856
|
+
open7 = false;
|
|
24822
25857
|
controller.error(error61);
|
|
24823
25858
|
}
|
|
24824
25859
|
});
|
|
24825
25860
|
},
|
|
24826
25861
|
cancel() {
|
|
24827
|
-
|
|
25862
|
+
open7 = false;
|
|
24828
25863
|
}
|
|
24829
25864
|
});
|
|
24830
25865
|
}
|
|
@@ -24843,7 +25878,7 @@ function writableAcpStream(output2) {
|
|
|
24843
25878
|
}
|
|
24844
25879
|
});
|
|
24845
25880
|
}
|
|
24846
|
-
async function
|
|
25881
|
+
async function probeAcpReadiness(specification, agent, environment, defaultWorkspace, signal) {
|
|
24847
25882
|
signal.throwIfAborted();
|
|
24848
25883
|
const controller = new AbortController();
|
|
24849
25884
|
let timedOut = false;
|
|
@@ -24887,13 +25922,13 @@ async function probeAcp(specification, agent, environment, defaultWorkspace, sig
|
|
|
24887
25922
|
}
|
|
24888
25923
|
};
|
|
24889
25924
|
stderr.on("data", consumeStderr);
|
|
24890
|
-
const connection = createAcpClient(
|
|
24891
|
-
|
|
24892
|
-
);
|
|
25925
|
+
const connection = createAcpClient(
|
|
25926
|
+
new DiscoveryAcpHandler()
|
|
25927
|
+
).connect(ndJsonStream2(writableAcpStream(stdin), readableAcpStream(stdout)));
|
|
24893
25928
|
try {
|
|
24894
25929
|
const initialized = await Promise.race([
|
|
24895
25930
|
connection.agent.request(
|
|
24896
|
-
|
|
25931
|
+
methods4.agent.initialize,
|
|
24897
25932
|
{
|
|
24898
25933
|
clientCapabilities: {},
|
|
24899
25934
|
clientInfo: { name: "mobius", version: "0.0.3" },
|
|
@@ -24930,7 +25965,7 @@ async function probeAcp(specification, agent, environment, defaultWorkspace, sig
|
|
|
24930
25965
|
if (error61 instanceof AgentProbeError) {
|
|
24931
25966
|
throw error61;
|
|
24932
25967
|
}
|
|
24933
|
-
if (error61 instanceof
|
|
25968
|
+
if (error61 instanceof RequestError2 && error61.code === -32e3 && specification.authenticationCommand().length > 0) {
|
|
24934
25969
|
throw new AgentProbeError(
|
|
24935
25970
|
"authentication_required",
|
|
24936
25971
|
"Agent authentication is required",
|
|
@@ -24951,6 +25986,8 @@ async function probeAcp(specification, agent, environment, defaultWorkspace, sig
|
|
|
24951
25986
|
await stopProcessTree(child);
|
|
24952
25987
|
}
|
|
24953
25988
|
}
|
|
25989
|
+
|
|
25990
|
+
// src/agent-catalog/discover-agent.ts
|
|
24954
25991
|
function probeFailure(specification, executableKind, error61) {
|
|
24955
25992
|
if (error61 instanceof AgentProbeError) {
|
|
24956
25993
|
if (error61.code === "authentication_required") {
|
|
@@ -24972,12 +26009,15 @@ function probeFailure(specification, executableKind, error61) {
|
|
|
24972
26009
|
`${executableKind === "agent" ? "Agent" : "Adapter"} probe failed`
|
|
24973
26010
|
);
|
|
24974
26011
|
}
|
|
24975
|
-
async function
|
|
24976
|
-
|
|
26012
|
+
async function discoverAgent(specification, context) {
|
|
26013
|
+
context.signal.throwIfAborted();
|
|
24977
26014
|
const [adapters, agents] = await Promise.all([
|
|
24978
|
-
resolveAdapterExecutables(specification,
|
|
24979
|
-
resolveAgentExecutables(specification,
|
|
26015
|
+
resolveAdapterExecutables(specification, context),
|
|
26016
|
+
resolveAgentExecutables(specification, context)
|
|
24980
26017
|
]);
|
|
26018
|
+
if (specification instanceof DirectAcpAgentDefinition && agents.length === 0) {
|
|
26019
|
+
return new MissingAgent(specification);
|
|
26020
|
+
}
|
|
24981
26021
|
if (adapters.length === 0) {
|
|
24982
26022
|
return new MissingAdapter(specification);
|
|
24983
26023
|
}
|
|
@@ -24991,35 +26031,45 @@ async function discoverSpecification(specification, options) {
|
|
|
24991
26031
|
agentVersion = await probeVersion(
|
|
24992
26032
|
agent,
|
|
24993
26033
|
specification.agentVersionArguments,
|
|
24994
|
-
|
|
24995
|
-
|
|
24996
|
-
|
|
26034
|
+
context.environment,
|
|
26035
|
+
context.defaultWorkspace,
|
|
26036
|
+
context.signal,
|
|
26037
|
+
specification.versionProbeTimeoutMilliseconds
|
|
24997
26038
|
);
|
|
24998
26039
|
} catch (error61) {
|
|
24999
|
-
if (
|
|
25000
|
-
|
|
26040
|
+
if (context.signal.aborted) {
|
|
26041
|
+
context.signal.throwIfAborted();
|
|
25001
26042
|
}
|
|
25002
26043
|
lastFailure = probeFailure(specification, "agent", error61);
|
|
25003
26044
|
continue;
|
|
25004
26045
|
}
|
|
25005
26046
|
for (const adapter of adapters) {
|
|
26047
|
+
if (specification instanceof DirectAcpAgentDefinition && adapter.path !== agent.path) {
|
|
26048
|
+
continue;
|
|
26049
|
+
}
|
|
25006
26050
|
let adapterVersion = "";
|
|
26051
|
+
let launchEnvironment;
|
|
25007
26052
|
try {
|
|
26053
|
+
launchEnvironment = await specification.createLaunchEnvironment(
|
|
26054
|
+
agent,
|
|
26055
|
+
context
|
|
26056
|
+
);
|
|
25008
26057
|
if (specification.adapterVersionArguments.length > 0) {
|
|
25009
26058
|
adapterVersion = await probeVersion(
|
|
25010
26059
|
adapter,
|
|
25011
26060
|
specification.adapterVersionArguments,
|
|
25012
26061
|
{
|
|
25013
|
-
...
|
|
25014
|
-
|
|
26062
|
+
...context.environment,
|
|
26063
|
+
...launchEnvironment
|
|
25015
26064
|
},
|
|
25016
|
-
|
|
25017
|
-
|
|
26065
|
+
context.defaultWorkspace,
|
|
26066
|
+
context.signal,
|
|
26067
|
+
specification.versionProbeTimeoutMilliseconds
|
|
25018
26068
|
);
|
|
25019
26069
|
}
|
|
25020
26070
|
} catch (error61) {
|
|
25021
|
-
if (
|
|
25022
|
-
|
|
26071
|
+
if (context.signal.aborted) {
|
|
26072
|
+
context.signal.throwIfAborted();
|
|
25023
26073
|
}
|
|
25024
26074
|
lastFailure = probeFailure(specification, "adapter", error61);
|
|
25025
26075
|
continue;
|
|
@@ -25028,8 +26078,8 @@ async function discoverSpecification(specification, options) {
|
|
|
25028
26078
|
specification.id,
|
|
25029
26079
|
specification.label,
|
|
25030
26080
|
adapter.path,
|
|
25031
|
-
|
|
25032
|
-
|
|
26081
|
+
specification.launchArguments,
|
|
26082
|
+
launchEnvironment,
|
|
25033
26083
|
adapterVersion,
|
|
25034
26084
|
agentVersion,
|
|
25035
26085
|
adapter.identity,
|
|
@@ -25037,12 +26087,12 @@ async function discoverSpecification(specification, options) {
|
|
|
25037
26087
|
specification.promptTimeoutMilliseconds
|
|
25038
26088
|
);
|
|
25039
26089
|
try {
|
|
25040
|
-
const acpVersion = await
|
|
26090
|
+
const acpVersion = await probeAcpReadiness(
|
|
25041
26091
|
specification,
|
|
25042
26092
|
definition,
|
|
25043
|
-
|
|
25044
|
-
|
|
25045
|
-
|
|
26093
|
+
context.environment,
|
|
26094
|
+
context.defaultWorkspace,
|
|
26095
|
+
context.signal
|
|
25046
26096
|
);
|
|
25047
26097
|
const verifiedAdapterVersion = adapterVersion.length > 0 ? adapterVersion : acpVersion;
|
|
25048
26098
|
if (verifiedAdapterVersion.length === 0) {
|
|
@@ -25057,8 +26107,8 @@ async function discoverSpecification(specification, options) {
|
|
|
25057
26107
|
specification.id,
|
|
25058
26108
|
specification.label,
|
|
25059
26109
|
adapter.path,
|
|
25060
|
-
|
|
25061
|
-
|
|
26110
|
+
specification.launchArguments,
|
|
26111
|
+
launchEnvironment,
|
|
25062
26112
|
verifiedAdapterVersion,
|
|
25063
26113
|
agentVersion,
|
|
25064
26114
|
adapter.identity,
|
|
@@ -25067,20 +26117,26 @@ async function discoverSpecification(specification, options) {
|
|
|
25067
26117
|
)
|
|
25068
26118
|
);
|
|
25069
26119
|
} catch (error61) {
|
|
25070
|
-
if (
|
|
25071
|
-
|
|
26120
|
+
if (context.signal.aborted) {
|
|
26121
|
+
context.signal.throwIfAborted();
|
|
25072
26122
|
}
|
|
25073
|
-
|
|
26123
|
+
const failure = probeFailure(specification, "adapter", error61);
|
|
26124
|
+
if (failure instanceof AuthenticationRequiredAgent) {
|
|
26125
|
+
return failure;
|
|
26126
|
+
}
|
|
26127
|
+
lastFailure = failure;
|
|
25074
26128
|
}
|
|
25075
26129
|
}
|
|
25076
26130
|
}
|
|
25077
26131
|
return lastFailure ?? new IncompatibleAdapter(specification);
|
|
25078
26132
|
}
|
|
26133
|
+
|
|
26134
|
+
// src/agent-catalog/discover-local-agents.ts
|
|
25079
26135
|
async function discoverLocalAgentInventory(options) {
|
|
25080
26136
|
const specifications = options.specifications ?? supportedLocalAgentSpecifications();
|
|
25081
26137
|
const discoveries = await Promise.all(
|
|
25082
26138
|
specifications.map(
|
|
25083
|
-
async (specification) => await
|
|
26139
|
+
async (specification) => await discoverAgent(specification, options)
|
|
25084
26140
|
)
|
|
25085
26141
|
);
|
|
25086
26142
|
let grantedAgents = /* @__PURE__ */ new Set();
|
|
@@ -25098,10 +26154,6 @@ async function discoverLocalAgentInventory(options) {
|
|
|
25098
26154
|
);
|
|
25099
26155
|
}
|
|
25100
26156
|
|
|
25101
|
-
// src/network/environment-proxy.ts
|
|
25102
|
-
import { EnvHttpProxyAgent } from "undici";
|
|
25103
|
-
var environmentProxyDispatcher = new EnvHttpProxyAgent();
|
|
25104
|
-
|
|
25105
26157
|
// src/pairing/pair-local-machine.ts
|
|
25106
26158
|
var PAIRING_TIMEOUT_MILLISECONDS = 2e4;
|
|
25107
26159
|
var PAIRING_CODE_PATTERN = /^[A-HJ-NP-Z2-9]{4}(?:-[A-HJ-NP-Z2-9]{4}){4}$/;
|
|
@@ -25127,7 +26179,7 @@ var PairingClientError = class extends Error {
|
|
|
25127
26179
|
this.name = "PairingClientError";
|
|
25128
26180
|
}
|
|
25129
26181
|
};
|
|
25130
|
-
function
|
|
26182
|
+
function isRecord7(value) {
|
|
25131
26183
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
25132
26184
|
}
|
|
25133
26185
|
function hasExactKeys(value, expectedKeys) {
|
|
@@ -25240,9 +26292,9 @@ function parseChannelArgument(arguments_) {
|
|
|
25240
26292
|
async function resolveDefaultWorkspace(path2) {
|
|
25241
26293
|
const requestedWorkspace = resolve3(path2);
|
|
25242
26294
|
try {
|
|
25243
|
-
await
|
|
25244
|
-
const defaultWorkspace = await
|
|
25245
|
-
const metadata = await
|
|
26295
|
+
await mkdir3(requestedWorkspace, { recursive: true, mode: 448 });
|
|
26296
|
+
const defaultWorkspace = await realpath5(requestedWorkspace);
|
|
26297
|
+
const metadata = await stat5(defaultWorkspace);
|
|
25246
26298
|
if (!metadata.isDirectory()) {
|
|
25247
26299
|
throw new PairingClientError(
|
|
25248
26300
|
"invalid_workspace",
|
|
@@ -25280,9 +26332,9 @@ async function readJsonResponse(response) {
|
|
|
25280
26332
|
}
|
|
25281
26333
|
}
|
|
25282
26334
|
function readRelayError(value) {
|
|
25283
|
-
if (
|
|
26335
|
+
if (isRecord7(value)) {
|
|
25284
26336
|
const error61 = value["error"];
|
|
25285
|
-
if (
|
|
26337
|
+
if (isRecord7(error61)) {
|
|
25286
26338
|
const code = error61["code"];
|
|
25287
26339
|
const message = error61["message"];
|
|
25288
26340
|
if (typeof code === "string" && typeof message === "string") {
|
|
@@ -25296,7 +26348,7 @@ function readRelayError(value) {
|
|
|
25296
26348
|
);
|
|
25297
26349
|
}
|
|
25298
26350
|
function decodeClaimResponse(value) {
|
|
25299
|
-
if (!
|
|
26351
|
+
if (!isRecord7(value) || !hasExactKeys(value, CLAIM_RESPONSE_KEYS)) {
|
|
25300
26352
|
throw new PairingClientError(
|
|
25301
26353
|
"invalid_relay_response",
|
|
25302
26354
|
"The relay returned an invalid pairing response"
|
|
@@ -25318,10 +26370,10 @@ async function claimPairing(options, defaultWorkspace, localAgents, installableA
|
|
|
25318
26370
|
id: agent.id,
|
|
25319
26371
|
label: agent.label
|
|
25320
26372
|
}));
|
|
25321
|
-
const endpoint = new URL("/api/pairings/claim", options.relayOrigin);
|
|
26373
|
+
const endpoint = new URL("/mobius/api/pairings/claim", options.relayOrigin);
|
|
25322
26374
|
let response;
|
|
25323
26375
|
try {
|
|
25324
|
-
response = await
|
|
26376
|
+
response = await fetch2(endpoint, {
|
|
25325
26377
|
body: JSON.stringify({
|
|
25326
26378
|
agents,
|
|
25327
26379
|
installableAgents: installableAgents.map((agent) => ({
|
|
@@ -25355,14 +26407,14 @@ async function claimPairing(options, defaultWorkspace, localAgents, installableA
|
|
|
25355
26407
|
return decodeClaimResponse(value);
|
|
25356
26408
|
}
|
|
25357
26409
|
async function persistConnection(channelId, relayOrigin, daemonToken, defaultWorkspace) {
|
|
25358
|
-
const connectionsDirectory =
|
|
25359
|
-
await
|
|
25360
|
-
const connectionPath =
|
|
25361
|
-
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(
|
|
25362
26414
|
connectionsDirectory,
|
|
25363
26415
|
`.${channelId}.${randomUUID()}.tmp`
|
|
25364
26416
|
);
|
|
25365
|
-
await
|
|
26417
|
+
await writeFile2(
|
|
25366
26418
|
temporaryPath,
|
|
25367
26419
|
`${JSON.stringify(
|
|
25368
26420
|
{
|
|
@@ -25377,11 +26429,11 @@ async function persistConnection(channelId, relayOrigin, daemonToken, defaultWor
|
|
|
25377
26429
|
`,
|
|
25378
26430
|
{ flag: "wx", mode: 384 }
|
|
25379
26431
|
);
|
|
25380
|
-
await
|
|
26432
|
+
await rename3(temporaryPath, connectionPath);
|
|
25381
26433
|
return connectionPath;
|
|
25382
26434
|
}
|
|
25383
26435
|
function decodeSavedConnection(value, expectedChannelId) {
|
|
25384
|
-
if (!
|
|
26436
|
+
if (!isRecord7(value) || !hasExactKeys(value, SAVED_CONNECTION_KEYS)) {
|
|
25385
26437
|
throw new PairingClientError(
|
|
25386
26438
|
"invalid_connection",
|
|
25387
26439
|
"The saved connection is invalid"
|
|
@@ -25405,13 +26457,13 @@ function decodeSavedConnection(value, expectedChannelId) {
|
|
|
25405
26457
|
};
|
|
25406
26458
|
}
|
|
25407
26459
|
async function readSavedConnection(channelId) {
|
|
25408
|
-
const connectionPath =
|
|
26460
|
+
const connectionPath = join13(
|
|
25409
26461
|
readStateDirectory(),
|
|
25410
26462
|
"connections",
|
|
25411
26463
|
`${channelId}.json`
|
|
25412
26464
|
);
|
|
25413
26465
|
let encoded = "";
|
|
25414
|
-
const handle = await
|
|
26466
|
+
const handle = await open6(connectionPath, "r");
|
|
25415
26467
|
try {
|
|
25416
26468
|
const metadata = await handle.stat();
|
|
25417
26469
|
if (!metadata.isFile() || metadata.size > MAX_CONNECTION_FILE_LENGTH) {
|
|
@@ -25455,12 +26507,12 @@ function assertInventoryUsable(inventory) {
|
|
|
25455
26507
|
function buildPairedDaemon(connection, connectionPath, inventory) {
|
|
25456
26508
|
assertInventoryUsable(inventory);
|
|
25457
26509
|
const relayUrl = new URL(
|
|
25458
|
-
`/api/channels/${encodeURIComponent(connection.channelId)}/daemon`,
|
|
26510
|
+
`/mobius/api/channels/${encodeURIComponent(connection.channelId)}/daemon`,
|
|
25459
26511
|
connection.relayOrigin
|
|
25460
26512
|
);
|
|
25461
26513
|
relayUrl.protocol = relayUrl.protocol === "https:" ? "wss:" : "ws:";
|
|
25462
26514
|
relayUrl.searchParams.set("token", connection.daemonToken);
|
|
25463
|
-
const auditDatabasePath =
|
|
26515
|
+
const auditDatabasePath = join13(
|
|
25464
26516
|
readStateDirectory(),
|
|
25465
26517
|
"audit",
|
|
25466
26518
|
`${connection.channelId}.sqlite`
|
|
@@ -25519,7 +26571,7 @@ async function pairLocalMachine(arguments_, signal = new AbortController().signa
|
|
|
25519
26571
|
}
|
|
25520
26572
|
async function resumeLocalMachine(arguments_, signal = new AbortController().signal) {
|
|
25521
26573
|
const channelId = parseChannelArgument(arguments_);
|
|
25522
|
-
const connectionPath =
|
|
26574
|
+
const connectionPath = join13(
|
|
25523
26575
|
readStateDirectory(),
|
|
25524
26576
|
"connections",
|
|
25525
26577
|
`${channelId}.json`
|
|
@@ -25535,10 +26587,11 @@ async function resumeLocalMachine(arguments_, signal = new AbortController().sig
|
|
|
25535
26587
|
|
|
25536
26588
|
// src/run-daemon.ts
|
|
25537
26589
|
import { basename as basename3 } from "node:path";
|
|
26590
|
+
import { styleText } from "node:util";
|
|
25538
26591
|
import { WebSocket as WebSocket2 } from "undici";
|
|
25539
26592
|
|
|
25540
26593
|
// src/agent-catalog/publish-agent-catalog.ts
|
|
25541
|
-
import { fetch as
|
|
26594
|
+
import { fetch as fetch3 } from "undici";
|
|
25542
26595
|
var CATALOG_UPDATE_TIMEOUT_MILLISECONDS = 2e4;
|
|
25543
26596
|
var AgentCatalogPublishError = class extends Error {
|
|
25544
26597
|
code = "agent_catalog_update_failed";
|
|
@@ -25565,7 +26618,7 @@ async function publishAgentCatalog(config2, signal) {
|
|
|
25565
26618
|
let response;
|
|
25566
26619
|
const catalog = config2.catalog.read();
|
|
25567
26620
|
try {
|
|
25568
|
-
response = await
|
|
26621
|
+
response = await fetch3(catalogEndpoint(config2.relayUrl), {
|
|
25569
26622
|
body: JSON.stringify({
|
|
25570
26623
|
agents: catalog.agents.map((agent) => ({
|
|
25571
26624
|
id: agent.id,
|
|
@@ -25971,7 +27024,7 @@ var InstalledAutomaticAdapter = class {
|
|
|
25971
27024
|
}
|
|
25972
27025
|
};
|
|
25973
27026
|
function shouldProvisionAdapter(unavailable, options) {
|
|
25974
|
-
return AUTOMATIC_ADAPTER_FAILURE_CODES.has(unavailable.code) && options.environment[unavailable.specification.adapterOverrideVariable] === void 0 && unavailable.specification.supportsInstallation(
|
|
27027
|
+
return unavailable.specification instanceof BridgedAcpAgentDefinition && AUTOMATIC_ADAPTER_FAILURE_CODES.has(unavailable.code) && options.environment[unavailable.specification.adapterOverrideVariable] === void 0 && unavailable.specification.supportsInstallation(
|
|
25975
27028
|
options.platform ?? process.platform,
|
|
25976
27029
|
options.architecture ?? process.arch
|
|
25977
27030
|
);
|
|
@@ -26015,6 +27068,10 @@ var AutomaticAdapterProvisioner = class {
|
|
|
26015
27068
|
for (const unavailable of candidates) {
|
|
26016
27069
|
signal.throwIfAborted();
|
|
26017
27070
|
const specification = unavailable.specification;
|
|
27071
|
+
if (!(specification instanceof BridgedAcpAgentDefinition)) {
|
|
27072
|
+
attempts.push(null);
|
|
27073
|
+
continue;
|
|
27074
|
+
}
|
|
26018
27075
|
const verifiedAgent = await findVerifiedAgentExecutable(
|
|
26019
27076
|
specification,
|
|
26020
27077
|
discoveryOptions(
|
|
@@ -26053,293 +27110,100 @@ var AutomaticAdapterProvisioner = class {
|
|
|
26053
27110
|
specification.id,
|
|
26054
27111
|
{ adapterVersion: specification.adapterVersion }
|
|
26055
27112
|
);
|
|
26056
|
-
attempts.push(
|
|
26057
|
-
new InstalledAutomaticAdapter(specification, requestId, executable)
|
|
26058
|
-
);
|
|
26059
|
-
} catch (error61) {
|
|
26060
|
-
if (signal.aborted) {
|
|
26061
|
-
this.#options.audit.record(
|
|
26062
|
-
"agent_adapter_auto_install_cancelled",
|
|
26063
|
-
requestId,
|
|
26064
|
-
specification.id
|
|
26065
|
-
);
|
|
26066
|
-
signal.throwIfAborted();
|
|
26067
|
-
}
|
|
26068
|
-
this.#options.audit.record(
|
|
26069
|
-
"agent_adapter_auto_install_failed",
|
|
26070
|
-
requestId,
|
|
26071
|
-
specification.id,
|
|
26072
|
-
{ code: stableFailureCode(error61) }
|
|
26073
|
-
);
|
|
26074
|
-
process.stderr.write(
|
|
26075
|
-
`The pinned ACP adapter for ${specification.label} could not be installed automatically; the daemon will continue.
|
|
26076
|
-
`
|
|
26077
|
-
);
|
|
26078
|
-
attempts.push(null);
|
|
26079
|
-
}
|
|
26080
|
-
}
|
|
26081
|
-
signal.throwIfAborted();
|
|
26082
|
-
const installed = attempts.filter(
|
|
26083
|
-
(attempt) => attempt !== null
|
|
26084
|
-
);
|
|
26085
|
-
if (installed.length > 0) {
|
|
26086
|
-
const verificationEnvironment = {
|
|
26087
|
-
...this.#options.environment
|
|
26088
|
-
};
|
|
26089
|
-
for (const attempt of installed) {
|
|
26090
|
-
verificationEnvironment[attempt.specification.adapterOverrideVariable] = attempt.executable.path;
|
|
26091
|
-
}
|
|
26092
|
-
inventory = await discoverLocalAgentInventory(
|
|
26093
|
-
discoveryOptions(
|
|
26094
|
-
this.#options,
|
|
26095
|
-
verificationEnvironment,
|
|
26096
|
-
signal,
|
|
26097
|
-
this.#specifications
|
|
26098
|
-
)
|
|
26099
|
-
);
|
|
26100
|
-
}
|
|
26101
|
-
this.#options.catalog.transition(
|
|
26102
|
-
inventory.readyAgents(),
|
|
26103
|
-
inventory.installable
|
|
26104
|
-
);
|
|
26105
|
-
for (const attempt of installed) {
|
|
26106
|
-
const available = inventory.available.find(
|
|
26107
|
-
(candidate) => candidate instanceof AvailableAgent && candidate.specification.id === attempt.specification.id
|
|
26108
|
-
);
|
|
26109
|
-
if (available === void 0) {
|
|
26110
|
-
const unavailable = inventory.unavailable.find(
|
|
26111
|
-
(candidate) => candidate.specification.id === attempt.specification.id
|
|
26112
|
-
);
|
|
26113
|
-
this.#options.audit.record(
|
|
26114
|
-
"agent_adapter_auto_install_verification_failed",
|
|
26115
|
-
attempt.requestId,
|
|
26116
|
-
attempt.specification.id,
|
|
26117
|
-
{ code: unavailable?.code ?? "agent_verification_failed" }
|
|
26118
|
-
);
|
|
26119
|
-
continue;
|
|
26120
|
-
}
|
|
26121
|
-
this.#options.audit.record(
|
|
26122
|
-
"agent_adapter_auto_install_verified",
|
|
26123
|
-
attempt.requestId,
|
|
26124
|
-
attempt.specification.id,
|
|
26125
|
-
{
|
|
26126
|
-
adapterVersion: available.agent.adapterVersion,
|
|
26127
|
-
agentVersion: available.agent.agentVersion
|
|
26128
|
-
}
|
|
26129
|
-
);
|
|
26130
|
-
process.stdout.write(
|
|
26131
|
-
`${attempt.specification.label} ACP integration is ready.
|
|
26132
|
-
`
|
|
26133
|
-
);
|
|
26134
|
-
}
|
|
26135
|
-
return inventory;
|
|
26136
|
-
};
|
|
26137
|
-
};
|
|
26138
|
-
|
|
26139
|
-
// src/agent-installation/fixed-installation-executor.ts
|
|
26140
|
-
import { realpathSync as realpathSync2, statSync as statSync2 } from "node:fs";
|
|
26141
|
-
import { resolve as resolve4 } from "node:path";
|
|
26142
|
-
|
|
26143
|
-
// src/agent-installation/fixed-agent-install-recipes.ts
|
|
26144
|
-
import { mkdir as mkdir3, mkdtemp as mkdtemp2, rm as rm2 } from "node:fs/promises";
|
|
26145
|
-
import { join as join9 } from "node:path";
|
|
26146
|
-
|
|
26147
|
-
// src/agent-installation/verified-download.ts
|
|
26148
|
-
import { createHash } from "node:crypto";
|
|
26149
|
-
import { open as open5, unlink } from "node:fs/promises";
|
|
26150
|
-
import { fetch as fetch3 } from "undici";
|
|
26151
|
-
var MAX_REDIRECTS = 4;
|
|
26152
|
-
var REDIRECT_STATUSES = /* @__PURE__ */ new Set([301, 302, 303, 307, 308]);
|
|
26153
|
-
var InstallerDownloadError = class extends Error {
|
|
26154
|
-
code;
|
|
26155
|
-
constructor(code, message, options = {}) {
|
|
26156
|
-
super(message, options);
|
|
26157
|
-
this.code = code;
|
|
26158
|
-
this.name = "InstallerDownloadError";
|
|
26159
|
-
}
|
|
26160
|
-
};
|
|
26161
|
-
var VerifiedDownload = class {
|
|
26162
|
-
bytes;
|
|
26163
|
-
sha256;
|
|
26164
|
-
url;
|
|
26165
|
-
constructor(url2, bytes, sha256) {
|
|
26166
|
-
this.bytes = bytes;
|
|
26167
|
-
this.sha256 = sha256;
|
|
26168
|
-
this.url = url2;
|
|
26169
|
-
}
|
|
26170
|
-
};
|
|
26171
|
-
var UndiciInstallerDownloadTransport = class {
|
|
26172
|
-
get = async (url2, signal) => await fetch3(url2, {
|
|
26173
|
-
dispatcher: environmentProxyDispatcher,
|
|
26174
|
-
headers: {
|
|
26175
|
-
accept: "text/plain, application/octet-stream;q=0.9",
|
|
26176
|
-
"user-agent": "Mobius-Agent-Installer/0.0.3"
|
|
26177
|
-
},
|
|
26178
|
-
method: "GET",
|
|
26179
|
-
redirect: "manual",
|
|
26180
|
-
signal
|
|
26181
|
-
});
|
|
26182
|
-
};
|
|
26183
|
-
function validateUrl(url2, allowedHosts) {
|
|
26184
|
-
if (url2.protocol !== "https:" || url2.username.length > 0 || url2.password.length > 0 || url2.port.length > 0 || !allowedHosts.has(url2.hostname)) {
|
|
26185
|
-
throw new InstallerDownloadError(
|
|
26186
|
-
"installer_host_not_allowed",
|
|
26187
|
-
"The installer download target is not allowed"
|
|
26188
|
-
);
|
|
26189
|
-
}
|
|
26190
|
-
}
|
|
26191
|
-
async function fetchInstaller(options, signal, transport) {
|
|
26192
|
-
let url2 = new URL(options.url);
|
|
26193
|
-
for (let redirectCount = 0; redirectCount <= MAX_REDIRECTS; redirectCount += 1) {
|
|
26194
|
-
validateUrl(url2, options.allowedHosts);
|
|
26195
|
-
const response = await transport.get(url2, signal);
|
|
26196
|
-
if (!REDIRECT_STATUSES.has(response.status)) {
|
|
26197
|
-
return { response, url: url2 };
|
|
26198
|
-
}
|
|
26199
|
-
await response.body?.cancel();
|
|
26200
|
-
const location = response.headers.get("location");
|
|
26201
|
-
if (location === null || redirectCount === MAX_REDIRECTS) {
|
|
26202
|
-
throw new InstallerDownloadError(
|
|
26203
|
-
"installer_redirect_invalid",
|
|
26204
|
-
"The installer returned an invalid redirect"
|
|
26205
|
-
);
|
|
26206
|
-
}
|
|
26207
|
-
let redirected;
|
|
26208
|
-
try {
|
|
26209
|
-
redirected = new URL(location, url2);
|
|
26210
|
-
} catch (error61) {
|
|
26211
|
-
throw new InstallerDownloadError(
|
|
26212
|
-
"installer_redirect_invalid",
|
|
26213
|
-
"The installer returned an invalid redirect",
|
|
26214
|
-
{ cause: error61 }
|
|
26215
|
-
);
|
|
26216
|
-
}
|
|
26217
|
-
try {
|
|
26218
|
-
validateUrl(redirected, options.allowedHosts);
|
|
26219
|
-
} catch (error61) {
|
|
26220
|
-
throw new InstallerDownloadError(
|
|
26221
|
-
"installer_redirect_not_allowed",
|
|
26222
|
-
"The installer redirect left the approved host allowlist",
|
|
26223
|
-
{ cause: error61 }
|
|
26224
|
-
);
|
|
26225
|
-
}
|
|
26226
|
-
url2 = redirected;
|
|
26227
|
-
}
|
|
26228
|
-
throw new InstallerDownloadError(
|
|
26229
|
-
"installer_redirect_invalid",
|
|
26230
|
-
"The installer returned too many redirects"
|
|
26231
|
-
);
|
|
26232
|
-
}
|
|
26233
|
-
async function writeCompleteChunk(handle, chunk) {
|
|
26234
|
-
let offset = 0;
|
|
26235
|
-
while (offset < chunk.byteLength) {
|
|
26236
|
-
const written = await handle.write(
|
|
26237
|
-
chunk,
|
|
26238
|
-
offset,
|
|
26239
|
-
chunk.byteLength - offset
|
|
26240
|
-
);
|
|
26241
|
-
if (written.bytesWritten < 1) {
|
|
26242
|
-
throw new InstallerDownloadError(
|
|
26243
|
-
"installer_write_failed",
|
|
26244
|
-
"The verified installer could not be stored"
|
|
26245
|
-
);
|
|
26246
|
-
}
|
|
26247
|
-
offset += written.bytesWritten;
|
|
26248
|
-
}
|
|
26249
|
-
}
|
|
26250
|
-
async function downloadVerifiedFile(options, transport = new UndiciInstallerDownloadTransport()) {
|
|
26251
|
-
options.signal.throwIfAborted();
|
|
26252
|
-
const timeoutSignal = AbortSignal.timeout(options.timeoutMilliseconds);
|
|
26253
|
-
const signal = AbortSignal.any([options.signal, timeoutSignal]);
|
|
26254
|
-
let handle = null;
|
|
26255
|
-
let responseBody = null;
|
|
26256
|
-
try {
|
|
26257
|
-
const fetched = await fetchInstaller(options, signal, transport);
|
|
26258
|
-
responseBody = fetched.response.body;
|
|
26259
|
-
if (!fetched.response.ok || fetched.response.body === null) {
|
|
26260
|
-
throw new InstallerDownloadError(
|
|
26261
|
-
"installer_download_failed",
|
|
26262
|
-
"The approved installer could not be downloaded"
|
|
26263
|
-
);
|
|
26264
|
-
}
|
|
26265
|
-
const contentLength = fetched.response.headers.get("content-length");
|
|
26266
|
-
if (contentLength !== null) {
|
|
26267
|
-
const declaredLength = Number(contentLength);
|
|
26268
|
-
if (!Number.isSafeInteger(declaredLength) || declaredLength < 1 || declaredLength > options.maximumBytes) {
|
|
26269
|
-
throw new InstallerDownloadError(
|
|
26270
|
-
"installer_size_invalid",
|
|
26271
|
-
"The installer size is outside the approved limit"
|
|
26272
|
-
);
|
|
26273
|
-
}
|
|
26274
|
-
}
|
|
26275
|
-
handle = await open5(options.destination, "wx", 384);
|
|
26276
|
-
const digest = createHash("sha256");
|
|
26277
|
-
const reader = fetched.response.body.getReader();
|
|
26278
|
-
let bytes = 0;
|
|
26279
|
-
try {
|
|
26280
|
-
while (true) {
|
|
26281
|
-
signal.throwIfAborted();
|
|
26282
|
-
const chunk = await reader.read();
|
|
26283
|
-
if (chunk.done) {
|
|
26284
|
-
break;
|
|
26285
|
-
}
|
|
26286
|
-
bytes += chunk.value.byteLength;
|
|
26287
|
-
if (bytes > options.maximumBytes) {
|
|
26288
|
-
throw new InstallerDownloadError(
|
|
26289
|
-
"installer_size_invalid",
|
|
26290
|
-
"The installer exceeded the approved size limit"
|
|
27113
|
+
attempts.push(
|
|
27114
|
+
new InstalledAutomaticAdapter(specification, requestId, executable)
|
|
27115
|
+
);
|
|
27116
|
+
} catch (error61) {
|
|
27117
|
+
if (signal.aborted) {
|
|
27118
|
+
this.#options.audit.record(
|
|
27119
|
+
"agent_adapter_auto_install_cancelled",
|
|
27120
|
+
requestId,
|
|
27121
|
+
specification.id
|
|
26291
27122
|
);
|
|
27123
|
+
signal.throwIfAborted();
|
|
26292
27124
|
}
|
|
26293
|
-
|
|
26294
|
-
|
|
27125
|
+
this.#options.audit.record(
|
|
27126
|
+
"agent_adapter_auto_install_failed",
|
|
27127
|
+
requestId,
|
|
27128
|
+
specification.id,
|
|
27129
|
+
{ code: stableFailureCode(error61) }
|
|
27130
|
+
);
|
|
27131
|
+
process.stderr.write(
|
|
27132
|
+
`The pinned ACP adapter for ${specification.label} could not be installed automatically; the daemon will continue.
|
|
27133
|
+
`
|
|
27134
|
+
);
|
|
27135
|
+
attempts.push(null);
|
|
26295
27136
|
}
|
|
26296
|
-
} finally {
|
|
26297
|
-
await reader.cancel().catch(() => void 0);
|
|
26298
|
-
reader.releaseLock();
|
|
26299
27137
|
}
|
|
26300
|
-
|
|
26301
|
-
|
|
26302
|
-
|
|
26303
|
-
|
|
27138
|
+
signal.throwIfAborted();
|
|
27139
|
+
const installed = attempts.filter(
|
|
27140
|
+
(attempt) => attempt !== null
|
|
27141
|
+
);
|
|
27142
|
+
if (installed.length > 0) {
|
|
27143
|
+
const verificationEnvironment = {
|
|
27144
|
+
...this.#options.environment
|
|
27145
|
+
};
|
|
27146
|
+
for (const attempt of installed) {
|
|
27147
|
+
verificationEnvironment[attempt.specification.adapterOverrideVariable] = attempt.executable.path;
|
|
27148
|
+
}
|
|
27149
|
+
inventory = await discoverLocalAgentInventory(
|
|
27150
|
+
discoveryOptions(
|
|
27151
|
+
this.#options,
|
|
27152
|
+
verificationEnvironment,
|
|
27153
|
+
signal,
|
|
27154
|
+
this.#specifications
|
|
27155
|
+
)
|
|
26304
27156
|
);
|
|
26305
27157
|
}
|
|
26306
|
-
|
|
26307
|
-
|
|
26308
|
-
|
|
26309
|
-
|
|
26310
|
-
|
|
26311
|
-
|
|
26312
|
-
|
|
26313
|
-
|
|
26314
|
-
|
|
26315
|
-
|
|
26316
|
-
|
|
26317
|
-
|
|
26318
|
-
|
|
26319
|
-
|
|
26320
|
-
|
|
26321
|
-
|
|
26322
|
-
|
|
27158
|
+
this.#options.catalog.transition(
|
|
27159
|
+
inventory.readyAgents(),
|
|
27160
|
+
inventory.installable
|
|
27161
|
+
);
|
|
27162
|
+
for (const attempt of installed) {
|
|
27163
|
+
const available = inventory.available.find(
|
|
27164
|
+
(candidate) => candidate instanceof AvailableAgent && candidate.specification.id === attempt.specification.id
|
|
27165
|
+
);
|
|
27166
|
+
if (available === void 0) {
|
|
27167
|
+
const unavailable = inventory.unavailable.find(
|
|
27168
|
+
(candidate) => candidate.specification.id === attempt.specification.id
|
|
27169
|
+
);
|
|
27170
|
+
this.#options.audit.record(
|
|
27171
|
+
"agent_adapter_auto_install_verification_failed",
|
|
27172
|
+
attempt.requestId,
|
|
27173
|
+
attempt.specification.id,
|
|
27174
|
+
{ code: unavailable?.code ?? "agent_verification_failed" }
|
|
27175
|
+
);
|
|
27176
|
+
continue;
|
|
27177
|
+
}
|
|
27178
|
+
this.#options.audit.record(
|
|
27179
|
+
"agent_adapter_auto_install_verified",
|
|
27180
|
+
attempt.requestId,
|
|
27181
|
+
attempt.specification.id,
|
|
27182
|
+
{
|
|
27183
|
+
adapterVersion: available.agent.adapterVersion,
|
|
27184
|
+
agentVersion: available.agent.agentVersion
|
|
27185
|
+
}
|
|
27186
|
+
);
|
|
27187
|
+
process.stdout.write(
|
|
27188
|
+
`${attempt.specification.label} ACP integration is ready.
|
|
27189
|
+
`
|
|
26323
27190
|
);
|
|
26324
27191
|
}
|
|
26325
|
-
|
|
26326
|
-
|
|
26327
|
-
|
|
26328
|
-
|
|
26329
|
-
|
|
26330
|
-
|
|
26331
|
-
|
|
26332
|
-
);
|
|
26333
|
-
} finally {
|
|
26334
|
-
await responseBody?.cancel().catch(() => void 0);
|
|
26335
|
-
}
|
|
26336
|
-
}
|
|
27192
|
+
return inventory;
|
|
27193
|
+
};
|
|
27194
|
+
};
|
|
27195
|
+
|
|
27196
|
+
// src/agent-installation/fixed-installation-executor.ts
|
|
27197
|
+
import { realpathSync as realpathSync2, statSync as statSync2 } from "node:fs";
|
|
27198
|
+
import { resolve as resolve4 } from "node:path";
|
|
26337
27199
|
|
|
26338
27200
|
// src/agent-installation/fixed-agent-install-recipes.ts
|
|
27201
|
+
import { mkdir as mkdir4, mkdtemp as mkdtemp3, rm as rm3 } from "node:fs/promises";
|
|
27202
|
+
import { join as join14 } from "node:path";
|
|
26339
27203
|
var INSTALLER_DOWNLOAD_LIMIT_BYTES = 1024 * 1024;
|
|
26340
27204
|
var INSTALLER_DOWNLOAD_TIMEOUT_MILLISECONDS = 6e4;
|
|
26341
27205
|
var AGENT_INSTALL_TIMEOUT_MILLISECONDS = 5 * 60 * 1e3;
|
|
26342
|
-
var
|
|
27206
|
+
var MINIMAL_PATH2 = "/usr/bin:/bin";
|
|
26343
27207
|
var FixedAgentInstallRecipe = class {
|
|
26344
27208
|
assertSupportedPlatform = () => {
|
|
26345
27209
|
if (process.platform !== "darwin" && process.platform !== "linux" || process.arch !== "arm64" && process.arch !== "x64") {
|
|
@@ -26366,22 +27230,22 @@ var CodexInstallRecipe = class extends FixedAgentInstallRecipe {
|
|
|
26366
27230
|
releaseChannel = "latest";
|
|
26367
27231
|
install = async (options) => {
|
|
26368
27232
|
this.assertSupportedPlatform();
|
|
26369
|
-
const root =
|
|
26370
|
-
const temporaryRoot =
|
|
27233
|
+
const root = join14(options.stateDirectory, "agents", this.id);
|
|
27234
|
+
const temporaryRoot = join14(options.stateDirectory, "temporary");
|
|
26371
27235
|
await Promise.all([
|
|
26372
|
-
|
|
26373
|
-
|
|
27236
|
+
mkdir4(root, { mode: 448, recursive: true }),
|
|
27237
|
+
mkdir4(temporaryRoot, { mode: 448, recursive: true })
|
|
26374
27238
|
]);
|
|
26375
|
-
const temporaryDirectory = await
|
|
26376
|
-
|
|
27239
|
+
const temporaryDirectory = await mkdtemp3(
|
|
27240
|
+
join14(temporaryRoot, ".codex-install-")
|
|
26377
27241
|
);
|
|
26378
|
-
const installerPath =
|
|
26379
|
-
const installDirectory =
|
|
26380
|
-
const codexHome =
|
|
27242
|
+
const installerPath = join14(temporaryDirectory, "install.sh");
|
|
27243
|
+
const installDirectory = join14(root, "bin");
|
|
27244
|
+
const codexHome = join14(root, "home");
|
|
26381
27245
|
try {
|
|
26382
27246
|
await Promise.all([
|
|
26383
|
-
|
|
26384
|
-
|
|
27247
|
+
mkdir4(installDirectory, { mode: 448, recursive: true }),
|
|
27248
|
+
mkdir4(codexHome, { mode: 448, recursive: true })
|
|
26385
27249
|
]);
|
|
26386
27250
|
await options.report("downloading");
|
|
26387
27251
|
const download = await downloadVerifiedFile({
|
|
@@ -26414,14 +27278,14 @@ var CodexInstallRecipe = class extends FixedAgentInstallRecipe {
|
|
|
26414
27278
|
CODEX_NON_INTERACTIVE: "1",
|
|
26415
27279
|
CODEX_RELEASE: this.releaseChannel,
|
|
26416
27280
|
HOME: codexHome,
|
|
26417
|
-
PATH:
|
|
27281
|
+
PATH: MINIMAL_PATH2
|
|
26418
27282
|
},
|
|
26419
27283
|
outputLimitBytes: 64 * 1024,
|
|
26420
27284
|
signal: options.signal,
|
|
26421
27285
|
timeoutMilliseconds: AGENT_INSTALL_TIMEOUT_MILLISECONDS
|
|
26422
27286
|
});
|
|
26423
27287
|
return await this.requireInstalledExecutable(
|
|
26424
|
-
|
|
27288
|
+
join14(installDirectory, "codex")
|
|
26425
27289
|
);
|
|
26426
27290
|
} catch (error61) {
|
|
26427
27291
|
if (options.signal.aborted) {
|
|
@@ -26435,7 +27299,7 @@ var CodexInstallRecipe = class extends FixedAgentInstallRecipe {
|
|
|
26435
27299
|
"The fixed Codex installation recipe failed"
|
|
26436
27300
|
);
|
|
26437
27301
|
} finally {
|
|
26438
|
-
await
|
|
27302
|
+
await rm3(temporaryDirectory, { force: true, recursive: true });
|
|
26439
27303
|
}
|
|
26440
27304
|
};
|
|
26441
27305
|
};
|
|
@@ -26445,17 +27309,17 @@ var ClaudeCodeInstallRecipe = class extends FixedAgentInstallRecipe {
|
|
|
26445
27309
|
releaseChannel = "stable";
|
|
26446
27310
|
install = async (options) => {
|
|
26447
27311
|
this.assertSupportedPlatform();
|
|
26448
|
-
const root =
|
|
26449
|
-
const managedHome =
|
|
26450
|
-
const temporaryRoot =
|
|
27312
|
+
const root = join14(options.stateDirectory, "agents", this.id);
|
|
27313
|
+
const managedHome = join14(root, "home");
|
|
27314
|
+
const temporaryRoot = join14(options.stateDirectory, "temporary");
|
|
26451
27315
|
await Promise.all([
|
|
26452
|
-
|
|
26453
|
-
|
|
27316
|
+
mkdir4(managedHome, { mode: 448, recursive: true }),
|
|
27317
|
+
mkdir4(temporaryRoot, { mode: 448, recursive: true })
|
|
26454
27318
|
]);
|
|
26455
|
-
const temporaryDirectory = await
|
|
26456
|
-
|
|
27319
|
+
const temporaryDirectory = await mkdtemp3(
|
|
27320
|
+
join14(temporaryRoot, ".claude-install-")
|
|
26457
27321
|
);
|
|
26458
|
-
const installerPath =
|
|
27322
|
+
const installerPath = join14(temporaryDirectory, "install.sh");
|
|
26459
27323
|
try {
|
|
26460
27324
|
await options.report("downloading");
|
|
26461
27325
|
const download = await downloadVerifiedFile({
|
|
@@ -26484,7 +27348,7 @@ var ClaudeCodeInstallRecipe = class extends FixedAgentInstallRecipe {
|
|
|
26484
27348
|
cwd: temporaryDirectory,
|
|
26485
27349
|
environment: {
|
|
26486
27350
|
HOME: managedHome,
|
|
26487
|
-
PATH:
|
|
27351
|
+
PATH: MINIMAL_PATH2,
|
|
26488
27352
|
SHELL: "/bin/bash"
|
|
26489
27353
|
},
|
|
26490
27354
|
outputLimitBytes: 64 * 1024,
|
|
@@ -26492,7 +27356,7 @@ var ClaudeCodeInstallRecipe = class extends FixedAgentInstallRecipe {
|
|
|
26492
27356
|
timeoutMilliseconds: AGENT_INSTALL_TIMEOUT_MILLISECONDS
|
|
26493
27357
|
});
|
|
26494
27358
|
return await this.requireInstalledExecutable(
|
|
26495
|
-
|
|
27359
|
+
join14(managedHome, ".local", "bin", "claude")
|
|
26496
27360
|
);
|
|
26497
27361
|
} catch (error61) {
|
|
26498
27362
|
if (options.signal.aborted) {
|
|
@@ -26506,7 +27370,7 @@ var ClaudeCodeInstallRecipe = class extends FixedAgentInstallRecipe {
|
|
|
26506
27370
|
"The fixed Claude Code installation recipe failed"
|
|
26507
27371
|
);
|
|
26508
27372
|
} finally {
|
|
26509
|
-
await
|
|
27373
|
+
await rm3(temporaryDirectory, { force: true, recursive: true });
|
|
26510
27374
|
}
|
|
26511
27375
|
};
|
|
26512
27376
|
};
|
|
@@ -26526,7 +27390,7 @@ var PiInstallRecipe = class extends FixedAgentInstallRecipe {
|
|
|
26526
27390
|
await options.report("verifying");
|
|
26527
27391
|
await options.report("installing_agent");
|
|
26528
27392
|
const executable = await this.#npmInstaller.install(
|
|
26529
|
-
|
|
27393
|
+
join14(
|
|
26530
27394
|
options.stateDirectory,
|
|
26531
27395
|
"agents",
|
|
26532
27396
|
this.id,
|
|
@@ -26581,11 +27445,161 @@ var PiInstallRecipe = class extends FixedAgentInstallRecipe {
|
|
|
26581
27445
|
}
|
|
26582
27446
|
};
|
|
26583
27447
|
};
|
|
27448
|
+
var DeepSeekHarnessInstallRecipe = class extends FixedAgentInstallRecipe {
|
|
27449
|
+
#npmInstaller;
|
|
27450
|
+
id = "deepseek-harness";
|
|
27451
|
+
label = "DeepSeek Harness";
|
|
27452
|
+
releaseChannel = DEEPSEEK_HARNESS_PACKAGE.version;
|
|
27453
|
+
constructor(npmInstaller = new ManagedNpmPackageInstaller()) {
|
|
27454
|
+
super();
|
|
27455
|
+
this.#npmInstaller = npmInstaller;
|
|
27456
|
+
}
|
|
27457
|
+
install = async (options) => {
|
|
27458
|
+
this.assertSupportedPlatform();
|
|
27459
|
+
try {
|
|
27460
|
+
const managedHome = join14(
|
|
27461
|
+
options.stateDirectory,
|
|
27462
|
+
"agents",
|
|
27463
|
+
this.id,
|
|
27464
|
+
"home"
|
|
27465
|
+
);
|
|
27466
|
+
await mkdir4(managedHome, { mode: 448, recursive: true });
|
|
27467
|
+
await options.report("downloading");
|
|
27468
|
+
await options.report("verifying");
|
|
27469
|
+
await options.report("installing_agent");
|
|
27470
|
+
const executable = await this.#npmInstaller.install(
|
|
27471
|
+
join14(
|
|
27472
|
+
options.stateDirectory,
|
|
27473
|
+
"agents",
|
|
27474
|
+
this.id,
|
|
27475
|
+
DEEPSEEK_HARNESS_PACKAGE.version
|
|
27476
|
+
),
|
|
27477
|
+
DEEPSEEK_HARNESS_PACKAGE,
|
|
27478
|
+
options.environment,
|
|
27479
|
+
options.signal
|
|
27480
|
+
);
|
|
27481
|
+
options.audit.record(
|
|
27482
|
+
"agent_npm_package_verified",
|
|
27483
|
+
options.requestId,
|
|
27484
|
+
this.id,
|
|
27485
|
+
{
|
|
27486
|
+
integrity: DEEPSEEK_HARNESS_PACKAGE.integrity,
|
|
27487
|
+
package: DEEPSEEK_HARNESS_PACKAGE.packageName,
|
|
27488
|
+
version: DEEPSEEK_HARNESS_PACKAGE.version
|
|
27489
|
+
}
|
|
27490
|
+
);
|
|
27491
|
+
return executable;
|
|
27492
|
+
} catch (error61) {
|
|
27493
|
+
if (options.signal.aborted) {
|
|
27494
|
+
options.signal.throwIfAborted();
|
|
27495
|
+
}
|
|
27496
|
+
if (error61 instanceof ManagedNpmPackageError) {
|
|
27497
|
+
if (error61.code === "managed_package_verification_failed") {
|
|
27498
|
+
throw new InstallationManagerError(
|
|
27499
|
+
"agent_verification_failed",
|
|
27500
|
+
"The managed DeepSeek Harness package did not match its pinned artifact",
|
|
27501
|
+
{ cause: error61 }
|
|
27502
|
+
);
|
|
27503
|
+
}
|
|
27504
|
+
if (error61.code === "managed_package_publish_failed") {
|
|
27505
|
+
throw new InstallationManagerError(
|
|
27506
|
+
"agent_publish_failed",
|
|
27507
|
+
"The managed DeepSeek Harness package could not be published",
|
|
27508
|
+
{ cause: error61 }
|
|
27509
|
+
);
|
|
27510
|
+
}
|
|
27511
|
+
throw new InstallationManagerError(error61.code, error61.message, {
|
|
27512
|
+
cause: error61
|
|
27513
|
+
});
|
|
27514
|
+
}
|
|
27515
|
+
if (error61 instanceof InstallationManagerError) {
|
|
27516
|
+
throw error61;
|
|
27517
|
+
}
|
|
27518
|
+
throw new InstallationManagerError(
|
|
27519
|
+
"agent_install_failed",
|
|
27520
|
+
"The fixed DeepSeek Harness installation recipe failed",
|
|
27521
|
+
{ cause: error61 }
|
|
27522
|
+
);
|
|
27523
|
+
}
|
|
27524
|
+
};
|
|
27525
|
+
};
|
|
27526
|
+
var OpenCodeInstallRecipe = class extends FixedAgentInstallRecipe {
|
|
27527
|
+
#archiveInstaller;
|
|
27528
|
+
id = "opencode";
|
|
27529
|
+
label = "OpenCode";
|
|
27530
|
+
releaseChannel = OPENCODE_MANAGED_VERSION;
|
|
27531
|
+
constructor(archiveInstaller = new ManagedAgentArchiveInstaller()) {
|
|
27532
|
+
super();
|
|
27533
|
+
this.#archiveInstaller = archiveInstaller;
|
|
27534
|
+
}
|
|
27535
|
+
install = async (options) => {
|
|
27536
|
+
this.assertSupportedPlatform();
|
|
27537
|
+
const definition = openCodeManagedArchive(process.platform, process.arch);
|
|
27538
|
+
try {
|
|
27539
|
+
await options.report("downloading");
|
|
27540
|
+
await options.report("verifying");
|
|
27541
|
+
await options.report("installing_agent");
|
|
27542
|
+
const executable = await this.#archiveInstaller.install(
|
|
27543
|
+
join14(
|
|
27544
|
+
options.stateDirectory,
|
|
27545
|
+
"agents",
|
|
27546
|
+
this.id,
|
|
27547
|
+
OPENCODE_MANAGED_VERSION
|
|
27548
|
+
),
|
|
27549
|
+
definition,
|
|
27550
|
+
options.signal
|
|
27551
|
+
);
|
|
27552
|
+
options.audit.record(
|
|
27553
|
+
"agent_archive_verified",
|
|
27554
|
+
options.requestId,
|
|
27555
|
+
this.id,
|
|
27556
|
+
{
|
|
27557
|
+
sha256: definition.archiveSha256,
|
|
27558
|
+
version: definition.version
|
|
27559
|
+
}
|
|
27560
|
+
);
|
|
27561
|
+
return executable;
|
|
27562
|
+
} catch (error61) {
|
|
27563
|
+
if (options.signal.aborted) {
|
|
27564
|
+
options.signal.throwIfAborted();
|
|
27565
|
+
}
|
|
27566
|
+
if (error61 instanceof ManagedAgentArchiveError) {
|
|
27567
|
+
if (error61.code === "managed_archive_verification_failed") {
|
|
27568
|
+
throw new InstallationManagerError(
|
|
27569
|
+
"agent_verification_failed",
|
|
27570
|
+
"The managed OpenCode archive did not match its pinned artifact",
|
|
27571
|
+
{ cause: error61 }
|
|
27572
|
+
);
|
|
27573
|
+
}
|
|
27574
|
+
if (error61.code === "managed_archive_publish_failed") {
|
|
27575
|
+
throw new InstallationManagerError(
|
|
27576
|
+
"agent_publish_failed",
|
|
27577
|
+
"The managed OpenCode archive could not be published",
|
|
27578
|
+
{ cause: error61 }
|
|
27579
|
+
);
|
|
27580
|
+
}
|
|
27581
|
+
throw new InstallationManagerError(error61.code, error61.message, {
|
|
27582
|
+
cause: error61
|
|
27583
|
+
});
|
|
27584
|
+
}
|
|
27585
|
+
if (error61 instanceof InstallationManagerError) {
|
|
27586
|
+
throw error61;
|
|
27587
|
+
}
|
|
27588
|
+
throw new InstallationManagerError(
|
|
27589
|
+
"agent_install_failed",
|
|
27590
|
+
"The fixed OpenCode installation recipe failed",
|
|
27591
|
+
{ cause: error61 }
|
|
27592
|
+
);
|
|
27593
|
+
}
|
|
27594
|
+
};
|
|
27595
|
+
};
|
|
26584
27596
|
function fixedAgentInstallRecipes() {
|
|
26585
27597
|
return Object.freeze([
|
|
26586
27598
|
new CodexInstallRecipe(),
|
|
26587
27599
|
new ClaudeCodeInstallRecipe(),
|
|
26588
|
-
new PiInstallRecipe()
|
|
27600
|
+
new PiInstallRecipe(),
|
|
27601
|
+
new DeepSeekHarnessInstallRecipe(),
|
|
27602
|
+
new OpenCodeInstallRecipe()
|
|
26589
27603
|
]);
|
|
26590
27604
|
}
|
|
26591
27605
|
|
|
@@ -26723,12 +27737,15 @@ var FixedInstallationExecutor = class {
|
|
|
26723
27737
|
});
|
|
26724
27738
|
installedAgent = true;
|
|
26725
27739
|
}
|
|
26726
|
-
let adapter = await resolveAdapterExecutable(
|
|
26727
|
-
specification,
|
|
26728
|
-
discoveryOptions2
|
|
26729
|
-
);
|
|
27740
|
+
let adapter = specification instanceof DirectAcpAgentDefinition ? agent : await resolveAdapterExecutable(specification, discoveryOptions2);
|
|
26730
27741
|
let installedAdapter = false;
|
|
26731
27742
|
if (adapter === null) {
|
|
27743
|
+
if (!(specification instanceof BridgedAcpAgentDefinition)) {
|
|
27744
|
+
throw new InstallationManagerError(
|
|
27745
|
+
"agent_verification_failed",
|
|
27746
|
+
"The direct Agent executable is unavailable"
|
|
27747
|
+
);
|
|
27748
|
+
}
|
|
26732
27749
|
await report("installing_adapter");
|
|
26733
27750
|
adapter = await this.#adapterInstaller.install(specification, signal);
|
|
26734
27751
|
installedAdapter = true;
|
|
@@ -26785,7 +27802,7 @@ var FixedInstallationExecutor = class {
|
|
|
26785
27802
|
"The complete Agent ACP path did not pass verification"
|
|
26786
27803
|
);
|
|
26787
27804
|
}
|
|
26788
|
-
if (!installedAdapter && requiresAdapterReplacement(unavailable.code)) {
|
|
27805
|
+
if (!installedAdapter && specification instanceof BridgedAcpAgentDefinition && requiresAdapterReplacement(unavailable.code)) {
|
|
26789
27806
|
await report("installing_adapter");
|
|
26790
27807
|
adapter = await this.#adapterInstaller.install(specification, signal);
|
|
26791
27808
|
installedAdapter = true;
|
|
@@ -26804,6 +27821,9 @@ var FixedInstallationExecutor = class {
|
|
|
26804
27821
|
stateDirectory: this.#stateDirectory
|
|
26805
27822
|
});
|
|
26806
27823
|
installedAgent = true;
|
|
27824
|
+
if (specification instanceof DirectAcpAgentDefinition) {
|
|
27825
|
+
adapter = agent;
|
|
27826
|
+
}
|
|
26807
27827
|
continue;
|
|
26808
27828
|
}
|
|
26809
27829
|
throw new InstallationManagerError(
|
|
@@ -26856,15 +27876,15 @@ Mobius Web requested installation of ${label} (${requestId}). Allow this fixed u
|
|
|
26856
27876
|
};
|
|
26857
27877
|
|
|
26858
27878
|
// src/authorization/workspace-directory.ts
|
|
26859
|
-
import { readdir, realpath as
|
|
27879
|
+
import { readdir, realpath as realpath6, stat as stat6 } from "node:fs/promises";
|
|
26860
27880
|
import { homedir as homedir2 } from "node:os";
|
|
26861
27881
|
import {
|
|
26862
27882
|
basename as basename2,
|
|
26863
|
-
dirname as
|
|
26864
|
-
isAbsolute as
|
|
26865
|
-
join as
|
|
26866
|
-
normalize,
|
|
26867
|
-
relative as
|
|
27883
|
+
dirname as dirname5,
|
|
27884
|
+
isAbsolute as isAbsolute5,
|
|
27885
|
+
join as join15,
|
|
27886
|
+
normalize as normalize2,
|
|
27887
|
+
relative as relative3
|
|
26868
27888
|
} from "node:path";
|
|
26869
27889
|
var WorkspaceDirectoryListing = class {
|
|
26870
27890
|
directoryId;
|
|
@@ -26892,7 +27912,7 @@ function decodePath(value, prefix) {
|
|
|
26892
27912
|
if (encoded.length === 0 || encoded.length > 2e3 || !/^[a-zA-Z0-9_-]+$/.test(encoded))
|
|
26893
27913
|
throw new LocalAuthorizationError("The directory identifier is invalid");
|
|
26894
27914
|
const decoded = Buffer.from(encoded, "base64url").toString("utf8");
|
|
26895
|
-
if (Buffer.from(decoded, "utf8").toString("base64url") !== encoded || decoded.includes("\0") ||
|
|
27915
|
+
if (Buffer.from(decoded, "utf8").toString("base64url") !== encoded || decoded.includes("\0") || normalize2(decoded) !== decoded)
|
|
26896
27916
|
throw new LocalAuthorizationError("The directory identifier is invalid");
|
|
26897
27917
|
return decoded;
|
|
26898
27918
|
}
|
|
@@ -26914,20 +27934,20 @@ var WorkspaceDirectoryService = class {
|
|
|
26914
27934
|
if (id === "home") return homedir2();
|
|
26915
27935
|
if (id.startsWith("path-")) {
|
|
26916
27936
|
const path2 = decodePath(id, "path-");
|
|
26917
|
-
if (
|
|
27937
|
+
if (isAbsolute5(path2)) return path2;
|
|
26918
27938
|
}
|
|
26919
27939
|
throw new LocalAuthorizationError("The directory identifier is invalid");
|
|
26920
27940
|
};
|
|
26921
27941
|
resolvePath = async (requested, signal) => {
|
|
26922
27942
|
signal.throwIfAborted();
|
|
26923
|
-
if (!
|
|
27943
|
+
if (!isAbsolute5(requested) || requested.includes("\0") || normalize2(requested) !== requested)
|
|
26924
27944
|
throw new LocalAuthorizationError("The local directory path is invalid");
|
|
26925
27945
|
try {
|
|
26926
|
-
const target = await
|
|
27946
|
+
const target = await realpath6(requested);
|
|
26927
27947
|
signal.throwIfAborted();
|
|
26928
|
-
const metadata = await
|
|
27948
|
+
const metadata = await stat6(target);
|
|
26929
27949
|
signal.throwIfAborted();
|
|
26930
|
-
if (!
|
|
27950
|
+
if (!isAbsolute5(target) || normalize2(target) !== target || !metadata.isDirectory())
|
|
26931
27951
|
throw new LocalAuthorizationError(
|
|
26932
27952
|
"The selected location is not a directory"
|
|
26933
27953
|
);
|
|
@@ -26942,8 +27962,8 @@ var WorkspaceDirectoryService = class {
|
|
|
26942
27962
|
}
|
|
26943
27963
|
};
|
|
26944
27964
|
label = (path2) => {
|
|
26945
|
-
const suffix =
|
|
26946
|
-
return suffix === "" ? "~" : !
|
|
27965
|
+
const suffix = relative3(homedir2(), path2);
|
|
27966
|
+
return suffix === "" ? "~" : !isAbsolute5(suffix) && suffix !== ".." && !suffix.startsWith(`..${process.platform === "win32" ? "\\" : "/"}`) ? `~/${suffix.replaceAll("\\", "/")}` : path2;
|
|
26947
27967
|
};
|
|
26948
27968
|
identify = async (bindingId, requestedPath, signal) => {
|
|
26949
27969
|
this.authorizeMachine(bindingId);
|
|
@@ -26971,7 +27991,7 @@ var WorkspaceDirectoryService = class {
|
|
|
26971
27991
|
continue;
|
|
26972
27992
|
}
|
|
26973
27993
|
try {
|
|
26974
|
-
const path2 = await this.resolvePath(
|
|
27994
|
+
const path2 = await this.resolvePath(join15(target, child.name), signal);
|
|
26975
27995
|
entries.push({ directoryId: encodePath(path2), name: child.name });
|
|
26976
27996
|
} catch (cause) {
|
|
26977
27997
|
signal.throwIfAborted();
|
|
@@ -26979,7 +27999,7 @@ var WorkspaceDirectoryService = class {
|
|
|
26979
27999
|
}
|
|
26980
28000
|
}
|
|
26981
28001
|
entries.sort((a, b) => a.name.localeCompare(b.name));
|
|
26982
|
-
const parent =
|
|
28002
|
+
const parent = dirname5(target);
|
|
26983
28003
|
return new WorkspaceDirectoryListing(
|
|
26984
28004
|
id,
|
|
26985
28005
|
this.label(target),
|
|
@@ -27094,7 +28114,8 @@ function decodeHistory(thread, value) {
|
|
|
27094
28114
|
status: "available",
|
|
27095
28115
|
messages,
|
|
27096
28116
|
truncated,
|
|
27097
|
-
coveredCommandIds: []
|
|
28117
|
+
coveredCommandIds: [],
|
|
28118
|
+
coveredMessageIds: []
|
|
27098
28119
|
}
|
|
27099
28120
|
};
|
|
27100
28121
|
}
|
|
@@ -27771,7 +28792,7 @@ var RelayConnectionLiveness = class {
|
|
|
27771
28792
|
|
|
27772
28793
|
// src/relay-connection/session-event-outbox.ts
|
|
27773
28794
|
import { mkdirSync as mkdirSync3 } from "node:fs";
|
|
27774
|
-
import { dirname as
|
|
28795
|
+
import { dirname as dirname6 } from "node:path";
|
|
27775
28796
|
import { DatabaseSync as DatabaseSync3 } from "node:sqlite";
|
|
27776
28797
|
function readPendingEnvelope(row) {
|
|
27777
28798
|
if (typeof row !== "object" || row === null || Array.isArray(row)) {
|
|
@@ -27786,7 +28807,7 @@ function readPendingEnvelope(row) {
|
|
|
27786
28807
|
var SessionEventOutbox = class {
|
|
27787
28808
|
#database;
|
|
27788
28809
|
constructor(path2) {
|
|
27789
|
-
mkdirSync3(
|
|
28810
|
+
mkdirSync3(dirname6(path2), { recursive: true });
|
|
27790
28811
|
this.#database = new DatabaseSync3(path2);
|
|
27791
28812
|
this.#database.exec(`
|
|
27792
28813
|
CREATE TABLE IF NOT EXISTS relay_session_event_outbox (
|
|
@@ -28530,10 +29551,11 @@ function waitForRelayRetry(signal, timer) {
|
|
|
28530
29551
|
signal.addEventListener("abort", finish, { once: true });
|
|
28531
29552
|
});
|
|
28532
29553
|
}
|
|
28533
|
-
async function runRelayConnection(config2, directories, audit, sessions, installations, installationObserver, nativeSessions, outbox, signal, timer) {
|
|
29554
|
+
async function runRelayConnection(config2, directories, audit, sessions, installations, installationObserver, nativeSessions, outbox, onConnected, signal, timer) {
|
|
28534
29555
|
const relayUrl = new URL(config2.relayUrl);
|
|
28535
29556
|
relayUrl.searchParams.set("liveness", "1");
|
|
28536
29557
|
const socket = await connectRelay(relayUrl, signal);
|
|
29558
|
+
onConnected();
|
|
28537
29559
|
const activeTurns = /* @__PURE__ */ new Map();
|
|
28538
29560
|
const activeAttemptIds = /* @__PURE__ */ new Map();
|
|
28539
29561
|
const connectionController = new AbortController();
|
|
@@ -28968,6 +29990,24 @@ async function runDaemon(config2, audit, signal, timer = systemDaemonTimer) {
|
|
|
28968
29990
|
installationAudit
|
|
28969
29991
|
);
|
|
28970
29992
|
let retryAnnounced = false;
|
|
29993
|
+
let connectionAnnounced = false;
|
|
29994
|
+
const announceConnection = () => {
|
|
29995
|
+
if (connectionAnnounced) {
|
|
29996
|
+
return;
|
|
29997
|
+
}
|
|
29998
|
+
connectionAnnounced = true;
|
|
29999
|
+
const reconnectCommand = `npx --yes @moxt-ai/mobius start --channel ${config2.channelId}`;
|
|
30000
|
+
process.stdout.write("Mobius daemon connected to the relay.\n\n");
|
|
30001
|
+
process.stdout.write(
|
|
30002
|
+
`${styleText(
|
|
30003
|
+
["bold", "yellow"],
|
|
30004
|
+
`Reconnect this channel later:
|
|
30005
|
+
${reconnectCommand}`
|
|
30006
|
+
)}
|
|
30007
|
+
|
|
30008
|
+
`
|
|
30009
|
+
);
|
|
30010
|
+
};
|
|
28971
30011
|
try {
|
|
28972
30012
|
while (!signal.aborted) {
|
|
28973
30013
|
try {
|
|
@@ -28981,6 +30021,7 @@ async function runDaemon(config2, audit, signal, timer = systemDaemonTimer) {
|
|
|
28981
30021
|
installationObserver,
|
|
28982
30022
|
nativeSessions,
|
|
28983
30023
|
outbox,
|
|
30024
|
+
announceConnection,
|
|
28984
30025
|
signal,
|
|
28985
30026
|
timer
|
|
28986
30027
|
);
|