@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/cli.js
CHANGED
|
@@ -6,100 +6,24 @@ var __export = (target, all) => {
|
|
|
6
6
|
};
|
|
7
7
|
|
|
8
8
|
// src/cli.ts
|
|
9
|
-
import { mkdir as
|
|
9
|
+
import { mkdir as mkdir5 } from "node:fs/promises";
|
|
10
10
|
|
|
11
|
-
// src/agent-catalog/
|
|
12
|
-
import {
|
|
13
|
-
import { isAbsolute as isAbsolute2, join as join6 } from "node:path";
|
|
14
|
-
import {
|
|
15
|
-
methods as methods2,
|
|
16
|
-
ndJsonStream,
|
|
17
|
-
PROTOCOL_VERSION,
|
|
18
|
-
RequestError
|
|
19
|
-
} from "@agentclientprotocol/sdk";
|
|
20
|
-
|
|
21
|
-
// src/acp/create-client.ts
|
|
22
|
-
import {
|
|
23
|
-
client,
|
|
24
|
-
methods
|
|
25
|
-
} from "@agentclientprotocol/sdk";
|
|
26
|
-
var createAcpClient = (handler) => client({ name: "mobius" }).onRequest(
|
|
27
|
-
methods.client.session.requestPermission,
|
|
28
|
-
async (context) => await handler.onPermission(context.params, context.signal)
|
|
29
|
-
).onRequest(
|
|
30
|
-
methods.client.elicitation.create,
|
|
31
|
-
async (context) => await handler.onElicitation(context.params, context.signal)
|
|
32
|
-
).onNotification(methods.client.session.update, async (context) => {
|
|
33
|
-
await handler.onUpdate(context.params);
|
|
34
|
-
}).onNotification(methods.client.elicitation.complete, async (context) => {
|
|
35
|
-
await handler.onElicitationComplete(context.params);
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
// src/agent-installation/installation-grants.ts
|
|
39
|
-
import { open } from "node:fs/promises";
|
|
40
|
-
import { join } from "node:path";
|
|
41
|
-
var MAX_GRANT_FILE_LENGTH = 16 * 1024;
|
|
42
|
-
var AGENT_ID_PATTERN = /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/;
|
|
43
|
-
function isRecord(value) {
|
|
44
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
45
|
-
}
|
|
46
|
-
async function readGrantedAgents(stateDirectory) {
|
|
47
|
-
const path2 = join(stateDirectory, "installation-grants.json");
|
|
48
|
-
let handle;
|
|
49
|
-
try {
|
|
50
|
-
handle = await open(path2, "r");
|
|
51
|
-
} catch (error61) {
|
|
52
|
-
if (error61 instanceof Error && "code" in error61 && error61.code === "ENOENT") {
|
|
53
|
-
return /* @__PURE__ */ new Set();
|
|
54
|
-
}
|
|
55
|
-
throw error61;
|
|
56
|
-
}
|
|
57
|
-
try {
|
|
58
|
-
const metadata = await handle.stat();
|
|
59
|
-
if (!metadata.isFile() || metadata.size > MAX_GRANT_FILE_LENGTH || typeof process.getuid === "function" && metadata.uid !== process.getuid() || process.platform !== "win32" && (metadata.mode & 63) !== 0) {
|
|
60
|
-
throw new Error("The local installation grant file is not private");
|
|
61
|
-
}
|
|
62
|
-
const encoded = await handle.readFile({ encoding: "utf8" });
|
|
63
|
-
const value = JSON.parse(encoded);
|
|
64
|
-
if (!isRecord(value) || Object.keys(value).length !== 1 || !Array.isArray(value["agents"])) {
|
|
65
|
-
throw new Error("The local installation grant file is invalid");
|
|
66
|
-
}
|
|
67
|
-
const agents = /* @__PURE__ */ new Set();
|
|
68
|
-
for (const candidate of value["agents"]) {
|
|
69
|
-
if (typeof candidate !== "string" || !AGENT_ID_PATTERN.test(candidate) || agents.has(candidate)) {
|
|
70
|
-
throw new Error("The local installation grant file is invalid");
|
|
71
|
-
}
|
|
72
|
-
agents.add(candidate);
|
|
73
|
-
}
|
|
74
|
-
return agents;
|
|
75
|
-
} finally {
|
|
76
|
-
await handle.close();
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
// src/agent-installation/managed-adapter-installer.ts
|
|
81
|
-
import { join as join4 } from "node:path";
|
|
82
|
-
|
|
83
|
-
// src/agent-installation/managed-npm-package.ts
|
|
84
|
-
import {
|
|
85
|
-
mkdir,
|
|
86
|
-
mkdtemp,
|
|
87
|
-
open as open2,
|
|
88
|
-
realpath as realpath2,
|
|
89
|
-
rename,
|
|
90
|
-
rm,
|
|
91
|
-
stat as stat2
|
|
92
|
-
} from "node:fs/promises";
|
|
93
|
-
import { delimiter, dirname, isAbsolute, join as join3, relative, sep } from "node:path";
|
|
11
|
+
// src/agent-catalog/local-agent.ts
|
|
12
|
+
import { realpathSync, statSync } from "node:fs";
|
|
94
13
|
|
|
95
14
|
// src/process/executable.ts
|
|
96
|
-
import { spawn } from "node:child_process";
|
|
15
|
+
import { execFile, spawn } from "node:child_process";
|
|
97
16
|
import { constants } from "node:fs";
|
|
98
17
|
import { access, realpath, stat } from "node:fs/promises";
|
|
99
|
-
import { join
|
|
18
|
+
import { join, resolve } from "node:path";
|
|
100
19
|
var DEFAULT_OUTPUT_LIMIT_BYTES = 16 * 1024;
|
|
101
20
|
var PROCESS_GRACEFUL_STOP_TIMEOUT_MILLISECONDS = 1e3;
|
|
102
21
|
var PROCESS_FORCED_STOP_TIMEOUT_MILLISECONDS = 5e3;
|
|
22
|
+
var PROCESS_TABLE_TIMEOUT_MILLISECONDS = 1e3;
|
|
23
|
+
var PROCESS_TABLE_OUTPUT_LIMIT_BYTES = 1024 * 1024;
|
|
24
|
+
var PROCESS_EXIT_CHECK_ATTEMPTS = 8;
|
|
25
|
+
var GRACEFUL_STOP_SIGNAL = 15;
|
|
26
|
+
var FORCED_STOP_SIGNAL = 9;
|
|
103
27
|
var ExecutableIdentity = class {
|
|
104
28
|
changedAtMilliseconds;
|
|
105
29
|
device;
|
|
@@ -193,7 +117,7 @@ async function findExecutableOnPath(executableName, environment, platform = proc
|
|
|
193
117
|
}
|
|
194
118
|
for (const extension of extensions) {
|
|
195
119
|
const requestedPath = resolve(
|
|
196
|
-
|
|
120
|
+
join(entry, `${executableName}${extension}`)
|
|
197
121
|
);
|
|
198
122
|
const executable = await resolveExecutablePath(requestedPath, platform);
|
|
199
123
|
if (executable !== null) {
|
|
@@ -218,6 +142,119 @@ function appendBounded(chunks, chunk, currentBytes, limitBytes) {
|
|
|
218
142
|
chunks.push(chunk);
|
|
219
143
|
return nextBytes;
|
|
220
144
|
}
|
|
145
|
+
function parseProcessTable(output2) {
|
|
146
|
+
const entries = [];
|
|
147
|
+
for (const line of output2.split("\n")) {
|
|
148
|
+
const groups = /^\s*(?<pid>\d+)\s+(?<ppid>\d+)\s+(?<pgid>\d+)\s*$/.exec(
|
|
149
|
+
line
|
|
150
|
+
)?.groups;
|
|
151
|
+
if (groups === void 0) {
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
const processId = Number(groups["pid"]);
|
|
155
|
+
const parentProcessId = Number(groups["ppid"]);
|
|
156
|
+
const processGroupId = Number(groups["pgid"]);
|
|
157
|
+
if (!Number.isSafeInteger(processId) || processId <= 0 || !Number.isSafeInteger(parentProcessId) || parentProcessId < 0 || !Number.isSafeInteger(processGroupId) || processGroupId <= 0) {
|
|
158
|
+
continue;
|
|
159
|
+
}
|
|
160
|
+
entries.push({ parentProcessId, processGroupId, processId });
|
|
161
|
+
}
|
|
162
|
+
return entries;
|
|
163
|
+
}
|
|
164
|
+
function readProcessTable() {
|
|
165
|
+
if (process.platform === "win32") {
|
|
166
|
+
return Promise.resolve([]);
|
|
167
|
+
}
|
|
168
|
+
const executable = process.platform === "darwin" ? "/bin/ps" : "/usr/bin/ps";
|
|
169
|
+
return new Promise((resolveTable) => {
|
|
170
|
+
execFile(
|
|
171
|
+
executable,
|
|
172
|
+
["-axo", "pid=,ppid=,pgid="],
|
|
173
|
+
{
|
|
174
|
+
encoding: "utf8",
|
|
175
|
+
maxBuffer: PROCESS_TABLE_OUTPUT_LIMIT_BYTES,
|
|
176
|
+
signal: AbortSignal.timeout(PROCESS_TABLE_TIMEOUT_MILLISECONDS),
|
|
177
|
+
timeout: PROCESS_TABLE_TIMEOUT_MILLISECONDS
|
|
178
|
+
},
|
|
179
|
+
(error61, stdout) => {
|
|
180
|
+
resolveTable(error61 === null ? parseProcessTable(stdout) : []);
|
|
181
|
+
}
|
|
182
|
+
);
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
function selectProcessTree(entries, rootProcessId) {
|
|
186
|
+
const processIds = /* @__PURE__ */ new Set([rootProcessId]);
|
|
187
|
+
let previousSize = 0;
|
|
188
|
+
while (previousSize !== processIds.size) {
|
|
189
|
+
previousSize = processIds.size;
|
|
190
|
+
for (const entry of entries) {
|
|
191
|
+
if (processIds.has(entry.parentProcessId)) {
|
|
192
|
+
processIds.add(entry.processId);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
return entries.filter((entry) => processIds.has(entry.processId)).map((entry) => ({
|
|
197
|
+
processGroupId: entry.processGroupId,
|
|
198
|
+
processId: entry.processId
|
|
199
|
+
}));
|
|
200
|
+
}
|
|
201
|
+
function mergeProcessTrees(captured, current) {
|
|
202
|
+
const processes = /* @__PURE__ */ new Map();
|
|
203
|
+
for (const identity2 of captured) {
|
|
204
|
+
processes.set(identity2.processId, identity2);
|
|
205
|
+
}
|
|
206
|
+
for (const identity2 of current) {
|
|
207
|
+
processes.set(identity2.processId, identity2);
|
|
208
|
+
}
|
|
209
|
+
return [...processes.values()];
|
|
210
|
+
}
|
|
211
|
+
async function captureProcessTree(child) {
|
|
212
|
+
if (process.platform === "win32" || child.pid === void 0) {
|
|
213
|
+
return [];
|
|
214
|
+
}
|
|
215
|
+
return selectProcessTree(await readProcessTable(), child.pid);
|
|
216
|
+
}
|
|
217
|
+
function signalDetachedProcessGroups(processes, rootProcessId, signal) {
|
|
218
|
+
const processIds = new Set(processes.map((identity2) => identity2.processId));
|
|
219
|
+
const signalledGroups = /* @__PURE__ */ new Set();
|
|
220
|
+
for (const identity2 of processes) {
|
|
221
|
+
if (identity2.processGroupId === rootProcessId || !processIds.has(identity2.processGroupId) || signalledGroups.has(identity2.processGroupId)) {
|
|
222
|
+
continue;
|
|
223
|
+
}
|
|
224
|
+
try {
|
|
225
|
+
process.kill(-identity2.processGroupId, signal);
|
|
226
|
+
signalledGroups.add(identity2.processGroupId);
|
|
227
|
+
} catch {
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
for (const identity2 of processes) {
|
|
231
|
+
if (identity2.processId === rootProcessId || identity2.processGroupId === rootProcessId || signalledGroups.has(identity2.processGroupId)) {
|
|
232
|
+
continue;
|
|
233
|
+
}
|
|
234
|
+
try {
|
|
235
|
+
process.kill(identity2.processId, signal);
|
|
236
|
+
} catch {
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
function processExists(processId) {
|
|
241
|
+
try {
|
|
242
|
+
process.kill(processId, 0);
|
|
243
|
+
return true;
|
|
244
|
+
} catch {
|
|
245
|
+
return false;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
async function waitForCapturedProcessesExit(processes, rootProcessId) {
|
|
249
|
+
const processIds = processes.map((identity2) => identity2.processId).filter((processId) => processId !== rootProcessId);
|
|
250
|
+
for (let attempt = 0; attempt < PROCESS_EXIT_CHECK_ATTEMPTS; attempt += 1) {
|
|
251
|
+
if (processIds.every((processId) => !processExists(processId))) {
|
|
252
|
+
return true;
|
|
253
|
+
}
|
|
254
|
+
await readProcessTable();
|
|
255
|
+
}
|
|
256
|
+
return processIds.every((processId) => !processExists(processId));
|
|
257
|
+
}
|
|
221
258
|
function terminateProcess(child) {
|
|
222
259
|
if (child.exitCode !== null || child.signalCode !== null || child.pid === void 0) {
|
|
223
260
|
return;
|
|
@@ -244,24 +281,35 @@ function forceTerminateProcess(child) {
|
|
|
244
281
|
}
|
|
245
282
|
child.kill("SIGKILL");
|
|
246
283
|
}
|
|
247
|
-
async function stopProcessTree(child) {
|
|
248
|
-
|
|
284
|
+
async function stopProcessTree(child, capturedProcesses = []) {
|
|
285
|
+
const childProcessId = child.pid;
|
|
286
|
+
if (childProcessId === void 0) {
|
|
249
287
|
return;
|
|
250
288
|
}
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
289
|
+
const childExited = child.exitCode !== null || child.signalCode !== null;
|
|
290
|
+
if (childExited && capturedProcesses.length === 0) {
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
const processes = mergeProcessTrees(
|
|
294
|
+
capturedProcesses,
|
|
295
|
+
childExited ? [] : await captureProcessTree(child)
|
|
255
296
|
);
|
|
256
|
-
|
|
297
|
+
signalDetachedProcessGroups(processes, childProcessId, GRACEFUL_STOP_SIGNAL);
|
|
298
|
+
terminateProcess(child);
|
|
299
|
+
const [exitedAfterTermination, descendantsExitedAfterTermination] = await Promise.all([
|
|
300
|
+
waitForProcessExit(child, PROCESS_GRACEFUL_STOP_TIMEOUT_MILLISECONDS),
|
|
301
|
+
waitForCapturedProcessesExit(processes, childProcessId)
|
|
302
|
+
]);
|
|
303
|
+
if (exitedAfterTermination && descendantsExitedAfterTermination) {
|
|
257
304
|
return;
|
|
258
305
|
}
|
|
306
|
+
signalDetachedProcessGroups(processes, childProcessId, FORCED_STOP_SIGNAL);
|
|
259
307
|
forceTerminateProcess(child);
|
|
260
|
-
const exitedAfterForce = await
|
|
261
|
-
child,
|
|
262
|
-
|
|
263
|
-
);
|
|
264
|
-
if (!exitedAfterForce) {
|
|
308
|
+
const [exitedAfterForce, descendantsExitedAfterForce] = await Promise.all([
|
|
309
|
+
waitForProcessExit(child, PROCESS_FORCED_STOP_TIMEOUT_MILLISECONDS),
|
|
310
|
+
waitForCapturedProcessesExit(processes, childProcessId)
|
|
311
|
+
]);
|
|
312
|
+
if (!exitedAfterForce || !descendantsExitedAfterForce) {
|
|
265
313
|
throw new ProcessExecutionError(
|
|
266
314
|
"process_termination_timeout",
|
|
267
315
|
"The executable process could not be stopped"
|
|
@@ -428,590 +476,1533 @@ async function runBoundedProcess(options) {
|
|
|
428
476
|
}
|
|
429
477
|
}
|
|
430
478
|
|
|
431
|
-
// src/agent-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
479
|
+
// src/agent-catalog/local-agent.ts
|
|
480
|
+
function readTrustedIdentity(path2) {
|
|
481
|
+
const resolvedPath = realpathSync(path2);
|
|
482
|
+
const metadata = statSync(resolvedPath);
|
|
483
|
+
return new ExecutableIdentity(
|
|
484
|
+
resolvedPath,
|
|
485
|
+
resolvedPath,
|
|
486
|
+
metadata.dev,
|
|
487
|
+
metadata.ino,
|
|
488
|
+
metadata.size,
|
|
489
|
+
metadata.ctimeMs
|
|
490
|
+
);
|
|
491
|
+
}
|
|
492
|
+
var LocalAgentDefinition = class {
|
|
493
|
+
adapterIdentity;
|
|
494
|
+
adapterPath;
|
|
495
|
+
adapterVersion;
|
|
496
|
+
agentIdentity;
|
|
497
|
+
agentVersion;
|
|
498
|
+
arguments;
|
|
499
|
+
command;
|
|
500
|
+
environment;
|
|
501
|
+
id;
|
|
502
|
+
label;
|
|
503
|
+
promptTimeoutMilliseconds;
|
|
504
|
+
constructor(id, label, command, arguments_, environment = {}, adapterVersion = "", agentVersion = "", adapterIdentity = readTrustedIdentity(command), agentIdentity = adapterIdentity, promptTimeoutMilliseconds = 30 * 60 * 1e3) {
|
|
505
|
+
if (!Number.isSafeInteger(promptTimeoutMilliseconds) || promptTimeoutMilliseconds < 1) {
|
|
506
|
+
throw new Error("The local Agent prompt deadline is invalid");
|
|
507
|
+
}
|
|
508
|
+
this.adapterIdentity = adapterIdentity;
|
|
509
|
+
this.adapterPath = adapterIdentity.realPath;
|
|
510
|
+
this.adapterVersion = adapterVersion;
|
|
511
|
+
this.agentIdentity = agentIdentity;
|
|
512
|
+
this.agentVersion = agentVersion;
|
|
513
|
+
this.id = id;
|
|
514
|
+
this.label = label;
|
|
515
|
+
this.promptTimeoutMilliseconds = promptTimeoutMilliseconds;
|
|
516
|
+
this.command = adapterIdentity.realPath;
|
|
517
|
+
this.arguments = Object.freeze([...arguments_]);
|
|
518
|
+
this.environment = Object.freeze({ ...environment });
|
|
443
519
|
}
|
|
444
520
|
};
|
|
445
|
-
var
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
this.
|
|
451
|
-
this.
|
|
521
|
+
var InstallableAgentDefinition = class {
|
|
522
|
+
id;
|
|
523
|
+
label;
|
|
524
|
+
requiresLocalApproval;
|
|
525
|
+
constructor(id, label, requiresLocalApproval = true) {
|
|
526
|
+
this.id = id;
|
|
527
|
+
this.label = label;
|
|
528
|
+
this.requiresLocalApproval = requiresLocalApproval;
|
|
452
529
|
}
|
|
453
530
|
};
|
|
454
|
-
var
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
this.
|
|
459
|
-
this.
|
|
531
|
+
var LocalAgentCatalogSnapshot = class {
|
|
532
|
+
agents;
|
|
533
|
+
installableAgents;
|
|
534
|
+
constructor(agents, installableAgents) {
|
|
535
|
+
this.agents = Object.freeze([...agents]);
|
|
536
|
+
this.installableAgents = Object.freeze([...installableAgents]);
|
|
460
537
|
}
|
|
461
538
|
};
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
throw new ManagedNpmPackageError(
|
|
479
|
-
"managed_package_verification_failed",
|
|
480
|
-
"The managed npm package metadata is invalid"
|
|
481
|
-
);
|
|
482
|
-
}
|
|
483
|
-
const value = JSON.parse(
|
|
484
|
-
await handle.readFile({ encoding: "utf8" })
|
|
485
|
-
);
|
|
486
|
-
if (!isRecord2(value)) {
|
|
487
|
-
throw new ManagedNpmPackageError(
|
|
488
|
-
"managed_package_verification_failed",
|
|
489
|
-
"The managed npm package metadata is invalid"
|
|
490
|
-
);
|
|
539
|
+
var LocalAgentCatalogError = class extends Error {
|
|
540
|
+
code = "agent_not_ready";
|
|
541
|
+
constructor() {
|
|
542
|
+
super("The requested local Agent is not ready");
|
|
543
|
+
this.name = "LocalAgentCatalogError";
|
|
544
|
+
}
|
|
545
|
+
};
|
|
546
|
+
var LocalAgentCatalog = class {
|
|
547
|
+
#snapshot;
|
|
548
|
+
constructor(agents, installableAgents) {
|
|
549
|
+
this.#snapshot = this.validate(agents, installableAgents);
|
|
550
|
+
}
|
|
551
|
+
find = (agentId) => {
|
|
552
|
+
for (const agent of this.#snapshot.agents) {
|
|
553
|
+
if (agent.id === agentId) {
|
|
554
|
+
return agent;
|
|
491
555
|
}
|
|
492
|
-
return value;
|
|
493
|
-
} finally {
|
|
494
|
-
await handle.close();
|
|
495
556
|
}
|
|
557
|
+
throw new LocalAgentCatalogError();
|
|
558
|
+
};
|
|
559
|
+
read = () => this.#snapshot;
|
|
560
|
+
transition = (agents, installableAgents) => {
|
|
561
|
+
const next = this.validate(agents, installableAgents);
|
|
562
|
+
this.#snapshot = next;
|
|
563
|
+
return next;
|
|
564
|
+
};
|
|
565
|
+
validate = (agents, installableAgents) => {
|
|
566
|
+
const identifiers = /* @__PURE__ */ new Set();
|
|
567
|
+
for (const agent of agents) {
|
|
568
|
+
if (identifiers.has(agent.id)) {
|
|
569
|
+
throw new Error("The local Agent catalog contains duplicate entries");
|
|
570
|
+
}
|
|
571
|
+
identifiers.add(agent.id);
|
|
572
|
+
}
|
|
573
|
+
for (const agent of installableAgents) {
|
|
574
|
+
if (identifiers.has(agent.id)) {
|
|
575
|
+
throw new Error("A local Agent cannot be ready and installable");
|
|
576
|
+
}
|
|
577
|
+
identifiers.add(agent.id);
|
|
578
|
+
}
|
|
579
|
+
return new LocalAgentCatalogSnapshot(agents, installableAgents);
|
|
580
|
+
};
|
|
581
|
+
};
|
|
582
|
+
|
|
583
|
+
// src/agent-catalog/agent-discovery.ts
|
|
584
|
+
var AgentDiscovery = class {
|
|
585
|
+
specification;
|
|
586
|
+
constructor(specification) {
|
|
587
|
+
this.specification = specification;
|
|
588
|
+
}
|
|
589
|
+
};
|
|
590
|
+
var AvailableAgent = class extends AgentDiscovery {
|
|
591
|
+
agent;
|
|
592
|
+
status = "ready";
|
|
593
|
+
constructor(specification, agent) {
|
|
594
|
+
super(specification);
|
|
595
|
+
this.agent = agent;
|
|
596
|
+
}
|
|
597
|
+
};
|
|
598
|
+
var UnavailableAgent = class extends AgentDiscovery {
|
|
599
|
+
};
|
|
600
|
+
var MissingAdapter = class extends UnavailableAgent {
|
|
601
|
+
code = "adapter_not_found";
|
|
602
|
+
message = "ACP adapter not found";
|
|
603
|
+
status = "missing_adapter";
|
|
604
|
+
constructor(specification) {
|
|
605
|
+
super(specification);
|
|
606
|
+
}
|
|
607
|
+
};
|
|
608
|
+
var MissingAgent = class extends UnavailableAgent {
|
|
609
|
+
code = "agent_not_found";
|
|
610
|
+
message = "Agent executable not found";
|
|
611
|
+
status = "missing_agent";
|
|
612
|
+
constructor(specification) {
|
|
613
|
+
super(specification);
|
|
614
|
+
}
|
|
615
|
+
};
|
|
616
|
+
var ProbeFailed = class extends UnavailableAgent {
|
|
617
|
+
code;
|
|
618
|
+
message;
|
|
619
|
+
status = "probe_failed";
|
|
620
|
+
constructor(specification, code, message) {
|
|
621
|
+
super(specification);
|
|
622
|
+
this.code = code;
|
|
623
|
+
this.message = message;
|
|
624
|
+
}
|
|
625
|
+
};
|
|
626
|
+
var IncompatibleAdapter = class extends UnavailableAgent {
|
|
627
|
+
code = "acp_incompatible";
|
|
628
|
+
message = "ACP adapter is incompatible";
|
|
629
|
+
status = "incompatible_adapter";
|
|
630
|
+
constructor(specification) {
|
|
631
|
+
super(specification);
|
|
632
|
+
}
|
|
633
|
+
};
|
|
634
|
+
var AuthenticationRequiredAgent = class extends UnavailableAgent {
|
|
635
|
+
code = "authentication_required";
|
|
636
|
+
message = "Agent authentication is required";
|
|
637
|
+
status = "authentication_required";
|
|
638
|
+
constructor(specification) {
|
|
639
|
+
super(specification);
|
|
640
|
+
}
|
|
641
|
+
};
|
|
642
|
+
var LocalAgentInventory = class {
|
|
643
|
+
available;
|
|
644
|
+
discoveries;
|
|
645
|
+
installable;
|
|
646
|
+
unavailable;
|
|
647
|
+
constructor(discoveries, grantedAgents = /* @__PURE__ */ new Set(), platform = process.platform, architecture = process.arch) {
|
|
648
|
+
const available = [];
|
|
649
|
+
const unavailable = [];
|
|
650
|
+
for (const discovery of discoveries) {
|
|
651
|
+
if (discovery instanceof AvailableAgent) {
|
|
652
|
+
available.push(discovery);
|
|
653
|
+
} else if (discovery instanceof UnavailableAgent) {
|
|
654
|
+
unavailable.push(discovery);
|
|
655
|
+
} else {
|
|
656
|
+
throw new Error("Unsupported Agent discovery outcome");
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
this.available = Object.freeze(available);
|
|
660
|
+
this.discoveries = Object.freeze([...discoveries]);
|
|
661
|
+
this.installable = Object.freeze(
|
|
662
|
+
unavailable.filter(
|
|
663
|
+
(discovery) => !(discovery instanceof AuthenticationRequiredAgent) && discovery.specification.supportsInstallation(
|
|
664
|
+
platform,
|
|
665
|
+
architecture
|
|
666
|
+
)
|
|
667
|
+
).map(
|
|
668
|
+
(discovery) => new InstallableAgentDefinition(
|
|
669
|
+
discovery.specification.id,
|
|
670
|
+
discovery.specification.label,
|
|
671
|
+
!grantedAgents.has(discovery.specification.id)
|
|
672
|
+
)
|
|
673
|
+
)
|
|
674
|
+
);
|
|
675
|
+
this.unavailable = Object.freeze(unavailable);
|
|
676
|
+
}
|
|
677
|
+
readyAgents = () => this.available.map((discovery) => discovery.agent);
|
|
678
|
+
};
|
|
679
|
+
|
|
680
|
+
// src/agent-catalog/agent-diagnostics.ts
|
|
681
|
+
var AvailableAgentDiagnostic = class {
|
|
682
|
+
adapterVersion;
|
|
683
|
+
agentVersion;
|
|
684
|
+
id;
|
|
685
|
+
label;
|
|
686
|
+
status = "ready";
|
|
687
|
+
constructor(discovery) {
|
|
688
|
+
this.adapterVersion = discovery.agent.adapterVersion;
|
|
689
|
+
this.agentVersion = discovery.agent.agentVersion;
|
|
690
|
+
this.id = discovery.specification.id;
|
|
691
|
+
this.label = discovery.specification.label;
|
|
692
|
+
}
|
|
693
|
+
};
|
|
694
|
+
var UnavailableAgentDiagnostic = class {
|
|
695
|
+
code;
|
|
696
|
+
id;
|
|
697
|
+
label;
|
|
698
|
+
message;
|
|
699
|
+
recoveryCommand;
|
|
700
|
+
status;
|
|
701
|
+
constructor(discovery) {
|
|
702
|
+
this.code = discovery.code;
|
|
703
|
+
this.id = discovery.specification.id;
|
|
704
|
+
this.label = discovery.specification.label;
|
|
705
|
+
this.message = discovery.message;
|
|
706
|
+
this.recoveryCommand = discovery instanceof MissingAdapter ? discovery.specification.recoveryCommand() : discovery.code === "authentication_required" ? discovery.specification.authenticationCommand() : "";
|
|
707
|
+
this.status = discovery.status;
|
|
708
|
+
}
|
|
709
|
+
};
|
|
710
|
+
var AgentDiagnostics = class {
|
|
711
|
+
available;
|
|
712
|
+
unavailable;
|
|
713
|
+
constructor(inventory) {
|
|
714
|
+
this.available = inventory.available.map(
|
|
715
|
+
(discovery) => new AvailableAgentDiagnostic(discovery)
|
|
716
|
+
);
|
|
717
|
+
this.unavailable = inventory.unavailable.map(
|
|
718
|
+
(discovery) => new UnavailableAgentDiagnostic(discovery)
|
|
719
|
+
);
|
|
720
|
+
}
|
|
721
|
+
};
|
|
722
|
+
function humanLine(label, status, detail) {
|
|
723
|
+
return `${label.padEnd(13)} ${status.padEnd(17)} ${detail}`.trimEnd();
|
|
724
|
+
}
|
|
725
|
+
function formatAgentDiagnostics(inventory, json2) {
|
|
726
|
+
const diagnostics = new AgentDiagnostics(inventory);
|
|
727
|
+
if (json2) {
|
|
728
|
+
return `${JSON.stringify(diagnostics, null, 2)}
|
|
729
|
+
`;
|
|
730
|
+
}
|
|
731
|
+
const lines = [];
|
|
732
|
+
for (const available of diagnostics.available) {
|
|
733
|
+
lines.push(
|
|
734
|
+
humanLine(
|
|
735
|
+
available.label,
|
|
736
|
+
available.status,
|
|
737
|
+
`${available.agentVersion} ${available.adapterVersion}`
|
|
738
|
+
)
|
|
739
|
+
);
|
|
740
|
+
}
|
|
741
|
+
for (const unavailable of diagnostics.unavailable) {
|
|
742
|
+
lines.push(
|
|
743
|
+
humanLine(unavailable.label, unavailable.status, unavailable.message)
|
|
744
|
+
);
|
|
745
|
+
if (unavailable.recoveryCommand.length > 0) {
|
|
746
|
+
lines.push(
|
|
747
|
+
unavailable.code === "authentication_required" ? ` Authenticate locally: ${unavailable.recoveryCommand}` : ` Install adapter: ${unavailable.recoveryCommand}`
|
|
748
|
+
);
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
return `${lines.join("\n")}
|
|
752
|
+
`;
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
// src/agent-installation/installation-grants.ts
|
|
756
|
+
import { open } from "node:fs/promises";
|
|
757
|
+
import { join as join2 } from "node:path";
|
|
758
|
+
var MAX_GRANT_FILE_LENGTH = 16 * 1024;
|
|
759
|
+
var AGENT_ID_PATTERN = /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/;
|
|
760
|
+
function isRecord(value) {
|
|
761
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
762
|
+
}
|
|
763
|
+
async function readGrantedAgents(stateDirectory) {
|
|
764
|
+
const path2 = join2(stateDirectory, "installation-grants.json");
|
|
765
|
+
let handle;
|
|
766
|
+
try {
|
|
767
|
+
handle = await open(path2, "r");
|
|
768
|
+
} catch (error61) {
|
|
769
|
+
if (error61 instanceof Error && "code" in error61 && error61.code === "ENOENT") {
|
|
770
|
+
return /* @__PURE__ */ new Set();
|
|
771
|
+
}
|
|
772
|
+
throw error61;
|
|
773
|
+
}
|
|
774
|
+
try {
|
|
775
|
+
const metadata = await handle.stat();
|
|
776
|
+
if (!metadata.isFile() || metadata.size > MAX_GRANT_FILE_LENGTH || typeof process.getuid === "function" && metadata.uid !== process.getuid() || process.platform !== "win32" && (metadata.mode & 63) !== 0) {
|
|
777
|
+
throw new Error("The local installation grant file is not private");
|
|
778
|
+
}
|
|
779
|
+
const encoded = await handle.readFile({ encoding: "utf8" });
|
|
780
|
+
const value = JSON.parse(encoded);
|
|
781
|
+
if (!isRecord(value) || Object.keys(value).length !== 1 || !Array.isArray(value["agents"])) {
|
|
782
|
+
throw new Error("The local installation grant file is invalid");
|
|
783
|
+
}
|
|
784
|
+
const agents = /* @__PURE__ */ new Set();
|
|
785
|
+
for (const candidate of value["agents"]) {
|
|
786
|
+
if (typeof candidate !== "string" || !AGENT_ID_PATTERN.test(candidate) || agents.has(candidate)) {
|
|
787
|
+
throw new Error("The local installation grant file is invalid");
|
|
788
|
+
}
|
|
789
|
+
agents.add(candidate);
|
|
790
|
+
}
|
|
791
|
+
return agents;
|
|
792
|
+
} finally {
|
|
793
|
+
await handle.close();
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
// src/storage/state-directory.ts
|
|
798
|
+
import { homedir } from "node:os";
|
|
799
|
+
import { join as join3, resolve as resolve2 } from "node:path";
|
|
800
|
+
function readStateDirectory(environment = process.env) {
|
|
801
|
+
const configured = environment["MOBIUS_STATE_DIRECTORY"]?.trim();
|
|
802
|
+
if (configured !== void 0 && configured.length > 0) {
|
|
803
|
+
return resolve2(configured);
|
|
804
|
+
}
|
|
805
|
+
return join3(homedir(), ".mobius");
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
// src/agent-installation/managed-npm-package.ts
|
|
809
|
+
import {
|
|
810
|
+
mkdir,
|
|
811
|
+
mkdtemp,
|
|
812
|
+
open as open2,
|
|
813
|
+
realpath as realpath2,
|
|
814
|
+
rename,
|
|
815
|
+
rm,
|
|
816
|
+
stat as stat2
|
|
817
|
+
} from "node:fs/promises";
|
|
818
|
+
import { delimiter, dirname, isAbsolute, join as join4, relative, sep } from "node:path";
|
|
819
|
+
var INSTALL_TIMEOUT_MILLISECONDS = 5 * 60 * 1e3;
|
|
820
|
+
var PACKAGE_METADATA_LIMIT_BYTES = 64 * 1024;
|
|
821
|
+
var PACKAGE_LOCK_LIMIT_BYTES = 8 * 1024 * 1024;
|
|
822
|
+
var ManagedNpmPackageDefinition = class {
|
|
823
|
+
dependencyResolutionArguments = Object.freeze([]);
|
|
824
|
+
executableName;
|
|
825
|
+
includeOptionalDependencies = false;
|
|
826
|
+
packageName;
|
|
827
|
+
version;
|
|
828
|
+
verifyDependencyClosure = false;
|
|
829
|
+
constructor(packageName, version2, executableName) {
|
|
830
|
+
this.executableName = executableName;
|
|
831
|
+
this.packageName = packageName;
|
|
832
|
+
this.version = version2;
|
|
833
|
+
}
|
|
834
|
+
};
|
|
835
|
+
var SriManagedNpmPackageDefinition = class extends ManagedNpmPackageDefinition {
|
|
836
|
+
integrity;
|
|
837
|
+
tarballUrl;
|
|
838
|
+
constructor(packageName, version2, executableName, integrity, tarballUrl) {
|
|
839
|
+
super(packageName, version2, executableName);
|
|
840
|
+
this.integrity = integrity;
|
|
841
|
+
this.tarballUrl = tarballUrl;
|
|
842
|
+
}
|
|
843
|
+
};
|
|
844
|
+
var ManagedNpmPackageError = class extends Error {
|
|
845
|
+
code;
|
|
846
|
+
constructor(code, message, options = {}) {
|
|
847
|
+
super(message, options);
|
|
848
|
+
this.code = code;
|
|
849
|
+
this.name = "ManagedNpmPackageError";
|
|
850
|
+
}
|
|
851
|
+
};
|
|
852
|
+
function isRecord2(value) {
|
|
853
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
854
|
+
}
|
|
855
|
+
function packagePath(root, packageName) {
|
|
856
|
+
return join4(root, "node_modules", ...packageName.split("/"));
|
|
857
|
+
}
|
|
858
|
+
function isContainedPath(root, candidate) {
|
|
859
|
+
const difference = relative(root, candidate);
|
|
860
|
+
return difference.length > 0 && difference !== ".." && !difference.startsWith(`..${sep}`) && !isAbsolute(difference);
|
|
861
|
+
}
|
|
862
|
+
async function readJsonRecord(path2, maximumBytes) {
|
|
863
|
+
try {
|
|
864
|
+
const handle = await open2(path2, "r");
|
|
865
|
+
try {
|
|
866
|
+
const metadata = await handle.stat();
|
|
867
|
+
if (!metadata.isFile() || metadata.size > maximumBytes) {
|
|
868
|
+
throw new ManagedNpmPackageError(
|
|
869
|
+
"managed_package_verification_failed",
|
|
870
|
+
"The managed npm package metadata is invalid"
|
|
871
|
+
);
|
|
872
|
+
}
|
|
873
|
+
const value = JSON.parse(
|
|
874
|
+
await handle.readFile({ encoding: "utf8" })
|
|
875
|
+
);
|
|
876
|
+
if (!isRecord2(value)) {
|
|
877
|
+
throw new ManagedNpmPackageError(
|
|
878
|
+
"managed_package_verification_failed",
|
|
879
|
+
"The managed npm package metadata is invalid"
|
|
880
|
+
);
|
|
881
|
+
}
|
|
882
|
+
return value;
|
|
883
|
+
} finally {
|
|
884
|
+
await handle.close();
|
|
885
|
+
}
|
|
886
|
+
} catch (error61) {
|
|
887
|
+
if (error61 instanceof ManagedNpmPackageError) {
|
|
888
|
+
throw error61;
|
|
889
|
+
}
|
|
890
|
+
throw new ManagedNpmPackageError(
|
|
891
|
+
"managed_package_verification_failed",
|
|
892
|
+
"The managed npm package metadata is invalid",
|
|
893
|
+
{ cause: error61 }
|
|
894
|
+
);
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
function readBinPath(packageMetadata, executableName) {
|
|
898
|
+
const bin = packageMetadata["bin"];
|
|
899
|
+
if (typeof bin === "string") {
|
|
900
|
+
return bin;
|
|
901
|
+
}
|
|
902
|
+
if (isRecord2(bin) && typeof bin[executableName] === "string") {
|
|
903
|
+
return bin[executableName];
|
|
904
|
+
}
|
|
905
|
+
throw new ManagedNpmPackageError(
|
|
906
|
+
"managed_package_verification_failed",
|
|
907
|
+
"The managed npm package executable declaration is invalid"
|
|
908
|
+
);
|
|
909
|
+
}
|
|
910
|
+
function verifyPackageLock(lock, definition) {
|
|
911
|
+
if (lock["lockfileVersion"] !== 3) {
|
|
912
|
+
throw new ManagedNpmPackageError(
|
|
913
|
+
"managed_package_verification_failed",
|
|
914
|
+
"The managed npm package lockfile is invalid"
|
|
915
|
+
);
|
|
916
|
+
}
|
|
917
|
+
const packages = lock["packages"];
|
|
918
|
+
if (!isRecord2(packages)) {
|
|
919
|
+
throw new ManagedNpmPackageError(
|
|
920
|
+
"managed_package_verification_failed",
|
|
921
|
+
"The managed npm package lockfile is invalid"
|
|
922
|
+
);
|
|
923
|
+
}
|
|
924
|
+
const suffix = `node_modules/${definition.packageName}`;
|
|
925
|
+
let entry;
|
|
926
|
+
let matches = 0;
|
|
927
|
+
for (const [key, candidate] of Object.entries(packages)) {
|
|
928
|
+
const normalizedKey = key.replaceAll("\\", "/");
|
|
929
|
+
if (definition.verifyDependencyClosure && normalizedKey.length > 0) {
|
|
930
|
+
let resolved;
|
|
931
|
+
try {
|
|
932
|
+
if (!normalizedKey.split("/").includes("node_modules") || !isRecord2(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") {
|
|
933
|
+
throw new Error("Invalid locked dependency");
|
|
934
|
+
}
|
|
935
|
+
resolved = new URL(candidate["resolved"]);
|
|
936
|
+
} catch (error61) {
|
|
937
|
+
throw new ManagedNpmPackageError(
|
|
938
|
+
"managed_package_verification_failed",
|
|
939
|
+
"The managed npm dependency closure is invalid",
|
|
940
|
+
{ cause: error61 }
|
|
941
|
+
);
|
|
942
|
+
}
|
|
943
|
+
if (resolved.protocol !== "https:" || resolved.hostname !== "registry.npmjs.org" || resolved.port.length > 0 || resolved.username.length > 0 || resolved.password.length > 0) {
|
|
944
|
+
throw new ManagedNpmPackageError(
|
|
945
|
+
"managed_package_verification_failed",
|
|
946
|
+
"The managed npm dependency closure is invalid"
|
|
947
|
+
);
|
|
948
|
+
}
|
|
949
|
+
}
|
|
950
|
+
if (normalizedKey === suffix || normalizedKey.endsWith(`/${suffix}`)) {
|
|
951
|
+
entry = candidate;
|
|
952
|
+
matches += 1;
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
if (matches !== 1 || !isRecord2(entry) || entry["integrity"] !== definition.integrity || entry["resolved"] !== definition.tarballUrl || entry["version"] !== definition.version) {
|
|
956
|
+
throw new ManagedNpmPackageError(
|
|
957
|
+
"managed_package_verification_failed",
|
|
958
|
+
"The managed npm package lockfile does not match the pinned artifact"
|
|
959
|
+
);
|
|
960
|
+
}
|
|
961
|
+
}
|
|
962
|
+
async function validateManagedNpmPackage(root, definition) {
|
|
963
|
+
try {
|
|
964
|
+
return await validateManagedNpmPackageContents(root, definition);
|
|
965
|
+
} catch (error61) {
|
|
966
|
+
if (error61 instanceof ManagedNpmPackageError) {
|
|
967
|
+
throw error61;
|
|
968
|
+
}
|
|
969
|
+
throw new ManagedNpmPackageError(
|
|
970
|
+
"managed_package_verification_failed",
|
|
971
|
+
"The managed npm package is invalid",
|
|
972
|
+
{ cause: error61 }
|
|
973
|
+
);
|
|
974
|
+
}
|
|
975
|
+
}
|
|
976
|
+
async function validateManagedNpmPackageContents(root, definition) {
|
|
977
|
+
const rootPath = await realpath2(root);
|
|
978
|
+
const packageRoot = await realpath2(
|
|
979
|
+
packagePath(rootPath, definition.packageName)
|
|
980
|
+
);
|
|
981
|
+
if (!isContainedPath(rootPath, packageRoot)) {
|
|
982
|
+
throw new ManagedNpmPackageError(
|
|
983
|
+
"managed_package_verification_failed",
|
|
984
|
+
"The managed npm package escaped its private cache"
|
|
985
|
+
);
|
|
986
|
+
}
|
|
987
|
+
const metadata = await readJsonRecord(
|
|
988
|
+
join4(packageRoot, "package.json"),
|
|
989
|
+
PACKAGE_METADATA_LIMIT_BYTES
|
|
990
|
+
);
|
|
991
|
+
if (metadata["name"] !== definition.packageName || metadata["version"] !== definition.version) {
|
|
992
|
+
throw new ManagedNpmPackageError(
|
|
993
|
+
"managed_package_verification_failed",
|
|
994
|
+
"The managed npm package identity is invalid"
|
|
995
|
+
);
|
|
996
|
+
}
|
|
997
|
+
if (definition instanceof SriManagedNpmPackageDefinition) {
|
|
998
|
+
verifyPackageLock(
|
|
999
|
+
await readJsonRecord(
|
|
1000
|
+
join4(rootPath, "package-lock.json"),
|
|
1001
|
+
PACKAGE_LOCK_LIMIT_BYTES
|
|
1002
|
+
),
|
|
1003
|
+
definition
|
|
1004
|
+
);
|
|
1005
|
+
}
|
|
1006
|
+
const declaredBin = readBinPath(metadata, definition.executableName);
|
|
1007
|
+
const executable = await resolveExecutablePath(
|
|
1008
|
+
join4(packageRoot, declaredBin)
|
|
1009
|
+
);
|
|
1010
|
+
if (executable === null || !isContainedPath(rootPath, executable.path)) {
|
|
1011
|
+
throw new ManagedNpmPackageError(
|
|
1012
|
+
"managed_package_verification_failed",
|
|
1013
|
+
"The managed npm package executable is invalid"
|
|
1014
|
+
);
|
|
1015
|
+
}
|
|
1016
|
+
return executable;
|
|
1017
|
+
}
|
|
1018
|
+
var ManagedNpmPackageInstaller = class {
|
|
1019
|
+
install = async (root, definition, environment, signal) => {
|
|
1020
|
+
signal.throwIfAborted();
|
|
1021
|
+
try {
|
|
1022
|
+
const metadata = await stat2(root);
|
|
1023
|
+
if (metadata.isDirectory()) {
|
|
1024
|
+
return await validateManagedNpmPackage(root, definition);
|
|
1025
|
+
}
|
|
1026
|
+
} catch (error61) {
|
|
1027
|
+
if (!(error61 instanceof Error) || !("code" in error61) || error61.code !== "ENOENT") {
|
|
1028
|
+
throw error61;
|
|
1029
|
+
}
|
|
1030
|
+
}
|
|
1031
|
+
const parent = dirname(root);
|
|
1032
|
+
await mkdir(parent, { mode: 448, recursive: true });
|
|
1033
|
+
const staging = await mkdtemp(
|
|
1034
|
+
join4(parent, `.${definition.version}.staging-`)
|
|
1035
|
+
);
|
|
1036
|
+
try {
|
|
1037
|
+
const npm = await findExecutableOnPath(
|
|
1038
|
+
process.platform === "win32" ? "npm.cmd" : "npm",
|
|
1039
|
+
environment
|
|
1040
|
+
);
|
|
1041
|
+
if (npm === null) {
|
|
1042
|
+
throw new ManagedNpmPackageError(
|
|
1043
|
+
"package_manager_not_found",
|
|
1044
|
+
"A supported npm executable is required to install the managed package"
|
|
1045
|
+
);
|
|
1046
|
+
}
|
|
1047
|
+
const installArguments = ["install", "--prefix", staging];
|
|
1048
|
+
installArguments.push(...definition.dependencyResolutionArguments);
|
|
1049
|
+
if (definition.includeOptionalDependencies) {
|
|
1050
|
+
installArguments.push("--include=optional");
|
|
1051
|
+
} else {
|
|
1052
|
+
installArguments.push("--omit=optional");
|
|
1053
|
+
}
|
|
1054
|
+
installArguments.push(
|
|
1055
|
+
"--ignore-scripts",
|
|
1056
|
+
"--no-audit",
|
|
1057
|
+
"--no-fund",
|
|
1058
|
+
"--package-lock=true",
|
|
1059
|
+
"--save-exact",
|
|
1060
|
+
"--registry=https://registry.npmjs.org/",
|
|
1061
|
+
`${definition.packageName}@${definition.version}`
|
|
1062
|
+
);
|
|
1063
|
+
const installEnvironment = {
|
|
1064
|
+
HOME: join4(staging, "home"),
|
|
1065
|
+
NPM_CONFIG_AUDIT: "false",
|
|
1066
|
+
NPM_CONFIG_CACHE: join4(staging, ".npm-cache"),
|
|
1067
|
+
NPM_CONFIG_FUND: "false",
|
|
1068
|
+
NPM_CONFIG_IGNORE_SCRIPTS: "true",
|
|
1069
|
+
NPM_CONFIG_PACKAGE_LOCK: "true",
|
|
1070
|
+
NPM_CONFIG_REGISTRY: "https://registry.npmjs.org/",
|
|
1071
|
+
PATH: `${dirname(process.execPath)}${delimiter}/usr/bin${delimiter}/bin`
|
|
1072
|
+
};
|
|
1073
|
+
if (definition.includeOptionalDependencies) {
|
|
1074
|
+
installEnvironment["NPM_CONFIG_INCLUDE"] = "optional";
|
|
1075
|
+
} else {
|
|
1076
|
+
installEnvironment["NPM_CONFIG_OMIT"] = "optional";
|
|
1077
|
+
}
|
|
1078
|
+
await runBoundedProcess({
|
|
1079
|
+
arguments: installArguments,
|
|
1080
|
+
command: npm.path,
|
|
1081
|
+
cwd: staging,
|
|
1082
|
+
environment: installEnvironment,
|
|
1083
|
+
outputLimitBytes: 64 * 1024,
|
|
1084
|
+
signal,
|
|
1085
|
+
timeoutMilliseconds: INSTALL_TIMEOUT_MILLISECONDS
|
|
1086
|
+
});
|
|
1087
|
+
await Promise.all([
|
|
1088
|
+
rm(join4(staging, ".npm-cache"), { force: true, recursive: true }),
|
|
1089
|
+
rm(join4(staging, "home"), { force: true, recursive: true })
|
|
1090
|
+
]);
|
|
1091
|
+
await validateManagedNpmPackage(staging, definition);
|
|
1092
|
+
try {
|
|
1093
|
+
await rename(staging, root);
|
|
1094
|
+
} catch (error61) {
|
|
1095
|
+
try {
|
|
1096
|
+
return await validateManagedNpmPackage(root, definition);
|
|
1097
|
+
} catch {
|
|
1098
|
+
throw new ManagedNpmPackageError(
|
|
1099
|
+
"managed_package_publish_failed",
|
|
1100
|
+
"The managed npm package could not be published",
|
|
1101
|
+
{ cause: error61 }
|
|
1102
|
+
);
|
|
1103
|
+
}
|
|
1104
|
+
}
|
|
1105
|
+
return await validateManagedNpmPackage(root, definition);
|
|
1106
|
+
} catch (error61) {
|
|
1107
|
+
if (signal.aborted) {
|
|
1108
|
+
signal.throwIfAborted();
|
|
1109
|
+
}
|
|
1110
|
+
if (error61 instanceof ManagedNpmPackageError) {
|
|
1111
|
+
throw error61;
|
|
1112
|
+
}
|
|
1113
|
+
throw new ManagedNpmPackageError(
|
|
1114
|
+
"managed_package_install_failed",
|
|
1115
|
+
"The pinned npm package could not be installed",
|
|
1116
|
+
{ cause: error61 }
|
|
1117
|
+
);
|
|
1118
|
+
} finally {
|
|
1119
|
+
await rm(staging, { force: true, recursive: true });
|
|
1120
|
+
}
|
|
1121
|
+
};
|
|
1122
|
+
};
|
|
1123
|
+
|
|
1124
|
+
// src/agent-catalog/agent-specification.ts
|
|
1125
|
+
import { join as join5 } from "node:path";
|
|
1126
|
+
var VERSION_PROBE_TIMEOUT_MILLISECONDS = 3e3;
|
|
1127
|
+
var ACP_PROBE_TIMEOUT_MILLISECONDS = 5e3;
|
|
1128
|
+
var DEFAULT_PROMPT_TIMEOUT_MILLISECONDS = 30 * 60 * 1e3;
|
|
1129
|
+
var LocalAgentSpecification = class {
|
|
1130
|
+
acpProbeTimeoutMilliseconds = ACP_PROBE_TIMEOUT_MILLISECONDS;
|
|
1131
|
+
authenticationCommand = () => "";
|
|
1132
|
+
adapterVersionArguments = ["--version"];
|
|
1133
|
+
agentVersionArguments = ["--version"];
|
|
1134
|
+
promptTimeoutMilliseconds = DEFAULT_PROMPT_TIMEOUT_MILLISECONDS;
|
|
1135
|
+
versionProbeTimeoutMilliseconds = VERSION_PROBE_TIMEOUT_MILLISECONDS;
|
|
1136
|
+
resolveManagedAgent = async (stateDirectory, platform, signal) => {
|
|
1137
|
+
signal.throwIfAborted();
|
|
1138
|
+
const executable = await resolveExecutablePath(
|
|
1139
|
+
join5(stateDirectory, ...this.managedAgentExecutablePath),
|
|
1140
|
+
platform
|
|
1141
|
+
);
|
|
1142
|
+
signal.throwIfAborted();
|
|
1143
|
+
if (executable === null) {
|
|
1144
|
+
throw new Error("The managed Agent executable is unavailable");
|
|
1145
|
+
}
|
|
1146
|
+
return executable;
|
|
1147
|
+
};
|
|
1148
|
+
createLaunchEnvironment = async (_agent, _context) => Object.freeze({});
|
|
1149
|
+
recoveryCommand = () => "";
|
|
1150
|
+
supportsInstallation = (platform, architecture) => (platform === "darwin" || platform === "linux") && (architecture === "arm64" || architecture === "x64");
|
|
1151
|
+
verifyAcp = (_connection, _initialized, _defaultWorkspace, _signal) => Promise.resolve();
|
|
1152
|
+
};
|
|
1153
|
+
var DirectAcpAgentDefinition = class extends LocalAgentSpecification {
|
|
1154
|
+
adapterOverrideVariable;
|
|
1155
|
+
agentOverrideVariable;
|
|
1156
|
+
launchArguments;
|
|
1157
|
+
managedAdapterExecutablePath;
|
|
1158
|
+
managedAgentExecutablePath;
|
|
1159
|
+
constructor(executableOverrideVariable, launchArguments, managedExecutablePath) {
|
|
1160
|
+
super();
|
|
1161
|
+
this.adapterOverrideVariable = executableOverrideVariable;
|
|
1162
|
+
this.agentOverrideVariable = executableOverrideVariable;
|
|
1163
|
+
this.launchArguments = Object.freeze([...launchArguments]);
|
|
1164
|
+
this.managedAdapterExecutablePath = Object.freeze([
|
|
1165
|
+
...managedExecutablePath
|
|
1166
|
+
]);
|
|
1167
|
+
this.managedAgentExecutablePath = this.managedAdapterExecutablePath;
|
|
1168
|
+
}
|
|
1169
|
+
};
|
|
1170
|
+
var BridgedAcpAgentDefinition = class extends LocalAgentSpecification {
|
|
1171
|
+
launchArguments = Object.freeze([]);
|
|
1172
|
+
get adapterExecutable() {
|
|
1173
|
+
return this.adapterPackageDefinition.executableName;
|
|
1174
|
+
}
|
|
1175
|
+
get adapterPackage() {
|
|
1176
|
+
return this.adapterPackageDefinition.packageName;
|
|
1177
|
+
}
|
|
1178
|
+
get adapterVersion() {
|
|
1179
|
+
return this.adapterPackageDefinition.version;
|
|
1180
|
+
}
|
|
1181
|
+
createLaunchEnvironment = async (agent, _context) => Object.freeze({ [this.adapterEnvironmentVariable]: agent.path });
|
|
1182
|
+
recoveryCommand = () => `npm install -g --omit=optional ${this.adapterPackage}@${this.adapterVersion}`;
|
|
1183
|
+
};
|
|
1184
|
+
|
|
1185
|
+
// src/agent-catalog/agents/claude-code-agent.ts
|
|
1186
|
+
var ClaudeCodeAgentSpecification = class extends BridgedAcpAgentDefinition {
|
|
1187
|
+
adapterEnvironmentVariable = "CLAUDE_CODE_EXECUTABLE";
|
|
1188
|
+
adapterOverrideVariable = "MOBIUS_CLAUDE_ACP_PATH";
|
|
1189
|
+
adapterPackageDefinition = new ManagedNpmPackageDefinition(
|
|
1190
|
+
"@agentclientprotocol/claude-agent-acp",
|
|
1191
|
+
"0.73.0",
|
|
1192
|
+
"claude-agent-acp"
|
|
1193
|
+
);
|
|
1194
|
+
agentExecutable = "claude";
|
|
1195
|
+
agentOverrideVariable = "MOBIUS_CLAUDE_PATH";
|
|
1196
|
+
id = "claude";
|
|
1197
|
+
label = "Claude Code";
|
|
1198
|
+
managedAdapterExecutablePath = [
|
|
1199
|
+
"adapters",
|
|
1200
|
+
"claude",
|
|
1201
|
+
"0.73.0",
|
|
1202
|
+
"node_modules",
|
|
1203
|
+
"@agentclientprotocol",
|
|
1204
|
+
"claude-agent-acp",
|
|
1205
|
+
"dist",
|
|
1206
|
+
"index.js"
|
|
1207
|
+
];
|
|
1208
|
+
managedAgentExecutablePath = [
|
|
1209
|
+
"agents",
|
|
1210
|
+
"claude",
|
|
1211
|
+
"home",
|
|
1212
|
+
".local",
|
|
1213
|
+
"bin",
|
|
1214
|
+
"claude"
|
|
1215
|
+
];
|
|
1216
|
+
};
|
|
1217
|
+
|
|
1218
|
+
// src/agent-catalog/agents/codex-agent.ts
|
|
1219
|
+
var CodexAgentSpecification = class extends BridgedAcpAgentDefinition {
|
|
1220
|
+
adapterEnvironmentVariable = "CODEX_PATH";
|
|
1221
|
+
adapterOverrideVariable = "MOBIUS_CODEX_ACP_PATH";
|
|
1222
|
+
adapterPackageDefinition = new ManagedNpmPackageDefinition(
|
|
1223
|
+
"@agentclientprotocol/codex-acp",
|
|
1224
|
+
"1.8.0",
|
|
1225
|
+
"codex-acp"
|
|
1226
|
+
);
|
|
1227
|
+
agentExecutable = "codex";
|
|
1228
|
+
agentOverrideVariable = "MOBIUS_CODEX_PATH";
|
|
1229
|
+
id = "codex";
|
|
1230
|
+
label = "Codex";
|
|
1231
|
+
managedAdapterExecutablePath = [
|
|
1232
|
+
"adapters",
|
|
1233
|
+
"codex",
|
|
1234
|
+
"1.8.0",
|
|
1235
|
+
"node_modules",
|
|
1236
|
+
"@agentclientprotocol",
|
|
1237
|
+
"codex-acp",
|
|
1238
|
+
"dist",
|
|
1239
|
+
"index.js"
|
|
1240
|
+
];
|
|
1241
|
+
managedAgentExecutablePath = ["agents", "codex", "bin", "codex"];
|
|
1242
|
+
};
|
|
1243
|
+
|
|
1244
|
+
// src/agent-catalog/agents/deepseek-harness-agent.ts
|
|
1245
|
+
import { realpath as realpath3, stat as stat3 } from "node:fs/promises";
|
|
1246
|
+
import { isAbsolute as isAbsolute2, join as join6, normalize } from "node:path";
|
|
1247
|
+
|
|
1248
|
+
// src/agent-installation/deepseek-managed-package.ts
|
|
1249
|
+
var DeepSeekHarnessManagedPackage = class extends SriManagedNpmPackageDefinition {
|
|
1250
|
+
dependencyResolutionArguments = Object.freeze([
|
|
1251
|
+
"--before=2026-09-03T06:31:52.107Z"
|
|
1252
|
+
]);
|
|
1253
|
+
includeOptionalDependencies = true;
|
|
1254
|
+
verifyDependencyClosure = true;
|
|
1255
|
+
};
|
|
1256
|
+
var DEEPSEEK_HARNESS_PACKAGE = new DeepSeekHarnessManagedPackage(
|
|
1257
|
+
"@deepseek-ai/dsh",
|
|
1258
|
+
"0.1.2-rc.1",
|
|
1259
|
+
"dsh",
|
|
1260
|
+
"sha512-RPq48TzxvwpdT9/7W1tbhZDBMmeK+bxDrX9cqQC27Wx/LqtgJF8PSa3b3xriU8oxtvhwYmk21w2cej3uMQrnVA==",
|
|
1261
|
+
"https://registry.npmjs.org/@deepseek-ai/dsh/-/dsh-0.1.2-rc.1.tgz"
|
|
1262
|
+
);
|
|
1263
|
+
|
|
1264
|
+
// src/agent-catalog/agent-probe-error.ts
|
|
1265
|
+
var AgentProbeError = class extends Error {
|
|
1266
|
+
code;
|
|
1267
|
+
constructor(code, message, options = {}) {
|
|
1268
|
+
super(message, options);
|
|
1269
|
+
this.code = code;
|
|
1270
|
+
this.name = "AgentProbeError";
|
|
1271
|
+
}
|
|
1272
|
+
};
|
|
1273
|
+
|
|
1274
|
+
// src/agent-catalog/agents/deepseek-harness-agent.ts
|
|
1275
|
+
async function validateAgentHome(path2) {
|
|
1276
|
+
if (!isAbsolute2(path2) || normalize(path2) !== path2) {
|
|
1277
|
+
throw new AgentProbeError(
|
|
1278
|
+
"agent_environment_invalid",
|
|
1279
|
+
"The configured Agent home is invalid"
|
|
1280
|
+
);
|
|
1281
|
+
}
|
|
1282
|
+
try {
|
|
1283
|
+
const resolved = await realpath3(path2);
|
|
1284
|
+
const metadata = await stat3(resolved);
|
|
1285
|
+
if (!metadata.isDirectory() || typeof process.getuid === "function" && metadata.uid !== process.getuid()) {
|
|
1286
|
+
throw new Error("Agent home is not a user-owned directory");
|
|
1287
|
+
}
|
|
1288
|
+
return resolved;
|
|
496
1289
|
} catch (error61) {
|
|
497
|
-
if (error61 instanceof
|
|
1290
|
+
if (error61 instanceof AgentProbeError) {
|
|
498
1291
|
throw error61;
|
|
499
1292
|
}
|
|
500
|
-
throw new
|
|
501
|
-
"
|
|
502
|
-
"The
|
|
503
|
-
{ cause: error61 }
|
|
504
|
-
);
|
|
505
|
-
}
|
|
506
|
-
}
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
1293
|
+
throw new AgentProbeError(
|
|
1294
|
+
"agent_environment_invalid",
|
|
1295
|
+
"The configured Agent home is invalid",
|
|
1296
|
+
{ cause: error61 }
|
|
1297
|
+
);
|
|
1298
|
+
}
|
|
1299
|
+
}
|
|
1300
|
+
var DeepSeekHarnessAgentSpecification = class extends DirectAcpAgentDefinition {
|
|
1301
|
+
adapterVersion = DEEPSEEK_HARNESS_PACKAGE.version;
|
|
1302
|
+
authenticationCommand = () => "dsh web";
|
|
1303
|
+
agentExecutable = "dsh";
|
|
1304
|
+
id = "deepseek-harness";
|
|
1305
|
+
label = "DeepSeek Harness";
|
|
1306
|
+
constructor() {
|
|
1307
|
+
super(
|
|
1308
|
+
"MOBIUS_DEEPSEEK_HARNESS_PATH",
|
|
1309
|
+
["--profile", "acp"],
|
|
1310
|
+
[
|
|
1311
|
+
"agents",
|
|
1312
|
+
"deepseek-harness",
|
|
1313
|
+
DEEPSEEK_HARNESS_PACKAGE.version,
|
|
1314
|
+
"node_modules",
|
|
1315
|
+
"@deepseek-ai",
|
|
1316
|
+
"dsh",
|
|
1317
|
+
"lib",
|
|
1318
|
+
"bin.js"
|
|
1319
|
+
]
|
|
1320
|
+
);
|
|
1321
|
+
}
|
|
1322
|
+
createLaunchEnvironment = async (agent, context) => {
|
|
1323
|
+
let selectedHome = context.environment["DSH_HOME"];
|
|
1324
|
+
try {
|
|
1325
|
+
const managed = await this.resolveManagedAgent(
|
|
1326
|
+
readStateDirectory(context.environment),
|
|
1327
|
+
context.platform ?? process.platform,
|
|
1328
|
+
context.signal
|
|
1329
|
+
);
|
|
1330
|
+
if (managed.path === agent.path) {
|
|
1331
|
+
selectedHome = join6(
|
|
1332
|
+
readStateDirectory(context.environment),
|
|
1333
|
+
"agents",
|
|
1334
|
+
this.id,
|
|
1335
|
+
"home"
|
|
1336
|
+
);
|
|
1337
|
+
}
|
|
1338
|
+
} catch {
|
|
1339
|
+
context.signal.throwIfAborted();
|
|
1340
|
+
}
|
|
1341
|
+
if (selectedHome === void 0 || selectedHome.length === 0) {
|
|
1342
|
+
return Object.freeze({ DSH_PERMISSION_MODE: "workspace-write" });
|
|
1343
|
+
}
|
|
1344
|
+
return Object.freeze({
|
|
1345
|
+
DSH_HOME: await validateAgentHome(selectedHome),
|
|
1346
|
+
DSH_PERMISSION_MODE: "workspace-write"
|
|
1347
|
+
});
|
|
1348
|
+
};
|
|
1349
|
+
resolveManagedAgent = async (stateDirectory, _platform, signal) => {
|
|
1350
|
+
signal.throwIfAborted();
|
|
1351
|
+
const executable = await validateManagedNpmPackage(
|
|
1352
|
+
join6(stateDirectory, "agents", this.id, DEEPSEEK_HARNESS_PACKAGE.version),
|
|
1353
|
+
DEEPSEEK_HARNESS_PACKAGE
|
|
1354
|
+
);
|
|
1355
|
+
signal.throwIfAborted();
|
|
1356
|
+
return executable;
|
|
1357
|
+
};
|
|
1358
|
+
verifyAcp = (_connection, initialized, _defaultWorkspace, _signal) => {
|
|
1359
|
+
const capabilities = initialized.agentCapabilities ?? {};
|
|
1360
|
+
const session = capabilities.sessionCapabilities;
|
|
1361
|
+
const prompt = capabilities.promptCapabilities;
|
|
1362
|
+
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) {
|
|
1363
|
+
throw new AgentProbeError(
|
|
1364
|
+
"acp_incompatible",
|
|
1365
|
+
"DeepSeek Harness reported an unsupported ACP capability set"
|
|
1366
|
+
);
|
|
1367
|
+
}
|
|
1368
|
+
return Promise.resolve();
|
|
1369
|
+
};
|
|
1370
|
+
};
|
|
1371
|
+
|
|
1372
|
+
// src/agent-catalog/agents/opencode-agent.ts
|
|
1373
|
+
import { join as join8 } from "node:path";
|
|
1374
|
+
|
|
1375
|
+
// src/agent-installation/managed-agent-archive.ts
|
|
1376
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
1377
|
+
import { createReadStream } from "node:fs";
|
|
1378
|
+
import {
|
|
1379
|
+
chmod,
|
|
1380
|
+
copyFile,
|
|
1381
|
+
mkdir as mkdir2,
|
|
1382
|
+
mkdtemp as mkdtemp2,
|
|
1383
|
+
open as open4,
|
|
1384
|
+
realpath as realpath4,
|
|
1385
|
+
rename as rename2,
|
|
1386
|
+
rm as rm2,
|
|
1387
|
+
stat as stat4,
|
|
1388
|
+
writeFile
|
|
1389
|
+
} from "node:fs/promises";
|
|
1390
|
+
import { dirname as dirname2, isAbsolute as isAbsolute3, join as join7, relative as relative2, sep as sep2 } from "node:path";
|
|
1391
|
+
|
|
1392
|
+
// src/agent-installation/verified-download.ts
|
|
1393
|
+
import { createHash } from "node:crypto";
|
|
1394
|
+
import { open as open3, unlink } from "node:fs/promises";
|
|
1395
|
+
import { fetch } from "undici";
|
|
1396
|
+
|
|
1397
|
+
// src/network/environment-proxy.ts
|
|
1398
|
+
import { EnvHttpProxyAgent } from "undici";
|
|
1399
|
+
var environmentProxyDispatcher = new EnvHttpProxyAgent();
|
|
1400
|
+
|
|
1401
|
+
// src/agent-installation/verified-download.ts
|
|
1402
|
+
var MAX_REDIRECTS = 4;
|
|
1403
|
+
var REDIRECT_STATUSES = /* @__PURE__ */ new Set([301, 302, 303, 307, 308]);
|
|
1404
|
+
var InstallerDownloadError = class extends Error {
|
|
1405
|
+
code;
|
|
1406
|
+
constructor(code, message, options = {}) {
|
|
1407
|
+
super(message, options);
|
|
1408
|
+
this.code = code;
|
|
1409
|
+
this.name = "InstallerDownloadError";
|
|
1410
|
+
}
|
|
1411
|
+
};
|
|
1412
|
+
var VerifiedDownload = class {
|
|
1413
|
+
bytes;
|
|
1414
|
+
sha256;
|
|
1415
|
+
url;
|
|
1416
|
+
constructor(url2, bytes, sha256) {
|
|
1417
|
+
this.bytes = bytes;
|
|
1418
|
+
this.sha256 = sha256;
|
|
1419
|
+
this.url = url2;
|
|
1420
|
+
}
|
|
1421
|
+
};
|
|
1422
|
+
var UndiciInstallerDownloadTransport = class {
|
|
1423
|
+
get = async (url2, signal) => await fetch(url2, {
|
|
1424
|
+
dispatcher: environmentProxyDispatcher,
|
|
1425
|
+
headers: {
|
|
1426
|
+
accept: "text/plain, application/octet-stream;q=0.9",
|
|
1427
|
+
"user-agent": "Mobius-Agent-Installer/0.0.3"
|
|
1428
|
+
},
|
|
1429
|
+
method: "GET",
|
|
1430
|
+
redirect: "manual",
|
|
1431
|
+
signal
|
|
1432
|
+
});
|
|
1433
|
+
};
|
|
1434
|
+
function validateUrl(url2, allowedHosts) {
|
|
1435
|
+
if (url2.protocol !== "https:" || url2.username.length > 0 || url2.password.length > 0 || url2.port.length > 0 || !allowedHosts.has(url2.hostname)) {
|
|
1436
|
+
throw new InstallerDownloadError(
|
|
1437
|
+
"installer_host_not_allowed",
|
|
1438
|
+
"The installer download target is not allowed"
|
|
1439
|
+
);
|
|
1440
|
+
}
|
|
1441
|
+
}
|
|
1442
|
+
async function fetchInstaller(options, signal, transport) {
|
|
1443
|
+
let url2 = new URL(options.url);
|
|
1444
|
+
for (let redirectCount = 0; redirectCount <= MAX_REDIRECTS; redirectCount += 1) {
|
|
1445
|
+
validateUrl(url2, options.allowedHosts);
|
|
1446
|
+
const response = await transport.get(url2, signal);
|
|
1447
|
+
if (!REDIRECT_STATUSES.has(response.status)) {
|
|
1448
|
+
return { response, url: url2 };
|
|
1449
|
+
}
|
|
1450
|
+
await response.body?.cancel();
|
|
1451
|
+
const location = response.headers.get("location");
|
|
1452
|
+
if (location === null || redirectCount === MAX_REDIRECTS) {
|
|
1453
|
+
throw new InstallerDownloadError(
|
|
1454
|
+
"installer_redirect_invalid",
|
|
1455
|
+
"The installer returned an invalid redirect"
|
|
1456
|
+
);
|
|
1457
|
+
}
|
|
1458
|
+
let redirected;
|
|
1459
|
+
try {
|
|
1460
|
+
redirected = new URL(location, url2);
|
|
1461
|
+
} catch (error61) {
|
|
1462
|
+
throw new InstallerDownloadError(
|
|
1463
|
+
"installer_redirect_invalid",
|
|
1464
|
+
"The installer returned an invalid redirect",
|
|
1465
|
+
{ cause: error61 }
|
|
1466
|
+
);
|
|
1467
|
+
}
|
|
1468
|
+
try {
|
|
1469
|
+
validateUrl(redirected, options.allowedHosts);
|
|
1470
|
+
} catch (error61) {
|
|
1471
|
+
throw new InstallerDownloadError(
|
|
1472
|
+
"installer_redirect_not_allowed",
|
|
1473
|
+
"The installer redirect left the approved host allowlist",
|
|
1474
|
+
{ cause: error61 }
|
|
1475
|
+
);
|
|
1476
|
+
}
|
|
1477
|
+
url2 = redirected;
|
|
514
1478
|
}
|
|
515
|
-
throw new
|
|
516
|
-
"
|
|
517
|
-
"The
|
|
1479
|
+
throw new InstallerDownloadError(
|
|
1480
|
+
"installer_redirect_invalid",
|
|
1481
|
+
"The installer returned too many redirects"
|
|
518
1482
|
);
|
|
519
1483
|
}
|
|
520
|
-
function
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
const packages = lock["packages"];
|
|
528
|
-
if (!isRecord2(packages)) {
|
|
529
|
-
throw new ManagedNpmPackageError(
|
|
530
|
-
"managed_package_verification_failed",
|
|
531
|
-
"The managed npm package lockfile is invalid"
|
|
1484
|
+
async function writeCompleteChunk(handle, chunk) {
|
|
1485
|
+
let offset = 0;
|
|
1486
|
+
while (offset < chunk.byteLength) {
|
|
1487
|
+
const written = await handle.write(
|
|
1488
|
+
chunk,
|
|
1489
|
+
offset,
|
|
1490
|
+
chunk.byteLength - offset
|
|
532
1491
|
);
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
const normalizedKey = key.replaceAll("\\", "/");
|
|
539
|
-
if (normalizedKey === suffix || normalizedKey.endsWith(`/${suffix}`)) {
|
|
540
|
-
entry = candidate;
|
|
541
|
-
matches += 1;
|
|
1492
|
+
if (written.bytesWritten < 1) {
|
|
1493
|
+
throw new InstallerDownloadError(
|
|
1494
|
+
"installer_write_failed",
|
|
1495
|
+
"The verified installer could not be stored"
|
|
1496
|
+
);
|
|
542
1497
|
}
|
|
543
|
-
|
|
544
|
-
if (matches !== 1 || !isRecord2(entry) || entry["integrity"] !== definition.integrity || entry["resolved"] !== definition.tarballUrl || entry["version"] !== definition.version) {
|
|
545
|
-
throw new ManagedNpmPackageError(
|
|
546
|
-
"managed_package_verification_failed",
|
|
547
|
-
"The managed npm package lockfile does not match the pinned artifact"
|
|
548
|
-
);
|
|
1498
|
+
offset += written.bytesWritten;
|
|
549
1499
|
}
|
|
550
1500
|
}
|
|
551
|
-
async function
|
|
1501
|
+
async function downloadVerifiedFile(options, transport = new UndiciInstallerDownloadTransport()) {
|
|
1502
|
+
options.signal.throwIfAborted();
|
|
1503
|
+
const timeoutSignal = AbortSignal.timeout(options.timeoutMilliseconds);
|
|
1504
|
+
const signal = AbortSignal.any([options.signal, timeoutSignal]);
|
|
1505
|
+
let handle = null;
|
|
1506
|
+
let responseBody = null;
|
|
552
1507
|
try {
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
if (
|
|
556
|
-
throw
|
|
1508
|
+
const fetched = await fetchInstaller(options, signal, transport);
|
|
1509
|
+
responseBody = fetched.response.body;
|
|
1510
|
+
if (!fetched.response.ok || fetched.response.body === null) {
|
|
1511
|
+
throw new InstallerDownloadError(
|
|
1512
|
+
"installer_download_failed",
|
|
1513
|
+
"The approved installer could not be downloaded"
|
|
1514
|
+
);
|
|
557
1515
|
}
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
const rootPath = await realpath2(root);
|
|
567
|
-
const packageRoot = await realpath2(
|
|
568
|
-
packagePath(rootPath, definition.packageName)
|
|
569
|
-
);
|
|
570
|
-
if (!isContainedPath(rootPath, packageRoot)) {
|
|
571
|
-
throw new ManagedNpmPackageError(
|
|
572
|
-
"managed_package_verification_failed",
|
|
573
|
-
"The managed npm package escaped its private cache"
|
|
574
|
-
);
|
|
575
|
-
}
|
|
576
|
-
const metadata = await readJsonRecord(
|
|
577
|
-
join3(packageRoot, "package.json"),
|
|
578
|
-
PACKAGE_METADATA_LIMIT_BYTES
|
|
579
|
-
);
|
|
580
|
-
if (metadata["name"] !== definition.packageName || metadata["version"] !== definition.version) {
|
|
581
|
-
throw new ManagedNpmPackageError(
|
|
582
|
-
"managed_package_verification_failed",
|
|
583
|
-
"The managed npm package identity is invalid"
|
|
584
|
-
);
|
|
585
|
-
}
|
|
586
|
-
if (definition instanceof SriManagedNpmPackageDefinition) {
|
|
587
|
-
verifyPackageLock(
|
|
588
|
-
await readJsonRecord(
|
|
589
|
-
join3(rootPath, "package-lock.json"),
|
|
590
|
-
PACKAGE_LOCK_LIMIT_BYTES
|
|
591
|
-
),
|
|
592
|
-
definition
|
|
593
|
-
);
|
|
594
|
-
}
|
|
595
|
-
const declaredBin = readBinPath(metadata, definition.executableName);
|
|
596
|
-
const executable = await resolveExecutablePath(
|
|
597
|
-
join3(packageRoot, declaredBin)
|
|
598
|
-
);
|
|
599
|
-
if (executable === null || !isContainedPath(rootPath, executable.path)) {
|
|
600
|
-
throw new ManagedNpmPackageError(
|
|
601
|
-
"managed_package_verification_failed",
|
|
602
|
-
"The managed npm package executable is invalid"
|
|
603
|
-
);
|
|
604
|
-
}
|
|
605
|
-
return executable;
|
|
606
|
-
}
|
|
607
|
-
var ManagedNpmPackageInstaller = class {
|
|
608
|
-
install = async (root, definition, environment, signal) => {
|
|
609
|
-
signal.throwIfAborted();
|
|
610
|
-
try {
|
|
611
|
-
const metadata = await stat2(root);
|
|
612
|
-
if (metadata.isDirectory()) {
|
|
613
|
-
return await validateManagedNpmPackage(root, definition);
|
|
614
|
-
}
|
|
615
|
-
} catch (error61) {
|
|
616
|
-
if (!(error61 instanceof Error) || !("code" in error61) || error61.code !== "ENOENT") {
|
|
617
|
-
throw error61;
|
|
1516
|
+
const contentLength = fetched.response.headers.get("content-length");
|
|
1517
|
+
if (contentLength !== null) {
|
|
1518
|
+
const declaredLength = Number(contentLength);
|
|
1519
|
+
if (!Number.isSafeInteger(declaredLength) || declaredLength < 1 || declaredLength > options.maximumBytes) {
|
|
1520
|
+
throw new InstallerDownloadError(
|
|
1521
|
+
"installer_size_invalid",
|
|
1522
|
+
"The installer size is outside the approved limit"
|
|
1523
|
+
);
|
|
618
1524
|
}
|
|
619
1525
|
}
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
const
|
|
623
|
-
|
|
624
|
-
);
|
|
1526
|
+
handle = await open3(options.destination, "wx", 384);
|
|
1527
|
+
const digest = createHash("sha256");
|
|
1528
|
+
const reader = fetched.response.body.getReader();
|
|
1529
|
+
let bytes = 0;
|
|
625
1530
|
try {
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
arguments: [
|
|
638
|
-
"install",
|
|
639
|
-
"--prefix",
|
|
640
|
-
staging,
|
|
641
|
-
"--omit=optional",
|
|
642
|
-
"--ignore-scripts",
|
|
643
|
-
"--no-audit",
|
|
644
|
-
"--no-fund",
|
|
645
|
-
"--package-lock=true",
|
|
646
|
-
"--save-exact",
|
|
647
|
-
"--registry=https://registry.npmjs.org/",
|
|
648
|
-
`${definition.packageName}@${definition.version}`
|
|
649
|
-
],
|
|
650
|
-
command: npm.path,
|
|
651
|
-
cwd: staging,
|
|
652
|
-
environment: {
|
|
653
|
-
HOME: join3(staging, "home"),
|
|
654
|
-
NPM_CONFIG_AUDIT: "false",
|
|
655
|
-
NPM_CONFIG_CACHE: join3(staging, ".npm-cache"),
|
|
656
|
-
NPM_CONFIG_FUND: "false",
|
|
657
|
-
NPM_CONFIG_IGNORE_SCRIPTS: "true",
|
|
658
|
-
NPM_CONFIG_OMIT: "optional",
|
|
659
|
-
NPM_CONFIG_PACKAGE_LOCK: "true",
|
|
660
|
-
NPM_CONFIG_REGISTRY: "https://registry.npmjs.org/",
|
|
661
|
-
PATH: `${dirname(process.execPath)}${delimiter}/usr/bin${delimiter}/bin`
|
|
662
|
-
},
|
|
663
|
-
outputLimitBytes: 64 * 1024,
|
|
664
|
-
signal,
|
|
665
|
-
timeoutMilliseconds: INSTALL_TIMEOUT_MILLISECONDS
|
|
666
|
-
});
|
|
667
|
-
await Promise.all([
|
|
668
|
-
rm(join3(staging, ".npm-cache"), { force: true, recursive: true }),
|
|
669
|
-
rm(join3(staging, "home"), { force: true, recursive: true })
|
|
670
|
-
]);
|
|
671
|
-
await validateManagedNpmPackage(staging, definition);
|
|
672
|
-
try {
|
|
673
|
-
await rename(staging, root);
|
|
674
|
-
} catch (error61) {
|
|
675
|
-
try {
|
|
676
|
-
return await validateManagedNpmPackage(root, definition);
|
|
677
|
-
} catch {
|
|
678
|
-
throw new ManagedNpmPackageError(
|
|
679
|
-
"managed_package_publish_failed",
|
|
680
|
-
"The managed npm package could not be published",
|
|
681
|
-
{ cause: error61 }
|
|
1531
|
+
while (true) {
|
|
1532
|
+
signal.throwIfAborted();
|
|
1533
|
+
const chunk = await reader.read();
|
|
1534
|
+
if (chunk.done) {
|
|
1535
|
+
break;
|
|
1536
|
+
}
|
|
1537
|
+
bytes += chunk.value.byteLength;
|
|
1538
|
+
if (bytes > options.maximumBytes) {
|
|
1539
|
+
throw new InstallerDownloadError(
|
|
1540
|
+
"installer_size_invalid",
|
|
1541
|
+
"The installer exceeded the approved size limit"
|
|
682
1542
|
);
|
|
683
1543
|
}
|
|
1544
|
+
digest.update(chunk.value);
|
|
1545
|
+
await writeCompleteChunk(handle, chunk.value);
|
|
684
1546
|
}
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
1547
|
+
} finally {
|
|
1548
|
+
await reader.cancel().catch(() => void 0);
|
|
1549
|
+
reader.releaseLock();
|
|
1550
|
+
}
|
|
1551
|
+
if (bytes === 0) {
|
|
1552
|
+
throw new InstallerDownloadError(
|
|
1553
|
+
"installer_verification_failed",
|
|
1554
|
+
"The downloaded installer is empty"
|
|
1555
|
+
);
|
|
1556
|
+
}
|
|
1557
|
+
await handle.sync();
|
|
1558
|
+
await handle.close();
|
|
1559
|
+
handle = null;
|
|
1560
|
+
return new VerifiedDownload(fetched.url, bytes, digest.digest("hex"));
|
|
1561
|
+
} catch (error61) {
|
|
1562
|
+
if (handle !== null) {
|
|
1563
|
+
await handle.close().catch(() => void 0);
|
|
1564
|
+
}
|
|
1565
|
+
await unlink(options.destination).catch(() => void 0);
|
|
1566
|
+
if (options.signal.aborted) {
|
|
1567
|
+
options.signal.throwIfAborted();
|
|
1568
|
+
}
|
|
1569
|
+
if (timeoutSignal.aborted) {
|
|
1570
|
+
throw new InstallerDownloadError(
|
|
1571
|
+
"installer_download_timeout",
|
|
1572
|
+
"The installer download timed out",
|
|
696
1573
|
{ cause: error61 }
|
|
697
1574
|
);
|
|
698
|
-
} finally {
|
|
699
|
-
await rm(staging, { force: true, recursive: true });
|
|
700
1575
|
}
|
|
701
|
-
|
|
1576
|
+
if (error61 instanceof InstallerDownloadError) {
|
|
1577
|
+
throw error61;
|
|
1578
|
+
}
|
|
1579
|
+
throw new InstallerDownloadError(
|
|
1580
|
+
"installer_download_failed",
|
|
1581
|
+
"The approved installer could not be downloaded",
|
|
1582
|
+
{ cause: error61 }
|
|
1583
|
+
);
|
|
1584
|
+
} finally {
|
|
1585
|
+
await responseBody?.cancel().catch(() => void 0);
|
|
1586
|
+
}
|
|
1587
|
+
}
|
|
1588
|
+
|
|
1589
|
+
// src/agent-installation/managed-agent-archive.ts
|
|
1590
|
+
var ARCHIVE_DOWNLOAD_LIMIT_BYTES = 128 * 1024 * 1024;
|
|
1591
|
+
var ARCHIVE_DOWNLOAD_TIMEOUT_MILLISECONDS = 2 * 60 * 1e3;
|
|
1592
|
+
var ARCHIVE_EXTRACTION_TIMEOUT_MILLISECONDS = 6e4;
|
|
1593
|
+
var MANIFEST_LIMIT_BYTES = 16 * 1024;
|
|
1594
|
+
var MINIMAL_PATH = "/usr/bin:/bin";
|
|
1595
|
+
var ManagedAgentArchiveDefinition = class {
|
|
1596
|
+
archiveName;
|
|
1597
|
+
archiveSha256;
|
|
1598
|
+
archiveUrl;
|
|
1599
|
+
executableName;
|
|
1600
|
+
version;
|
|
1601
|
+
constructor(version2, archiveName, archiveUrl, archiveSha256, executableName) {
|
|
1602
|
+
this.archiveName = archiveName;
|
|
1603
|
+
this.archiveSha256 = archiveSha256;
|
|
1604
|
+
this.archiveUrl = new URL(archiveUrl);
|
|
1605
|
+
this.executableName = executableName;
|
|
1606
|
+
this.version = version2;
|
|
1607
|
+
}
|
|
1608
|
+
};
|
|
1609
|
+
var ZipManagedAgentArchiveDefinition = class extends ManagedAgentArchiveDefinition {
|
|
1610
|
+
extractor = "/usr/bin/unzip";
|
|
1611
|
+
extractArguments = (archivePath, destination) => ["-q", archivePath, "-d", destination];
|
|
1612
|
+
listArguments = (archivePath) => [
|
|
1613
|
+
"-Z1",
|
|
1614
|
+
archivePath
|
|
1615
|
+
];
|
|
702
1616
|
};
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
1617
|
+
var TarGzipManagedAgentArchiveDefinition = class extends ManagedAgentArchiveDefinition {
|
|
1618
|
+
extractor = "/usr/bin/tar";
|
|
1619
|
+
extractArguments = (archivePath, destination) => ["-xzf", archivePath, "-C", destination];
|
|
1620
|
+
listArguments = (archivePath) => [
|
|
1621
|
+
"-tzf",
|
|
1622
|
+
archivePath
|
|
1623
|
+
];
|
|
1624
|
+
};
|
|
1625
|
+
var ManagedAgentArchiveError = class extends Error {
|
|
706
1626
|
code;
|
|
707
1627
|
constructor(code, message, options = {}) {
|
|
708
1628
|
super(message, options);
|
|
709
1629
|
this.code = code;
|
|
710
|
-
this.name = "
|
|
1630
|
+
this.name = "ManagedAgentArchiveError";
|
|
711
1631
|
}
|
|
712
1632
|
};
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
1633
|
+
var ManagedAgentArchiveDownloader = class {
|
|
1634
|
+
download = async (options) => await downloadVerifiedFile(options);
|
|
1635
|
+
};
|
|
1636
|
+
function isRecord3(value) {
|
|
1637
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1638
|
+
}
|
|
1639
|
+
function isContainedPath2(root, candidate) {
|
|
1640
|
+
const difference = relative2(root, candidate);
|
|
1641
|
+
return difference.length > 0 && difference !== ".." && !difference.startsWith(`..${sep2}`) && !isAbsolute3(difference);
|
|
1642
|
+
}
|
|
1643
|
+
async function hashFile(path2, signal) {
|
|
1644
|
+
signal.throwIfAborted();
|
|
1645
|
+
const digest = createHash2("sha256");
|
|
1646
|
+
const stream = createReadStream(path2, { signal });
|
|
1647
|
+
try {
|
|
1648
|
+
for await (const chunk of stream) {
|
|
1649
|
+
signal.throwIfAborted();
|
|
1650
|
+
if (!(chunk instanceof Uint8Array)) {
|
|
1651
|
+
throw new ManagedAgentArchiveError(
|
|
1652
|
+
"managed_archive_verification_failed",
|
|
1653
|
+
"The managed Agent archive produced invalid bytes"
|
|
1654
|
+
);
|
|
1655
|
+
}
|
|
1656
|
+
digest.update(chunk);
|
|
724
1657
|
}
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
{ cause: error61 }
|
|
730
|
-
);
|
|
1658
|
+
return digest.digest("hex");
|
|
1659
|
+
} catch (error61) {
|
|
1660
|
+
if (signal.aborted) {
|
|
1661
|
+
signal.throwIfAborted();
|
|
731
1662
|
}
|
|
732
|
-
if (error61
|
|
733
|
-
|
|
734
|
-
"adapter_publish_failed",
|
|
735
|
-
"The managed adapter could not be published",
|
|
736
|
-
{ cause: error61 }
|
|
737
|
-
);
|
|
1663
|
+
if (error61 instanceof ManagedAgentArchiveError) {
|
|
1664
|
+
throw error61;
|
|
738
1665
|
}
|
|
1666
|
+
throw new ManagedAgentArchiveError(
|
|
1667
|
+
"managed_archive_verification_failed",
|
|
1668
|
+
"The managed Agent artifact could not be verified",
|
|
1669
|
+
{ cause: error61 }
|
|
1670
|
+
);
|
|
739
1671
|
}
|
|
740
|
-
return new ManagedAdapterInstallError(
|
|
741
|
-
"adapter_install_failed",
|
|
742
|
-
"The pinned ACP adapter could not be installed",
|
|
743
|
-
{ cause: error61 }
|
|
744
|
-
);
|
|
745
1672
|
}
|
|
746
|
-
async function
|
|
1673
|
+
async function readManifest(path2) {
|
|
1674
|
+
let handle;
|
|
747
1675
|
try {
|
|
748
|
-
|
|
749
|
-
root,
|
|
750
|
-
specification.adapterPackageDefinition
|
|
751
|
-
);
|
|
1676
|
+
handle = await open4(path2, "r");
|
|
752
1677
|
} catch (error61) {
|
|
753
|
-
throw
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
#npmInstaller;
|
|
759
|
-
#stateDirectory;
|
|
760
|
-
constructor(options, npmInstaller = new ManagedNpmPackageInstaller()) {
|
|
761
|
-
this.#environment = options.environment;
|
|
762
|
-
this.#npmInstaller = npmInstaller;
|
|
763
|
-
this.#stateDirectory = options.stateDirectory;
|
|
1678
|
+
throw new ManagedAgentArchiveError(
|
|
1679
|
+
"managed_archive_verification_failed",
|
|
1680
|
+
"The managed Agent archive manifest is invalid",
|
|
1681
|
+
{ cause: error61 }
|
|
1682
|
+
);
|
|
764
1683
|
}
|
|
765
|
-
|
|
766
|
-
const
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
1684
|
+
try {
|
|
1685
|
+
const metadata = await handle.stat();
|
|
1686
|
+
if (!metadata.isFile() || metadata.size > MANIFEST_LIMIT_BYTES) {
|
|
1687
|
+
throw new ManagedAgentArchiveError(
|
|
1688
|
+
"managed_archive_verification_failed",
|
|
1689
|
+
"The managed Agent archive manifest is invalid"
|
|
1690
|
+
);
|
|
1691
|
+
}
|
|
1692
|
+
const parsed = JSON.parse(
|
|
1693
|
+
await handle.readFile({ encoding: "utf8" })
|
|
771
1694
|
);
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
this.#environment,
|
|
777
|
-
signal
|
|
1695
|
+
if (!isRecord3(parsed)) {
|
|
1696
|
+
throw new ManagedAgentArchiveError(
|
|
1697
|
+
"managed_archive_verification_failed",
|
|
1698
|
+
"The managed Agent archive manifest is invalid"
|
|
778
1699
|
);
|
|
779
|
-
} catch (error61) {
|
|
780
|
-
if (signal.aborted) {
|
|
781
|
-
signal.throwIfAborted();
|
|
782
|
-
}
|
|
783
|
-
throw translateError(error61);
|
|
784
1700
|
}
|
|
785
|
-
|
|
786
|
-
}
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
"@earendil-works/pi-coding-agent",
|
|
798
|
-
"0.85.0",
|
|
799
|
-
"pi",
|
|
800
|
-
"sha512-INxVkLAVfAMju5MojJpmyu/0bMP+r+ffZuS7UqVv32E2JwHBRbcHfELDfmFNvapEbgYfKN2r9OYO1p3TqDBR+g==",
|
|
801
|
-
"https://registry.npmjs.org/@earendil-works/pi-coding-agent/-/pi-coding-agent-0.85.0.tgz"
|
|
802
|
-
);
|
|
803
|
-
|
|
804
|
-
// src/storage/state-directory.ts
|
|
805
|
-
import { homedir } from "node:os";
|
|
806
|
-
import { join as join5, resolve as resolve2 } from "node:path";
|
|
807
|
-
function readStateDirectory(environment = process.env) {
|
|
808
|
-
const configured = environment["MOBIUS_STATE_DIRECTORY"]?.trim();
|
|
809
|
-
if (configured !== void 0 && configured.length > 0) {
|
|
810
|
-
return resolve2(configured);
|
|
1701
|
+
return parsed;
|
|
1702
|
+
} catch (error61) {
|
|
1703
|
+
if (error61 instanceof ManagedAgentArchiveError) {
|
|
1704
|
+
throw error61;
|
|
1705
|
+
}
|
|
1706
|
+
throw new ManagedAgentArchiveError(
|
|
1707
|
+
"managed_archive_verification_failed",
|
|
1708
|
+
"The managed Agent archive manifest is invalid",
|
|
1709
|
+
{ cause: error61 }
|
|
1710
|
+
);
|
|
1711
|
+
} finally {
|
|
1712
|
+
await handle.close();
|
|
811
1713
|
}
|
|
812
|
-
return join5(homedir(), ".mobius");
|
|
813
|
-
}
|
|
814
|
-
|
|
815
|
-
// src/agent-catalog/local-agent.ts
|
|
816
|
-
import { realpathSync, statSync } from "node:fs";
|
|
817
|
-
function readTrustedIdentity(path2) {
|
|
818
|
-
const resolvedPath = realpathSync(path2);
|
|
819
|
-
const metadata = statSync(resolvedPath);
|
|
820
|
-
return new ExecutableIdentity(
|
|
821
|
-
resolvedPath,
|
|
822
|
-
resolvedPath,
|
|
823
|
-
metadata.dev,
|
|
824
|
-
metadata.ino,
|
|
825
|
-
metadata.size,
|
|
826
|
-
metadata.ctimeMs
|
|
827
|
-
);
|
|
828
1714
|
}
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
arguments;
|
|
836
|
-
command;
|
|
837
|
-
environment;
|
|
838
|
-
id;
|
|
839
|
-
label;
|
|
840
|
-
promptTimeoutMilliseconds;
|
|
841
|
-
constructor(id, label, command, arguments_, environment = {}, adapterVersion = "", agentVersion = "", adapterIdentity = readTrustedIdentity(command), agentIdentity = adapterIdentity, promptTimeoutMilliseconds = 30 * 60 * 1e3) {
|
|
842
|
-
if (!Number.isSafeInteger(promptTimeoutMilliseconds) || promptTimeoutMilliseconds < 1) {
|
|
843
|
-
throw new Error("The local Agent prompt deadline is invalid");
|
|
1715
|
+
async function validateManagedAgentArchive(root, definition, signal) {
|
|
1716
|
+
try {
|
|
1717
|
+
const rootPath = await realpath4(root);
|
|
1718
|
+
const rootMetadata = await stat4(rootPath);
|
|
1719
|
+
if (!rootMetadata.isDirectory() || typeof process.getuid === "function" && rootMetadata.uid !== process.getuid()) {
|
|
1720
|
+
throw new Error("Managed Agent root is not user-owned");
|
|
844
1721
|
}
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
}
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
var LocalAgentCatalogSnapshot = class {
|
|
869
|
-
agents;
|
|
870
|
-
installableAgents;
|
|
871
|
-
constructor(agents, installableAgents) {
|
|
872
|
-
this.agents = Object.freeze([...agents]);
|
|
873
|
-
this.installableAgents = Object.freeze([...installableAgents]);
|
|
1722
|
+
const manifest = await readManifest(join7(rootPath, "archive.json"));
|
|
1723
|
+
if (manifest["archiveSha256"] !== definition.archiveSha256 || manifest["archiveUrl"] !== definition.archiveUrl.toString() || manifest["version"] !== definition.version || typeof manifest["executableSha256"] !== "string") {
|
|
1724
|
+
throw new Error("Managed Agent archive identity is invalid");
|
|
1725
|
+
}
|
|
1726
|
+
const executable = await resolveExecutablePath(
|
|
1727
|
+
join7(rootPath, "bin", definition.executableName)
|
|
1728
|
+
);
|
|
1729
|
+
if (executable === null || !isContainedPath2(rootPath, executable.path) || await hashFile(executable.path, signal) !== manifest["executableSha256"]) {
|
|
1730
|
+
throw new Error("Managed Agent executable is invalid");
|
|
1731
|
+
}
|
|
1732
|
+
return executable;
|
|
1733
|
+
} catch (error61) {
|
|
1734
|
+
if (signal.aborted) {
|
|
1735
|
+
signal.throwIfAborted();
|
|
1736
|
+
}
|
|
1737
|
+
if (error61 instanceof ManagedAgentArchiveError) {
|
|
1738
|
+
throw error61;
|
|
1739
|
+
}
|
|
1740
|
+
throw new ManagedAgentArchiveError(
|
|
1741
|
+
"managed_archive_verification_failed",
|
|
1742
|
+
"The managed Agent archive did not match its pinned artifact",
|
|
1743
|
+
{ cause: error61 }
|
|
1744
|
+
);
|
|
874
1745
|
}
|
|
875
|
-
}
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
1746
|
+
}
|
|
1747
|
+
function validateArchiveEntries(output2, definition) {
|
|
1748
|
+
const entries = output2.split(/\r?\n/).map((entry) => entry.trim()).filter((entry) => entry.length > 0);
|
|
1749
|
+
if (entries.length !== 1 || entries[0] !== definition.executableName && entries[0] !== `./${definition.executableName}`) {
|
|
1750
|
+
throw new ManagedAgentArchiveError(
|
|
1751
|
+
"managed_archive_verification_failed",
|
|
1752
|
+
"The managed Agent archive contains unexpected entries"
|
|
1753
|
+
);
|
|
881
1754
|
}
|
|
882
|
-
}
|
|
883
|
-
var
|
|
884
|
-
#
|
|
885
|
-
constructor(
|
|
886
|
-
this.#
|
|
1755
|
+
}
|
|
1756
|
+
var ManagedAgentArchiveInstaller = class {
|
|
1757
|
+
#downloader;
|
|
1758
|
+
constructor(downloader = new ManagedAgentArchiveDownloader()) {
|
|
1759
|
+
this.#downloader = downloader;
|
|
887
1760
|
}
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
1761
|
+
install = async (root, definition, signal) => {
|
|
1762
|
+
signal.throwIfAborted();
|
|
1763
|
+
try {
|
|
1764
|
+
const metadata = await stat4(root);
|
|
1765
|
+
if (metadata.isDirectory()) {
|
|
1766
|
+
return await validateManagedAgentArchive(root, definition, signal);
|
|
1767
|
+
}
|
|
1768
|
+
} catch (error61) {
|
|
1769
|
+
if (error61 instanceof ManagedAgentArchiveError || !(error61 instanceof Error) || !("code" in error61) || error61.code !== "ENOENT") {
|
|
1770
|
+
throw error61;
|
|
892
1771
|
}
|
|
893
1772
|
}
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
1773
|
+
const parent = dirname2(root);
|
|
1774
|
+
await mkdir2(parent, { mode: 448, recursive: true });
|
|
1775
|
+
const working = await mkdtemp2(
|
|
1776
|
+
join7(parent, `.${definition.version}.archive-`)
|
|
1777
|
+
);
|
|
1778
|
+
const staging = await mkdtemp2(
|
|
1779
|
+
join7(parent, `.${definition.version}.staging-`)
|
|
1780
|
+
);
|
|
1781
|
+
try {
|
|
1782
|
+
const archivePath = join7(working, definition.archiveName);
|
|
1783
|
+
const extractionRoot = join7(working, "extracted");
|
|
1784
|
+
await mkdir2(extractionRoot, { mode: 448 });
|
|
1785
|
+
const canonicalExtractionRoot = await realpath4(extractionRoot);
|
|
1786
|
+
const download = await this.#downloader.download({
|
|
1787
|
+
allowedHosts: /* @__PURE__ */ new Set([
|
|
1788
|
+
"github.com",
|
|
1789
|
+
"objects.githubusercontent.com",
|
|
1790
|
+
"release-assets.githubusercontent.com"
|
|
1791
|
+
]),
|
|
1792
|
+
destination: archivePath,
|
|
1793
|
+
maximumBytes: ARCHIVE_DOWNLOAD_LIMIT_BYTES,
|
|
1794
|
+
signal,
|
|
1795
|
+
timeoutMilliseconds: ARCHIVE_DOWNLOAD_TIMEOUT_MILLISECONDS,
|
|
1796
|
+
url: definition.archiveUrl
|
|
1797
|
+
});
|
|
1798
|
+
if (download.sha256 !== definition.archiveSha256) {
|
|
1799
|
+
throw new ManagedAgentArchiveError(
|
|
1800
|
+
"managed_archive_verification_failed",
|
|
1801
|
+
"The managed Agent archive checksum is invalid"
|
|
1802
|
+
);
|
|
1803
|
+
}
|
|
1804
|
+
const list = await runBoundedProcess({
|
|
1805
|
+
arguments: definition.listArguments(archivePath),
|
|
1806
|
+
command: definition.extractor,
|
|
1807
|
+
cwd: working,
|
|
1808
|
+
environment: { PATH: MINIMAL_PATH },
|
|
1809
|
+
outputLimitBytes: 64 * 1024,
|
|
1810
|
+
signal,
|
|
1811
|
+
timeoutMilliseconds: ARCHIVE_EXTRACTION_TIMEOUT_MILLISECONDS
|
|
1812
|
+
});
|
|
1813
|
+
validateArchiveEntries(list.stdout, definition);
|
|
1814
|
+
await runBoundedProcess({
|
|
1815
|
+
arguments: definition.extractArguments(archivePath, extractionRoot),
|
|
1816
|
+
command: definition.extractor,
|
|
1817
|
+
cwd: working,
|
|
1818
|
+
environment: { PATH: MINIMAL_PATH },
|
|
1819
|
+
outputLimitBytes: 64 * 1024,
|
|
1820
|
+
signal,
|
|
1821
|
+
timeoutMilliseconds: ARCHIVE_EXTRACTION_TIMEOUT_MILLISECONDS
|
|
1822
|
+
});
|
|
1823
|
+
const extracted = await realpath4(
|
|
1824
|
+
join7(canonicalExtractionRoot, definition.executableName)
|
|
1825
|
+
);
|
|
1826
|
+
const extractedMetadata = await stat4(extracted);
|
|
1827
|
+
if (!isContainedPath2(canonicalExtractionRoot, extracted) || !extractedMetadata.isFile()) {
|
|
1828
|
+
throw new ManagedAgentArchiveError(
|
|
1829
|
+
"managed_archive_verification_failed",
|
|
1830
|
+
"The managed Agent archive executable is invalid"
|
|
1831
|
+
);
|
|
1832
|
+
}
|
|
1833
|
+
const binDirectory = join7(staging, "bin");
|
|
1834
|
+
const executablePath = join7(binDirectory, definition.executableName);
|
|
1835
|
+
await mkdir2(binDirectory, { mode: 448 });
|
|
1836
|
+
await copyFile(extracted, executablePath);
|
|
1837
|
+
await chmod(executablePath, 448);
|
|
1838
|
+
const executableSha256 = await hashFile(executablePath, signal);
|
|
1839
|
+
await writeFile(
|
|
1840
|
+
join7(staging, "archive.json"),
|
|
1841
|
+
`${JSON.stringify({
|
|
1842
|
+
archiveSha256: definition.archiveSha256,
|
|
1843
|
+
archiveUrl: definition.archiveUrl.toString(),
|
|
1844
|
+
executableSha256,
|
|
1845
|
+
version: definition.version
|
|
1846
|
+
})}
|
|
1847
|
+
`,
|
|
1848
|
+
{ mode: 384 }
|
|
1849
|
+
);
|
|
1850
|
+
await validateManagedAgentArchive(staging, definition, signal);
|
|
1851
|
+
try {
|
|
1852
|
+
await rename2(staging, root);
|
|
1853
|
+
} catch (error61) {
|
|
1854
|
+
try {
|
|
1855
|
+
return await validateManagedAgentArchive(root, definition, signal);
|
|
1856
|
+
} catch {
|
|
1857
|
+
throw new ManagedAgentArchiveError(
|
|
1858
|
+
"managed_archive_publish_failed",
|
|
1859
|
+
"The managed Agent archive could not be published",
|
|
1860
|
+
{ cause: error61 }
|
|
1861
|
+
);
|
|
1862
|
+
}
|
|
907
1863
|
}
|
|
908
|
-
|
|
909
|
-
}
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
throw new Error("A local Agent cannot be ready and installable");
|
|
1864
|
+
return await validateManagedAgentArchive(root, definition, signal);
|
|
1865
|
+
} catch (error61) {
|
|
1866
|
+
if (signal.aborted) {
|
|
1867
|
+
signal.throwIfAborted();
|
|
913
1868
|
}
|
|
914
|
-
|
|
1869
|
+
if (error61 instanceof ManagedAgentArchiveError) {
|
|
1870
|
+
throw error61;
|
|
1871
|
+
}
|
|
1872
|
+
throw new ManagedAgentArchiveError(
|
|
1873
|
+
"managed_archive_install_failed",
|
|
1874
|
+
"The pinned Agent archive could not be installed",
|
|
1875
|
+
{ cause: error61 }
|
|
1876
|
+
);
|
|
1877
|
+
} finally {
|
|
1878
|
+
await Promise.all([
|
|
1879
|
+
rm2(working, { force: true, recursive: true }),
|
|
1880
|
+
rm2(staging, { force: true, recursive: true })
|
|
1881
|
+
]);
|
|
915
1882
|
}
|
|
916
|
-
return new LocalAgentCatalogSnapshot(agents, installableAgents);
|
|
917
1883
|
};
|
|
918
1884
|
};
|
|
919
1885
|
|
|
920
|
-
// src/agent-
|
|
921
|
-
var
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
1886
|
+
// src/agent-installation/opencode-managed-release.ts
|
|
1887
|
+
var OPENCODE_MANAGED_VERSION = "1.18.29";
|
|
1888
|
+
function releaseUrl(asset) {
|
|
1889
|
+
return new URL(
|
|
1890
|
+
`https://github.com/anomalyco/opencode/releases/download/v${OPENCODE_MANAGED_VERSION}/${asset}`
|
|
1891
|
+
);
|
|
1892
|
+
}
|
|
1893
|
+
function openCodeManagedArchive(platform, architecture) {
|
|
1894
|
+
if (platform === "darwin" && architecture === "arm64") {
|
|
1895
|
+
const asset = "opencode-darwin-arm64.zip";
|
|
1896
|
+
return new ZipManagedAgentArchiveDefinition(
|
|
1897
|
+
OPENCODE_MANAGED_VERSION,
|
|
1898
|
+
asset,
|
|
1899
|
+
releaseUrl(asset),
|
|
1900
|
+
"fe764f7f360c584a83e18dd5f23fb1a6b2725f5ee8854b0252fe558f7798e946",
|
|
1901
|
+
"opencode"
|
|
1902
|
+
);
|
|
935
1903
|
}
|
|
936
|
-
|
|
937
|
-
|
|
1904
|
+
if (platform === "darwin" && architecture === "x64") {
|
|
1905
|
+
const asset = "opencode-darwin-x64.zip";
|
|
1906
|
+
return new ZipManagedAgentArchiveDefinition(
|
|
1907
|
+
OPENCODE_MANAGED_VERSION,
|
|
1908
|
+
asset,
|
|
1909
|
+
releaseUrl(asset),
|
|
1910
|
+
"9858853e7bacdbbd22c2d70c377e009dc4b354dd04f5588705411e7afb89fd2d",
|
|
1911
|
+
"opencode"
|
|
1912
|
+
);
|
|
938
1913
|
}
|
|
939
|
-
|
|
940
|
-
|
|
1914
|
+
if (platform === "linux" && architecture === "arm64") {
|
|
1915
|
+
const asset = "opencode-linux-arm64.tar.gz";
|
|
1916
|
+
return new TarGzipManagedAgentArchiveDefinition(
|
|
1917
|
+
OPENCODE_MANAGED_VERSION,
|
|
1918
|
+
asset,
|
|
1919
|
+
releaseUrl(asset),
|
|
1920
|
+
"70baf769395ca4e7a68924026530c390eace194f3b7e4919d4efcb2aa2eed3c0",
|
|
1921
|
+
"opencode"
|
|
1922
|
+
);
|
|
941
1923
|
}
|
|
942
|
-
|
|
943
|
-
const
|
|
944
|
-
|
|
945
|
-
|
|
1924
|
+
if (platform === "linux" && architecture === "x64") {
|
|
1925
|
+
const asset = "opencode-linux-x64.tar.gz";
|
|
1926
|
+
return new TarGzipManagedAgentArchiveDefinition(
|
|
1927
|
+
OPENCODE_MANAGED_VERSION,
|
|
1928
|
+
asset,
|
|
1929
|
+
releaseUrl(asset),
|
|
1930
|
+
"ea800b7ff56226b70952126c9fc1e2517ca4c4b5682fd9d3f9e87449697a1194",
|
|
1931
|
+
"opencode"
|
|
946
1932
|
);
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
return executable;
|
|
951
|
-
};
|
|
952
|
-
recoveryCommand = () => `npm install -g --omit=optional ${this.adapterPackage}@${this.adapterVersion}`;
|
|
953
|
-
supportsInstallation = (platform, architecture) => (platform === "darwin" || platform === "linux") && (architecture === "arm64" || architecture === "x64");
|
|
954
|
-
verifyAcp = (_connection, _initialized, _defaultWorkspace, _signal) => Promise.resolve();
|
|
955
|
-
};
|
|
956
|
-
var BridgedAcpAgentDefinition = class extends LocalAgentSpecification {
|
|
957
|
-
};
|
|
958
|
-
var CodexAgentSpecification = class extends BridgedAcpAgentDefinition {
|
|
959
|
-
adapterEnvironmentVariable = "CODEX_PATH";
|
|
960
|
-
adapterOverrideVariable = "MOBIUS_CODEX_ACP_PATH";
|
|
961
|
-
adapterPackageDefinition = new ManagedNpmPackageDefinition(
|
|
962
|
-
"@agentclientprotocol/codex-acp",
|
|
963
|
-
"1.8.0",
|
|
964
|
-
"codex-acp"
|
|
1933
|
+
}
|
|
1934
|
+
throw new Error(
|
|
1935
|
+
"OpenCode does not publish an approved archive for this platform"
|
|
965
1936
|
);
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
1937
|
+
}
|
|
1938
|
+
|
|
1939
|
+
// src/agent-catalog/agents/opencode-agent.ts
|
|
1940
|
+
var OpenCodeAgentSpecification = class extends DirectAcpAgentDefinition {
|
|
1941
|
+
versionProbeTimeoutMilliseconds = 15e3;
|
|
1942
|
+
adapterVersion = OPENCODE_MANAGED_VERSION;
|
|
1943
|
+
authenticationCommand = () => "opencode auth login";
|
|
1944
|
+
agentExecutable = "opencode";
|
|
1945
|
+
id = "opencode";
|
|
1946
|
+
label = "OpenCode";
|
|
1947
|
+
constructor() {
|
|
1948
|
+
super(
|
|
1949
|
+
"MOBIUS_OPENCODE_PATH",
|
|
1950
|
+
["acp"],
|
|
1951
|
+
[
|
|
1952
|
+
"agents",
|
|
1953
|
+
"opencode",
|
|
1954
|
+
OPENCODE_MANAGED_VERSION,
|
|
1955
|
+
"bin",
|
|
1956
|
+
process.platform === "win32" ? "opencode.exe" : "opencode"
|
|
1957
|
+
]
|
|
1958
|
+
);
|
|
1959
|
+
}
|
|
1960
|
+
createLaunchEnvironment = async (_agent, _context) => Object.freeze({ OPENCODE_DISABLE_AUTOUPDATE: "1" });
|
|
1961
|
+
resolveManagedAgent = async (stateDirectory, platform, signal) => await validateManagedAgentArchive(
|
|
1962
|
+
join8(stateDirectory, "agents", this.id, OPENCODE_MANAGED_VERSION),
|
|
1963
|
+
openCodeManagedArchive(platform, process.arch),
|
|
1964
|
+
signal
|
|
989
1965
|
);
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
"dist",
|
|
1002
|
-
"index.js"
|
|
1003
|
-
];
|
|
1004
|
-
managedAgentExecutablePath = [
|
|
1005
|
-
"agents",
|
|
1006
|
-
"claude",
|
|
1007
|
-
"home",
|
|
1008
|
-
".local",
|
|
1009
|
-
"bin",
|
|
1010
|
-
"claude"
|
|
1011
|
-
];
|
|
1966
|
+
verifyAcp = (_connection, initialized, _defaultWorkspace, _signal) => {
|
|
1967
|
+
const capabilities = initialized.agentCapabilities ?? {};
|
|
1968
|
+
const session = capabilities.sessionCapabilities;
|
|
1969
|
+
if (capabilities.loadSession !== true || session?.close == null || session.list == null || session.resume == null) {
|
|
1970
|
+
throw new AgentProbeError(
|
|
1971
|
+
"acp_incompatible",
|
|
1972
|
+
"OpenCode does not support the required ACP session lifecycle"
|
|
1973
|
+
);
|
|
1974
|
+
}
|
|
1975
|
+
return Promise.resolve();
|
|
1976
|
+
};
|
|
1012
1977
|
};
|
|
1978
|
+
|
|
1979
|
+
// src/agent-catalog/agents/pi-agent.ts
|
|
1980
|
+
import { join as join9 } from "node:path";
|
|
1981
|
+
import {
|
|
1982
|
+
methods
|
|
1983
|
+
} from "@agentclientprotocol/sdk";
|
|
1984
|
+
|
|
1985
|
+
// src/agent-installation/pi-managed-packages.ts
|
|
1986
|
+
var PI_ACP_PACKAGE = new SriManagedNpmPackageDefinition(
|
|
1987
|
+
"pi-acp",
|
|
1988
|
+
"0.0.33",
|
|
1989
|
+
"pi-acp",
|
|
1990
|
+
"sha512-vX9kY1tK14E72G4dBAx+RGCk/k7XPjTHls6dLUxA8WSkBav6B6JHuSBv3eusp50LCR/GTRsR2kIKsG0Z5jANzw==",
|
|
1991
|
+
"https://registry.npmjs.org/pi-acp/-/pi-acp-0.0.33.tgz"
|
|
1992
|
+
);
|
|
1993
|
+
var PI_AGENT_PACKAGE = new SriManagedNpmPackageDefinition(
|
|
1994
|
+
"@earendil-works/pi-coding-agent",
|
|
1995
|
+
"0.85.0",
|
|
1996
|
+
"pi",
|
|
1997
|
+
"sha512-INxVkLAVfAMju5MojJpmyu/0bMP+r+ffZuS7UqVv32E2JwHBRbcHfELDfmFNvapEbgYfKN2r9OYO1p3TqDBR+g==",
|
|
1998
|
+
"https://registry.npmjs.org/@earendil-works/pi-coding-agent/-/pi-coding-agent-0.85.0.tgz"
|
|
1999
|
+
);
|
|
2000
|
+
|
|
2001
|
+
// src/agent-catalog/agents/pi-agent.ts
|
|
2002
|
+
var ACP_PROBE_TIMEOUT_MILLISECONDS2 = 3e4;
|
|
2003
|
+
var PROMPT_TIMEOUT_MILLISECONDS = 5 * 60 * 1e3;
|
|
1013
2004
|
var PiAgentSpecification = class extends BridgedAcpAgentDefinition {
|
|
1014
|
-
acpProbeTimeoutMilliseconds =
|
|
2005
|
+
acpProbeTimeoutMilliseconds = ACP_PROBE_TIMEOUT_MILLISECONDS2;
|
|
1015
2006
|
adapterEnvironmentVariable = "PI_ACP_PI_COMMAND";
|
|
1016
2007
|
adapterOverrideVariable = "MOBIUS_PI_ACP_PATH";
|
|
1017
2008
|
adapterPackageDefinition = PI_ACP_PACKAGE;
|
|
@@ -1041,11 +2032,16 @@ var PiAgentSpecification = class extends BridgedAcpAgentDefinition {
|
|
|
1041
2032
|
"bundle",
|
|
1042
2033
|
"cli.js"
|
|
1043
2034
|
];
|
|
1044
|
-
promptTimeoutMilliseconds =
|
|
1045
|
-
resolveManagedAgent = async (stateDirectory, _platform) =>
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
2035
|
+
promptTimeoutMilliseconds = PROMPT_TIMEOUT_MILLISECONDS;
|
|
2036
|
+
resolveManagedAgent = async (stateDirectory, _platform, signal) => {
|
|
2037
|
+
signal.throwIfAborted();
|
|
2038
|
+
const executable = await validateManagedNpmPackage(
|
|
2039
|
+
join9(stateDirectory, "agents", this.id, PI_AGENT_PACKAGE.version),
|
|
2040
|
+
PI_AGENT_PACKAGE
|
|
2041
|
+
);
|
|
2042
|
+
signal.throwIfAborted();
|
|
2043
|
+
return executable;
|
|
2044
|
+
};
|
|
1049
2045
|
verifyAcp = async (connection, initialized, defaultWorkspace, signal) => {
|
|
1050
2046
|
const capabilities = initialized.agentCapabilities ?? {};
|
|
1051
2047
|
if (capabilities.loadSession !== true) {
|
|
@@ -1055,7 +2051,7 @@ var PiAgentSpecification = class extends BridgedAcpAgentDefinition {
|
|
|
1055
2051
|
);
|
|
1056
2052
|
}
|
|
1057
2053
|
const session = await connection.agent.request(
|
|
1058
|
-
|
|
2054
|
+
methods.agent.session.new,
|
|
1059
2055
|
{
|
|
1060
2056
|
additionalDirectories: [],
|
|
1061
2057
|
cwd: defaultWorkspace,
|
|
@@ -1070,7 +2066,7 @@ var PiAgentSpecification = class extends BridgedAcpAgentDefinition {
|
|
|
1070
2066
|
);
|
|
1071
2067
|
}
|
|
1072
2068
|
const prompt = await connection.agent.request(
|
|
1073
|
-
|
|
2069
|
+
methods.agent.session.prompt,
|
|
1074
2070
|
{
|
|
1075
2071
|
prompt: [{ text: "/session", type: "text" }],
|
|
1076
2072
|
sessionId: session.sessionId
|
|
@@ -1078,145 +2074,158 @@ var PiAgentSpecification = class extends BridgedAcpAgentDefinition {
|
|
|
1078
2074
|
{ cancellationSignal: signal }
|
|
1079
2075
|
);
|
|
1080
2076
|
if (prompt.stopReason !== "end_turn") {
|
|
1081
|
-
throw new AgentProbeError(
|
|
1082
|
-
"acp_incompatible",
|
|
1083
|
-
"Pi ACP adapter did not complete its conformance prompt"
|
|
1084
|
-
);
|
|
1085
|
-
}
|
|
1086
|
-
};
|
|
1087
|
-
};
|
|
1088
|
-
function supportedLocalAgentSpecifications() {
|
|
1089
|
-
return Object.freeze([
|
|
1090
|
-
new CodexAgentSpecification(),
|
|
1091
|
-
new ClaudeCodeAgentSpecification(),
|
|
1092
|
-
new PiAgentSpecification()
|
|
1093
|
-
]);
|
|
1094
|
-
}
|
|
1095
|
-
var AgentDiscovery = class {
|
|
1096
|
-
specification;
|
|
1097
|
-
constructor(specification) {
|
|
1098
|
-
this.specification = specification;
|
|
1099
|
-
}
|
|
1100
|
-
};
|
|
1101
|
-
var AvailableAgent = class extends AgentDiscovery {
|
|
1102
|
-
agent;
|
|
1103
|
-
status = "ready";
|
|
1104
|
-
constructor(specification, agent) {
|
|
1105
|
-
super(specification);
|
|
1106
|
-
this.agent = agent;
|
|
1107
|
-
}
|
|
1108
|
-
};
|
|
1109
|
-
var UnavailableAgent = class extends AgentDiscovery {
|
|
1110
|
-
};
|
|
1111
|
-
var MissingAdapter = class extends UnavailableAgent {
|
|
1112
|
-
code = "adapter_not_found";
|
|
1113
|
-
message = "ACP adapter not found";
|
|
1114
|
-
status = "missing_adapter";
|
|
1115
|
-
constructor(specification) {
|
|
1116
|
-
super(specification);
|
|
1117
|
-
}
|
|
1118
|
-
};
|
|
1119
|
-
var MissingAgent = class extends UnavailableAgent {
|
|
1120
|
-
code = "agent_not_found";
|
|
1121
|
-
message = "Agent executable not found";
|
|
1122
|
-
status = "missing_agent";
|
|
1123
|
-
constructor(specification) {
|
|
1124
|
-
super(specification);
|
|
1125
|
-
}
|
|
1126
|
-
};
|
|
1127
|
-
var ProbeFailed = class extends UnavailableAgent {
|
|
1128
|
-
code;
|
|
1129
|
-
message;
|
|
1130
|
-
status = "probe_failed";
|
|
1131
|
-
constructor(specification, code, message) {
|
|
1132
|
-
super(specification);
|
|
1133
|
-
this.code = code;
|
|
1134
|
-
this.message = message;
|
|
1135
|
-
}
|
|
1136
|
-
};
|
|
1137
|
-
var IncompatibleAdapter = class extends UnavailableAgent {
|
|
1138
|
-
code = "acp_incompatible";
|
|
1139
|
-
message = "ACP adapter is incompatible";
|
|
1140
|
-
status = "incompatible_adapter";
|
|
1141
|
-
constructor(specification) {
|
|
1142
|
-
super(specification);
|
|
1143
|
-
}
|
|
1144
|
-
};
|
|
1145
|
-
var AuthenticationRequiredAgent = class extends UnavailableAgent {
|
|
1146
|
-
code = "authentication_required";
|
|
1147
|
-
message = "Agent authentication is required";
|
|
1148
|
-
status = "authentication_required";
|
|
1149
|
-
constructor(specification) {
|
|
1150
|
-
super(specification);
|
|
1151
|
-
}
|
|
1152
|
-
};
|
|
1153
|
-
var LocalAgentInventory = class {
|
|
1154
|
-
available;
|
|
1155
|
-
discoveries;
|
|
1156
|
-
installable;
|
|
1157
|
-
unavailable;
|
|
1158
|
-
constructor(discoveries, grantedAgents = /* @__PURE__ */ new Set(), platform = process.platform, architecture = process.arch) {
|
|
1159
|
-
const available = [];
|
|
1160
|
-
const unavailable = [];
|
|
1161
|
-
for (const discovery of discoveries) {
|
|
1162
|
-
if (discovery instanceof AvailableAgent) {
|
|
1163
|
-
available.push(discovery);
|
|
1164
|
-
} else if (discovery instanceof UnavailableAgent) {
|
|
1165
|
-
unavailable.push(discovery);
|
|
1166
|
-
} else {
|
|
1167
|
-
throw new Error("Unsupported Agent discovery outcome");
|
|
1168
|
-
}
|
|
1169
|
-
}
|
|
1170
|
-
this.available = Object.freeze(available);
|
|
1171
|
-
this.discoveries = Object.freeze([...discoveries]);
|
|
1172
|
-
this.installable = Object.freeze(
|
|
1173
|
-
unavailable.filter(
|
|
1174
|
-
(discovery) => !(discovery instanceof AuthenticationRequiredAgent) && discovery.specification.supportsInstallation(
|
|
1175
|
-
platform,
|
|
1176
|
-
architecture
|
|
1177
|
-
)
|
|
1178
|
-
).map(
|
|
1179
|
-
(discovery) => new InstallableAgentDefinition(
|
|
1180
|
-
discovery.specification.id,
|
|
1181
|
-
discovery.specification.label,
|
|
1182
|
-
!grantedAgents.has(discovery.specification.id)
|
|
1183
|
-
)
|
|
1184
|
-
)
|
|
1185
|
-
);
|
|
1186
|
-
this.unavailable = Object.freeze(unavailable);
|
|
1187
|
-
}
|
|
1188
|
-
readyAgents = () => this.available.map((discovery) => discovery.agent);
|
|
2077
|
+
throw new AgentProbeError(
|
|
2078
|
+
"acp_incompatible",
|
|
2079
|
+
"Pi ACP adapter did not complete its conformance prompt"
|
|
2080
|
+
);
|
|
2081
|
+
}
|
|
2082
|
+
};
|
|
1189
2083
|
};
|
|
1190
|
-
|
|
2084
|
+
|
|
2085
|
+
// src/agent-catalog/agents/supported-agent-specifications.ts
|
|
2086
|
+
function supportedLocalAgentSpecifications() {
|
|
2087
|
+
return Object.freeze([
|
|
2088
|
+
new CodexAgentSpecification(),
|
|
2089
|
+
new ClaudeCodeAgentSpecification(),
|
|
2090
|
+
new PiAgentSpecification(),
|
|
2091
|
+
new DeepSeekHarnessAgentSpecification(),
|
|
2092
|
+
new OpenCodeAgentSpecification()
|
|
2093
|
+
]);
|
|
2094
|
+
}
|
|
2095
|
+
|
|
2096
|
+
// src/agent-catalog/acp-readiness-probe.ts
|
|
2097
|
+
import { spawn as spawn2 } from "node:child_process";
|
|
2098
|
+
import {
|
|
2099
|
+
methods as methods3,
|
|
2100
|
+
ndJsonStream,
|
|
2101
|
+
PROTOCOL_VERSION,
|
|
2102
|
+
RequestError
|
|
2103
|
+
} from "@agentclientprotocol/sdk";
|
|
2104
|
+
|
|
2105
|
+
// src/acp/create-client.ts
|
|
2106
|
+
import {
|
|
2107
|
+
client,
|
|
2108
|
+
methods as methods2
|
|
2109
|
+
} from "@agentclientprotocol/sdk";
|
|
2110
|
+
var createAcpClient = (handler) => client({ name: "mobius" }).onRequest(
|
|
2111
|
+
methods2.client.session.requestPermission,
|
|
2112
|
+
async (context) => await handler.onPermission(context.params, context.signal)
|
|
2113
|
+
).onRequest(
|
|
2114
|
+
methods2.client.elicitation.create,
|
|
2115
|
+
async (context) => await handler.onElicitation(context.params, context.signal)
|
|
2116
|
+
).onNotification(methods2.client.session.update, async (context) => {
|
|
2117
|
+
await handler.onUpdate(context.params);
|
|
2118
|
+
}).onNotification(methods2.client.elicitation.complete, async (context) => {
|
|
2119
|
+
await handler.onElicitationComplete(context.params);
|
|
2120
|
+
});
|
|
2121
|
+
|
|
2122
|
+
// src/agent-catalog/executable-discovery.ts
|
|
2123
|
+
import { isAbsolute as isAbsolute4, join as join11 } from "node:path";
|
|
2124
|
+
|
|
2125
|
+
// src/agent-installation/managed-adapter-installer.ts
|
|
2126
|
+
import { join as join10 } from "node:path";
|
|
2127
|
+
var ManagedAdapterInstallError = class extends Error {
|
|
1191
2128
|
code;
|
|
1192
2129
|
constructor(code, message, options = {}) {
|
|
1193
2130
|
super(message, options);
|
|
1194
2131
|
this.code = code;
|
|
1195
|
-
this.name = "
|
|
2132
|
+
this.name = "ManagedAdapterInstallError";
|
|
1196
2133
|
}
|
|
1197
2134
|
};
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
2135
|
+
function translateError(error61) {
|
|
2136
|
+
if (error61 instanceof ManagedAdapterInstallError) {
|
|
2137
|
+
return error61;
|
|
2138
|
+
}
|
|
2139
|
+
if (error61 instanceof ManagedNpmPackageError) {
|
|
2140
|
+
if (error61.code === "package_manager_not_found") {
|
|
2141
|
+
return new ManagedAdapterInstallError(
|
|
2142
|
+
error61.code,
|
|
2143
|
+
"A supported npm executable is required to install the ACP adapter",
|
|
2144
|
+
{ cause: error61 }
|
|
2145
|
+
);
|
|
2146
|
+
}
|
|
2147
|
+
if (error61.code === "managed_package_verification_failed") {
|
|
2148
|
+
return new ManagedAdapterInstallError(
|
|
2149
|
+
"adapter_verification_failed",
|
|
2150
|
+
"The managed adapter did not match its pinned artifact",
|
|
2151
|
+
{ cause: error61 }
|
|
2152
|
+
);
|
|
2153
|
+
}
|
|
2154
|
+
if (error61.code === "managed_package_publish_failed") {
|
|
2155
|
+
return new ManagedAdapterInstallError(
|
|
2156
|
+
"adapter_publish_failed",
|
|
2157
|
+
"The managed adapter could not be published",
|
|
2158
|
+
{ cause: error61 }
|
|
2159
|
+
);
|
|
2160
|
+
}
|
|
2161
|
+
}
|
|
2162
|
+
return new ManagedAdapterInstallError(
|
|
2163
|
+
"adapter_install_failed",
|
|
2164
|
+
"The pinned ACP adapter could not be installed",
|
|
2165
|
+
{ cause: error61 }
|
|
2166
|
+
);
|
|
2167
|
+
}
|
|
2168
|
+
async function validateManagedAdapter(root, specification) {
|
|
2169
|
+
try {
|
|
2170
|
+
return await validateManagedNpmPackage(
|
|
2171
|
+
root,
|
|
2172
|
+
specification.adapterPackageDefinition
|
|
2173
|
+
);
|
|
2174
|
+
} catch (error61) {
|
|
2175
|
+
throw translateError(error61);
|
|
2176
|
+
}
|
|
2177
|
+
}
|
|
2178
|
+
var ManagedAdapterInstaller = class {
|
|
2179
|
+
#environment;
|
|
2180
|
+
#npmInstaller;
|
|
2181
|
+
#stateDirectory;
|
|
2182
|
+
constructor(options, npmInstaller = new ManagedNpmPackageInstaller()) {
|
|
2183
|
+
this.#environment = options.environment;
|
|
2184
|
+
this.#npmInstaller = npmInstaller;
|
|
2185
|
+
this.#stateDirectory = options.stateDirectory;
|
|
2186
|
+
}
|
|
2187
|
+
install = async (specification, signal) => {
|
|
2188
|
+
const root = join10(
|
|
2189
|
+
this.#stateDirectory,
|
|
2190
|
+
"adapters",
|
|
2191
|
+
specification.id,
|
|
2192
|
+
specification.adapterVersion
|
|
2193
|
+
);
|
|
2194
|
+
try {
|
|
2195
|
+
return await this.#npmInstaller.install(
|
|
2196
|
+
root,
|
|
2197
|
+
specification.adapterPackageDefinition,
|
|
2198
|
+
this.#environment,
|
|
2199
|
+
signal
|
|
2200
|
+
);
|
|
2201
|
+
} catch (error61) {
|
|
2202
|
+
if (signal.aborted) {
|
|
2203
|
+
signal.throwIfAborted();
|
|
2204
|
+
}
|
|
2205
|
+
throw translateError(error61);
|
|
2206
|
+
}
|
|
2207
|
+
};
|
|
1203
2208
|
};
|
|
1204
|
-
|
|
2209
|
+
|
|
2210
|
+
// src/agent-catalog/executable-discovery.ts
|
|
2211
|
+
async function resolveManagedExecutable(specification, context) {
|
|
1205
2212
|
try {
|
|
1206
2213
|
return await specification.resolveManagedAgent(
|
|
1207
|
-
readStateDirectory(
|
|
1208
|
-
|
|
2214
|
+
readStateDirectory(context.environment),
|
|
2215
|
+
context.platform ?? process.platform,
|
|
2216
|
+
context.signal
|
|
1209
2217
|
);
|
|
1210
2218
|
} catch {
|
|
2219
|
+
context.signal.throwIfAborted();
|
|
1211
2220
|
return null;
|
|
1212
2221
|
}
|
|
1213
2222
|
}
|
|
1214
|
-
async function resolveManagedAdapterExecutable(specification,
|
|
2223
|
+
async function resolveManagedAdapterExecutable(specification, context) {
|
|
1215
2224
|
let managed;
|
|
1216
2225
|
try {
|
|
1217
2226
|
managed = await validateManagedAdapter(
|
|
1218
|
-
|
|
1219
|
-
readStateDirectory(
|
|
2227
|
+
join11(
|
|
2228
|
+
readStateDirectory(context.environment),
|
|
1220
2229
|
"adapters",
|
|
1221
2230
|
specification.id,
|
|
1222
2231
|
specification.adapterVersion
|
|
@@ -1228,19 +2237,19 @@ async function resolveManagedAdapterExecutable(specification, options) {
|
|
|
1228
2237
|
}
|
|
1229
2238
|
return managed;
|
|
1230
2239
|
}
|
|
1231
|
-
async function resolveSpecificationExecutables(executableName, overrideVariable, resolveManaged,
|
|
1232
|
-
const override =
|
|
2240
|
+
async function resolveSpecificationExecutables(executableName, overrideVariable, resolveManaged, context) {
|
|
2241
|
+
const override = context.environment[overrideVariable];
|
|
1233
2242
|
if (override !== void 0) {
|
|
1234
|
-
if (override.length === 0 || !
|
|
2243
|
+
if (override.length === 0 || !isAbsolute4(override)) {
|
|
1235
2244
|
return [];
|
|
1236
2245
|
}
|
|
1237
|
-
const executable = await resolveExecutablePath(override,
|
|
2246
|
+
const executable = await resolveExecutablePath(override, context.platform);
|
|
1238
2247
|
return executable === null ? [] : [executable];
|
|
1239
2248
|
}
|
|
1240
2249
|
const external = await findExecutableOnPath(
|
|
1241
2250
|
executableName,
|
|
1242
|
-
|
|
1243
|
-
|
|
2251
|
+
context.environment,
|
|
2252
|
+
context.platform
|
|
1244
2253
|
);
|
|
1245
2254
|
const managed = await resolveManaged();
|
|
1246
2255
|
if (external === null) {
|
|
@@ -1251,41 +2260,47 @@ async function resolveSpecificationExecutables(executableName, overrideVariable,
|
|
|
1251
2260
|
}
|
|
1252
2261
|
return [external, managed];
|
|
1253
2262
|
}
|
|
1254
|
-
async function resolveAgentExecutables(specification,
|
|
2263
|
+
async function resolveAgentExecutables(specification, context) {
|
|
1255
2264
|
return await resolveSpecificationExecutables(
|
|
1256
2265
|
specification.agentExecutable,
|
|
1257
2266
|
specification.agentOverrideVariable,
|
|
1258
|
-
async () => await resolveManagedExecutable(specification,
|
|
1259
|
-
|
|
2267
|
+
async () => await resolveManagedExecutable(specification, context),
|
|
2268
|
+
context
|
|
1260
2269
|
);
|
|
1261
2270
|
}
|
|
1262
|
-
async function resolveAdapterExecutables(specification,
|
|
2271
|
+
async function resolveAdapterExecutables(specification, context) {
|
|
2272
|
+
if (specification instanceof DirectAcpAgentDefinition) {
|
|
2273
|
+
return await resolveAgentExecutables(specification, context);
|
|
2274
|
+
}
|
|
2275
|
+
if (!(specification instanceof BridgedAcpAgentDefinition)) {
|
|
2276
|
+
throw new Error("Unsupported local Agent execution topology");
|
|
2277
|
+
}
|
|
1263
2278
|
return await resolveSpecificationExecutables(
|
|
1264
2279
|
specification.adapterExecutable,
|
|
1265
2280
|
specification.adapterOverrideVariable,
|
|
1266
|
-
async () => await resolveManagedAdapterExecutable(specification,
|
|
1267
|
-
|
|
2281
|
+
async () => await resolveManagedAdapterExecutable(specification, context),
|
|
2282
|
+
context
|
|
1268
2283
|
);
|
|
1269
2284
|
}
|
|
1270
|
-
async function resolveAgentExecutable(specification,
|
|
1271
|
-
const executables = await resolveAgentExecutables(specification,
|
|
2285
|
+
async function resolveAgentExecutable(specification, context) {
|
|
2286
|
+
const executables = await resolveAgentExecutables(specification, context);
|
|
1272
2287
|
return executables[0] ?? null;
|
|
1273
2288
|
}
|
|
1274
|
-
async function resolveAdapterExecutable(specification,
|
|
1275
|
-
const executables = await resolveAdapterExecutables(specification,
|
|
2289
|
+
async function resolveAdapterExecutable(specification, context) {
|
|
2290
|
+
const executables = await resolveAdapterExecutables(specification, context);
|
|
1276
2291
|
return executables[0] ?? null;
|
|
1277
2292
|
}
|
|
1278
2293
|
function normalizedVersion(output2) {
|
|
1279
2294
|
return output2.trim().split(/\r?\n/, 1)[0]?.trim().slice(0, 128) ?? "";
|
|
1280
2295
|
}
|
|
1281
|
-
async function probeVersion(executable, arguments_, environment, defaultWorkspace, signal) {
|
|
2296
|
+
async function probeVersion(executable, arguments_, environment, defaultWorkspace, signal, timeoutMilliseconds) {
|
|
1282
2297
|
const result = await runBoundedProcess({
|
|
1283
2298
|
arguments: arguments_,
|
|
1284
2299
|
command: executable.path,
|
|
1285
2300
|
cwd: defaultWorkspace,
|
|
1286
2301
|
environment,
|
|
1287
2302
|
signal,
|
|
1288
|
-
timeoutMilliseconds
|
|
2303
|
+
timeoutMilliseconds
|
|
1289
2304
|
});
|
|
1290
2305
|
const version2 = normalizedVersion(result.stdout || result.stderr);
|
|
1291
2306
|
if (version2.length === 0) {
|
|
@@ -1304,63 +2319,73 @@ var VerifiedAgentExecutable = class {
|
|
|
1304
2319
|
this.version = version2;
|
|
1305
2320
|
}
|
|
1306
2321
|
};
|
|
1307
|
-
async function findVerifiedAgentExecutable(specification,
|
|
1308
|
-
const executables = await resolveAgentExecutables(specification,
|
|
2322
|
+
async function findVerifiedAgentExecutable(specification, context) {
|
|
2323
|
+
const executables = await resolveAgentExecutables(specification, context);
|
|
1309
2324
|
for (const executable of executables) {
|
|
1310
2325
|
try {
|
|
1311
2326
|
const version2 = await probeVersion(
|
|
1312
2327
|
executable,
|
|
1313
2328
|
specification.agentVersionArguments,
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
2329
|
+
context.environment,
|
|
2330
|
+
context.defaultWorkspace,
|
|
2331
|
+
context.signal,
|
|
2332
|
+
specification.versionProbeTimeoutMilliseconds
|
|
1317
2333
|
);
|
|
1318
2334
|
return new VerifiedAgentExecutable(executable, version2);
|
|
1319
2335
|
} catch {
|
|
1320
|
-
if (
|
|
1321
|
-
|
|
2336
|
+
if (context.signal.aborted) {
|
|
2337
|
+
context.signal.throwIfAborted();
|
|
1322
2338
|
}
|
|
1323
2339
|
}
|
|
1324
2340
|
}
|
|
1325
2341
|
return null;
|
|
1326
2342
|
}
|
|
2343
|
+
|
|
2344
|
+
// src/agent-catalog/acp-readiness-probe.ts
|
|
2345
|
+
var ACP_OUTPUT_LIMIT_BYTES = 1024 * 1024;
|
|
2346
|
+
var DiscoveryAcpHandler = class {
|
|
2347
|
+
onElicitation = (_request, _signal) => Promise.reject(new Error("ACP probe does not accept elicitations"));
|
|
2348
|
+
onElicitationComplete = (_notification) => Promise.resolve();
|
|
2349
|
+
onPermission = (_request, _signal) => Promise.reject(new Error("ACP probe does not grant permissions"));
|
|
2350
|
+
onUpdate = (_notification) => Promise.resolve();
|
|
2351
|
+
};
|
|
1327
2352
|
function readableAcpStream(input2) {
|
|
1328
2353
|
let byteLength = 0;
|
|
1329
|
-
let
|
|
2354
|
+
let open7 = true;
|
|
1330
2355
|
return new ReadableStream({
|
|
1331
2356
|
start(controller) {
|
|
1332
2357
|
input2.on("data", (chunk) => {
|
|
1333
|
-
if (!
|
|
2358
|
+
if (!open7) {
|
|
1334
2359
|
return;
|
|
1335
2360
|
}
|
|
1336
2361
|
if (!(chunk instanceof Uint8Array)) {
|
|
1337
|
-
|
|
2362
|
+
open7 = false;
|
|
1338
2363
|
controller.error(new Error("ACP adapter produced invalid output"));
|
|
1339
2364
|
return;
|
|
1340
2365
|
}
|
|
1341
2366
|
byteLength += chunk.byteLength;
|
|
1342
2367
|
if (byteLength > ACP_OUTPUT_LIMIT_BYTES) {
|
|
1343
|
-
|
|
2368
|
+
open7 = false;
|
|
1344
2369
|
controller.error(new Error("ACP adapter output limit exceeded"));
|
|
1345
2370
|
return;
|
|
1346
2371
|
}
|
|
1347
2372
|
controller.enqueue(new Uint8Array(chunk));
|
|
1348
2373
|
});
|
|
1349
2374
|
input2.once("end", () => {
|
|
1350
|
-
if (
|
|
1351
|
-
|
|
2375
|
+
if (open7) {
|
|
2376
|
+
open7 = false;
|
|
1352
2377
|
controller.close();
|
|
1353
2378
|
}
|
|
1354
2379
|
});
|
|
1355
2380
|
input2.once("error", (error61) => {
|
|
1356
|
-
if (
|
|
1357
|
-
|
|
2381
|
+
if (open7) {
|
|
2382
|
+
open7 = false;
|
|
1358
2383
|
controller.error(error61);
|
|
1359
2384
|
}
|
|
1360
2385
|
});
|
|
1361
2386
|
},
|
|
1362
2387
|
cancel() {
|
|
1363
|
-
|
|
2388
|
+
open7 = false;
|
|
1364
2389
|
}
|
|
1365
2390
|
});
|
|
1366
2391
|
}
|
|
@@ -1379,7 +2404,7 @@ function writableAcpStream(output2) {
|
|
|
1379
2404
|
}
|
|
1380
2405
|
});
|
|
1381
2406
|
}
|
|
1382
|
-
async function
|
|
2407
|
+
async function probeAcpReadiness(specification, agent, environment, defaultWorkspace, signal) {
|
|
1383
2408
|
signal.throwIfAborted();
|
|
1384
2409
|
const controller = new AbortController();
|
|
1385
2410
|
let timedOut = false;
|
|
@@ -1423,13 +2448,13 @@ async function probeAcp(specification, agent, environment, defaultWorkspace, sig
|
|
|
1423
2448
|
}
|
|
1424
2449
|
};
|
|
1425
2450
|
stderr.on("data", consumeStderr);
|
|
1426
|
-
const connection = createAcpClient(
|
|
1427
|
-
|
|
1428
|
-
);
|
|
2451
|
+
const connection = createAcpClient(
|
|
2452
|
+
new DiscoveryAcpHandler()
|
|
2453
|
+
).connect(ndJsonStream(writableAcpStream(stdin), readableAcpStream(stdout)));
|
|
1429
2454
|
try {
|
|
1430
2455
|
const initialized = await Promise.race([
|
|
1431
2456
|
connection.agent.request(
|
|
1432
|
-
|
|
2457
|
+
methods3.agent.initialize,
|
|
1433
2458
|
{
|
|
1434
2459
|
clientCapabilities: {},
|
|
1435
2460
|
clientInfo: { name: "mobius", version: "0.0.3" },
|
|
@@ -1487,6 +2512,8 @@ async function probeAcp(specification, agent, environment, defaultWorkspace, sig
|
|
|
1487
2512
|
await stopProcessTree(child);
|
|
1488
2513
|
}
|
|
1489
2514
|
}
|
|
2515
|
+
|
|
2516
|
+
// src/agent-catalog/discover-agent.ts
|
|
1490
2517
|
function probeFailure(specification, executableKind, error61) {
|
|
1491
2518
|
if (error61 instanceof AgentProbeError) {
|
|
1492
2519
|
if (error61.code === "authentication_required") {
|
|
@@ -1508,12 +2535,15 @@ function probeFailure(specification, executableKind, error61) {
|
|
|
1508
2535
|
`${executableKind === "agent" ? "Agent" : "Adapter"} probe failed`
|
|
1509
2536
|
);
|
|
1510
2537
|
}
|
|
1511
|
-
async function
|
|
1512
|
-
|
|
2538
|
+
async function discoverAgent(specification, context) {
|
|
2539
|
+
context.signal.throwIfAborted();
|
|
1513
2540
|
const [adapters, agents] = await Promise.all([
|
|
1514
|
-
resolveAdapterExecutables(specification,
|
|
1515
|
-
resolveAgentExecutables(specification,
|
|
2541
|
+
resolveAdapterExecutables(specification, context),
|
|
2542
|
+
resolveAgentExecutables(specification, context)
|
|
1516
2543
|
]);
|
|
2544
|
+
if (specification instanceof DirectAcpAgentDefinition && agents.length === 0) {
|
|
2545
|
+
return new MissingAgent(specification);
|
|
2546
|
+
}
|
|
1517
2547
|
if (adapters.length === 0) {
|
|
1518
2548
|
return new MissingAdapter(specification);
|
|
1519
2549
|
}
|
|
@@ -1527,35 +2557,45 @@ async function discoverSpecification(specification, options) {
|
|
|
1527
2557
|
agentVersion = await probeVersion(
|
|
1528
2558
|
agent,
|
|
1529
2559
|
specification.agentVersionArguments,
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
2560
|
+
context.environment,
|
|
2561
|
+
context.defaultWorkspace,
|
|
2562
|
+
context.signal,
|
|
2563
|
+
specification.versionProbeTimeoutMilliseconds
|
|
1533
2564
|
);
|
|
1534
2565
|
} catch (error61) {
|
|
1535
|
-
if (
|
|
1536
|
-
|
|
2566
|
+
if (context.signal.aborted) {
|
|
2567
|
+
context.signal.throwIfAborted();
|
|
1537
2568
|
}
|
|
1538
2569
|
lastFailure = probeFailure(specification, "agent", error61);
|
|
1539
2570
|
continue;
|
|
1540
2571
|
}
|
|
1541
2572
|
for (const adapter of adapters) {
|
|
2573
|
+
if (specification instanceof DirectAcpAgentDefinition && adapter.path !== agent.path) {
|
|
2574
|
+
continue;
|
|
2575
|
+
}
|
|
1542
2576
|
let adapterVersion = "";
|
|
2577
|
+
let launchEnvironment;
|
|
1543
2578
|
try {
|
|
2579
|
+
launchEnvironment = await specification.createLaunchEnvironment(
|
|
2580
|
+
agent,
|
|
2581
|
+
context
|
|
2582
|
+
);
|
|
1544
2583
|
if (specification.adapterVersionArguments.length > 0) {
|
|
1545
2584
|
adapterVersion = await probeVersion(
|
|
1546
2585
|
adapter,
|
|
1547
2586
|
specification.adapterVersionArguments,
|
|
1548
2587
|
{
|
|
1549
|
-
...
|
|
1550
|
-
|
|
2588
|
+
...context.environment,
|
|
2589
|
+
...launchEnvironment
|
|
1551
2590
|
},
|
|
1552
|
-
|
|
1553
|
-
|
|
2591
|
+
context.defaultWorkspace,
|
|
2592
|
+
context.signal,
|
|
2593
|
+
specification.versionProbeTimeoutMilliseconds
|
|
1554
2594
|
);
|
|
1555
2595
|
}
|
|
1556
2596
|
} catch (error61) {
|
|
1557
|
-
if (
|
|
1558
|
-
|
|
2597
|
+
if (context.signal.aborted) {
|
|
2598
|
+
context.signal.throwIfAborted();
|
|
1559
2599
|
}
|
|
1560
2600
|
lastFailure = probeFailure(specification, "adapter", error61);
|
|
1561
2601
|
continue;
|
|
@@ -1564,8 +2604,8 @@ async function discoverSpecification(specification, options) {
|
|
|
1564
2604
|
specification.id,
|
|
1565
2605
|
specification.label,
|
|
1566
2606
|
adapter.path,
|
|
1567
|
-
|
|
1568
|
-
|
|
2607
|
+
specification.launchArguments,
|
|
2608
|
+
launchEnvironment,
|
|
1569
2609
|
adapterVersion,
|
|
1570
2610
|
agentVersion,
|
|
1571
2611
|
adapter.identity,
|
|
@@ -1573,12 +2613,12 @@ async function discoverSpecification(specification, options) {
|
|
|
1573
2613
|
specification.promptTimeoutMilliseconds
|
|
1574
2614
|
);
|
|
1575
2615
|
try {
|
|
1576
|
-
const acpVersion = await
|
|
2616
|
+
const acpVersion = await probeAcpReadiness(
|
|
1577
2617
|
specification,
|
|
1578
2618
|
definition,
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
2619
|
+
context.environment,
|
|
2620
|
+
context.defaultWorkspace,
|
|
2621
|
+
context.signal
|
|
1582
2622
|
);
|
|
1583
2623
|
const verifiedAdapterVersion = adapterVersion.length > 0 ? adapterVersion : acpVersion;
|
|
1584
2624
|
if (verifiedAdapterVersion.length === 0) {
|
|
@@ -1593,8 +2633,8 @@ async function discoverSpecification(specification, options) {
|
|
|
1593
2633
|
specification.id,
|
|
1594
2634
|
specification.label,
|
|
1595
2635
|
adapter.path,
|
|
1596
|
-
|
|
1597
|
-
|
|
2636
|
+
specification.launchArguments,
|
|
2637
|
+
launchEnvironment,
|
|
1598
2638
|
verifiedAdapterVersion,
|
|
1599
2639
|
agentVersion,
|
|
1600
2640
|
adapter.identity,
|
|
@@ -1603,20 +2643,26 @@ async function discoverSpecification(specification, options) {
|
|
|
1603
2643
|
)
|
|
1604
2644
|
);
|
|
1605
2645
|
} catch (error61) {
|
|
1606
|
-
if (
|
|
1607
|
-
|
|
2646
|
+
if (context.signal.aborted) {
|
|
2647
|
+
context.signal.throwIfAborted();
|
|
1608
2648
|
}
|
|
1609
|
-
|
|
2649
|
+
const failure = probeFailure(specification, "adapter", error61);
|
|
2650
|
+
if (failure instanceof AuthenticationRequiredAgent) {
|
|
2651
|
+
return failure;
|
|
2652
|
+
}
|
|
2653
|
+
lastFailure = failure;
|
|
1610
2654
|
}
|
|
1611
2655
|
}
|
|
1612
2656
|
}
|
|
1613
2657
|
return lastFailure ?? new IncompatibleAdapter(specification);
|
|
1614
2658
|
}
|
|
2659
|
+
|
|
2660
|
+
// src/agent-catalog/discover-local-agents.ts
|
|
1615
2661
|
async function discoverLocalAgentInventory(options) {
|
|
1616
2662
|
const specifications = options.specifications ?? supportedLocalAgentSpecifications();
|
|
1617
2663
|
const discoveries = await Promise.all(
|
|
1618
2664
|
specifications.map(
|
|
1619
|
-
async (specification) => await
|
|
2665
|
+
async (specification) => await discoverAgent(specification, options)
|
|
1620
2666
|
)
|
|
1621
2667
|
);
|
|
1622
2668
|
let grantedAgents = /* @__PURE__ */ new Set();
|
|
@@ -1634,89 +2680,14 @@ async function discoverLocalAgentInventory(options) {
|
|
|
1634
2680
|
);
|
|
1635
2681
|
}
|
|
1636
2682
|
|
|
1637
|
-
// src/agent-catalog/agent-diagnostics.ts
|
|
1638
|
-
var AvailableAgentDiagnostic = class {
|
|
1639
|
-
adapterVersion;
|
|
1640
|
-
agentVersion;
|
|
1641
|
-
id;
|
|
1642
|
-
label;
|
|
1643
|
-
status = "ready";
|
|
1644
|
-
constructor(discovery) {
|
|
1645
|
-
this.adapterVersion = discovery.agent.adapterVersion;
|
|
1646
|
-
this.agentVersion = discovery.agent.agentVersion;
|
|
1647
|
-
this.id = discovery.specification.id;
|
|
1648
|
-
this.label = discovery.specification.label;
|
|
1649
|
-
}
|
|
1650
|
-
};
|
|
1651
|
-
var UnavailableAgentDiagnostic = class {
|
|
1652
|
-
code;
|
|
1653
|
-
id;
|
|
1654
|
-
label;
|
|
1655
|
-
message;
|
|
1656
|
-
recoveryCommand;
|
|
1657
|
-
status;
|
|
1658
|
-
constructor(discovery) {
|
|
1659
|
-
this.code = discovery.code;
|
|
1660
|
-
this.id = discovery.specification.id;
|
|
1661
|
-
this.label = discovery.specification.label;
|
|
1662
|
-
this.message = discovery.message;
|
|
1663
|
-
this.recoveryCommand = discovery instanceof MissingAdapter ? discovery.specification.recoveryCommand() : discovery.code === "authentication_required" ? discovery.specification.authenticationCommand() : "";
|
|
1664
|
-
this.status = discovery.status;
|
|
1665
|
-
}
|
|
1666
|
-
};
|
|
1667
|
-
var AgentDiagnostics = class {
|
|
1668
|
-
available;
|
|
1669
|
-
unavailable;
|
|
1670
|
-
constructor(inventory) {
|
|
1671
|
-
this.available = inventory.available.map(
|
|
1672
|
-
(discovery) => new AvailableAgentDiagnostic(discovery)
|
|
1673
|
-
);
|
|
1674
|
-
this.unavailable = inventory.unavailable.map(
|
|
1675
|
-
(discovery) => new UnavailableAgentDiagnostic(discovery)
|
|
1676
|
-
);
|
|
1677
|
-
}
|
|
1678
|
-
};
|
|
1679
|
-
function humanLine(label, status, detail) {
|
|
1680
|
-
return `${label.padEnd(13)} ${status.padEnd(17)} ${detail}`.trimEnd();
|
|
1681
|
-
}
|
|
1682
|
-
function formatAgentDiagnostics(inventory, json2) {
|
|
1683
|
-
const diagnostics = new AgentDiagnostics(inventory);
|
|
1684
|
-
if (json2) {
|
|
1685
|
-
return `${JSON.stringify(diagnostics, null, 2)}
|
|
1686
|
-
`;
|
|
1687
|
-
}
|
|
1688
|
-
const lines = [];
|
|
1689
|
-
for (const available of diagnostics.available) {
|
|
1690
|
-
lines.push(
|
|
1691
|
-
humanLine(
|
|
1692
|
-
available.label,
|
|
1693
|
-
available.status,
|
|
1694
|
-
`${available.agentVersion} ${available.adapterVersion}`
|
|
1695
|
-
)
|
|
1696
|
-
);
|
|
1697
|
-
}
|
|
1698
|
-
for (const unavailable of diagnostics.unavailable) {
|
|
1699
|
-
lines.push(
|
|
1700
|
-
humanLine(unavailable.label, unavailable.status, unavailable.message)
|
|
1701
|
-
);
|
|
1702
|
-
if (unavailable.recoveryCommand.length > 0) {
|
|
1703
|
-
lines.push(
|
|
1704
|
-
unavailable.code === "authentication_required" ? ` Authenticate locally: ${unavailable.recoveryCommand}` : ` Install adapter: ${unavailable.recoveryCommand}`
|
|
1705
|
-
);
|
|
1706
|
-
}
|
|
1707
|
-
}
|
|
1708
|
-
return `${lines.join("\n")}
|
|
1709
|
-
`;
|
|
1710
|
-
}
|
|
1711
|
-
|
|
1712
2683
|
// src/audit/audit-store.ts
|
|
1713
2684
|
import { mkdirSync } from "node:fs";
|
|
1714
|
-
import { dirname as
|
|
2685
|
+
import { dirname as dirname3 } from "node:path";
|
|
1715
2686
|
import { DatabaseSync } from "node:sqlite";
|
|
1716
2687
|
var AuditStore = class {
|
|
1717
2688
|
database;
|
|
1718
2689
|
constructor(path2) {
|
|
1719
|
-
mkdirSync(
|
|
2690
|
+
mkdirSync(dirname3(path2), { recursive: true });
|
|
1720
2691
|
this.database = new DatabaseSync(path2);
|
|
1721
2692
|
this.database.exec(`
|
|
1722
2693
|
CREATE TABLE IF NOT EXISTS audit_events (
|
|
@@ -1760,10 +2731,10 @@ var AuditStore = class {
|
|
|
1760
2731
|
};
|
|
1761
2732
|
|
|
1762
2733
|
// src/config.ts
|
|
1763
|
-
import { join as
|
|
2734
|
+
import { join as join12 } from "node:path";
|
|
1764
2735
|
function loadDefaultWorkspace() {
|
|
1765
2736
|
const { MOBIUS_DEFAULT_WORKSPACE: configuredWorkspace } = process.env;
|
|
1766
|
-
return configuredWorkspace ??
|
|
2737
|
+
return configuredWorkspace ?? join12(readStateDirectory(), "workspace");
|
|
1767
2738
|
}
|
|
1768
2739
|
function createDaemonConfig(connection, agents = [], installableAgents = []) {
|
|
1769
2740
|
return {
|
|
@@ -1781,22 +2752,16 @@ function createDaemonConfig(connection, agents = [], installableAgents = []) {
|
|
|
1781
2752
|
// src/pairing/pair-local-machine.ts
|
|
1782
2753
|
import { randomUUID } from "node:crypto";
|
|
1783
2754
|
import {
|
|
1784
|
-
mkdir as
|
|
1785
|
-
open as
|
|
1786
|
-
realpath as
|
|
1787
|
-
rename as
|
|
1788
|
-
stat as
|
|
1789
|
-
writeFile
|
|
2755
|
+
mkdir as mkdir3,
|
|
2756
|
+
open as open5,
|
|
2757
|
+
realpath as realpath5,
|
|
2758
|
+
rename as rename3,
|
|
2759
|
+
stat as stat5,
|
|
2760
|
+
writeFile as writeFile2
|
|
1790
2761
|
} from "node:fs/promises";
|
|
1791
2762
|
import { hostname } from "node:os";
|
|
1792
|
-
import { basename, join as
|
|
1793
|
-
import { fetch } from "undici";
|
|
1794
|
-
|
|
1795
|
-
// src/network/environment-proxy.ts
|
|
1796
|
-
import { EnvHttpProxyAgent } from "undici";
|
|
1797
|
-
var environmentProxyDispatcher = new EnvHttpProxyAgent();
|
|
1798
|
-
|
|
1799
|
-
// src/pairing/pair-local-machine.ts
|
|
2763
|
+
import { basename, join as join13, resolve as resolve3 } from "node:path";
|
|
2764
|
+
import { fetch as fetch2 } from "undici";
|
|
1800
2765
|
var PAIRING_TIMEOUT_MILLISECONDS = 2e4;
|
|
1801
2766
|
var PAIRING_CODE_PATTERN = /^[A-HJ-NP-Z2-9]{4}(?:-[A-HJ-NP-Z2-9]{4}){4}$/;
|
|
1802
2767
|
var IDENTIFIER_PATTERN = /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/;
|
|
@@ -1821,7 +2786,7 @@ var PairingClientError = class extends Error {
|
|
|
1821
2786
|
this.name = "PairingClientError";
|
|
1822
2787
|
}
|
|
1823
2788
|
};
|
|
1824
|
-
function
|
|
2789
|
+
function isRecord4(value) {
|
|
1825
2790
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1826
2791
|
}
|
|
1827
2792
|
function hasExactKeys(value, expectedKeys) {
|
|
@@ -1934,9 +2899,9 @@ function parseChannelArgument(arguments_) {
|
|
|
1934
2899
|
async function resolveDefaultWorkspace(path2) {
|
|
1935
2900
|
const requestedWorkspace = resolve3(path2);
|
|
1936
2901
|
try {
|
|
1937
|
-
await
|
|
1938
|
-
const defaultWorkspace = await
|
|
1939
|
-
const metadata = await
|
|
2902
|
+
await mkdir3(requestedWorkspace, { recursive: true, mode: 448 });
|
|
2903
|
+
const defaultWorkspace = await realpath5(requestedWorkspace);
|
|
2904
|
+
const metadata = await stat5(defaultWorkspace);
|
|
1940
2905
|
if (!metadata.isDirectory()) {
|
|
1941
2906
|
throw new PairingClientError(
|
|
1942
2907
|
"invalid_workspace",
|
|
@@ -1974,9 +2939,9 @@ async function readJsonResponse(response) {
|
|
|
1974
2939
|
}
|
|
1975
2940
|
}
|
|
1976
2941
|
function readRelayError(value) {
|
|
1977
|
-
if (
|
|
2942
|
+
if (isRecord4(value)) {
|
|
1978
2943
|
const error61 = value["error"];
|
|
1979
|
-
if (
|
|
2944
|
+
if (isRecord4(error61)) {
|
|
1980
2945
|
const code = error61["code"];
|
|
1981
2946
|
const message = error61["message"];
|
|
1982
2947
|
if (typeof code === "string" && typeof message === "string") {
|
|
@@ -1990,7 +2955,7 @@ function readRelayError(value) {
|
|
|
1990
2955
|
);
|
|
1991
2956
|
}
|
|
1992
2957
|
function decodeClaimResponse(value) {
|
|
1993
|
-
if (!
|
|
2958
|
+
if (!isRecord4(value) || !hasExactKeys(value, CLAIM_RESPONSE_KEYS)) {
|
|
1994
2959
|
throw new PairingClientError(
|
|
1995
2960
|
"invalid_relay_response",
|
|
1996
2961
|
"The relay returned an invalid pairing response"
|
|
@@ -2012,10 +2977,10 @@ async function claimPairing(options, defaultWorkspace, localAgents, installableA
|
|
|
2012
2977
|
id: agent.id,
|
|
2013
2978
|
label: agent.label
|
|
2014
2979
|
}));
|
|
2015
|
-
const endpoint = new URL("/api/pairings/claim", options.relayOrigin);
|
|
2980
|
+
const endpoint = new URL("/mobius/api/pairings/claim", options.relayOrigin);
|
|
2016
2981
|
let response;
|
|
2017
2982
|
try {
|
|
2018
|
-
response = await
|
|
2983
|
+
response = await fetch2(endpoint, {
|
|
2019
2984
|
body: JSON.stringify({
|
|
2020
2985
|
agents,
|
|
2021
2986
|
installableAgents: installableAgents.map((agent) => ({
|
|
@@ -2049,14 +3014,14 @@ async function claimPairing(options, defaultWorkspace, localAgents, installableA
|
|
|
2049
3014
|
return decodeClaimResponse(value);
|
|
2050
3015
|
}
|
|
2051
3016
|
async function persistConnection(channelId, relayOrigin, daemonToken, defaultWorkspace) {
|
|
2052
|
-
const connectionsDirectory =
|
|
2053
|
-
await
|
|
2054
|
-
const connectionPath =
|
|
2055
|
-
const temporaryPath =
|
|
3017
|
+
const connectionsDirectory = join13(readStateDirectory(), "connections");
|
|
3018
|
+
await mkdir3(connectionsDirectory, { mode: 448, recursive: true });
|
|
3019
|
+
const connectionPath = join13(connectionsDirectory, `${channelId}.json`);
|
|
3020
|
+
const temporaryPath = join13(
|
|
2056
3021
|
connectionsDirectory,
|
|
2057
3022
|
`.${channelId}.${randomUUID()}.tmp`
|
|
2058
3023
|
);
|
|
2059
|
-
await
|
|
3024
|
+
await writeFile2(
|
|
2060
3025
|
temporaryPath,
|
|
2061
3026
|
`${JSON.stringify(
|
|
2062
3027
|
{
|
|
@@ -2071,11 +3036,11 @@ async function persistConnection(channelId, relayOrigin, daemonToken, defaultWor
|
|
|
2071
3036
|
`,
|
|
2072
3037
|
{ flag: "wx", mode: 384 }
|
|
2073
3038
|
);
|
|
2074
|
-
await
|
|
3039
|
+
await rename3(temporaryPath, connectionPath);
|
|
2075
3040
|
return connectionPath;
|
|
2076
3041
|
}
|
|
2077
3042
|
function decodeSavedConnection(value, expectedChannelId) {
|
|
2078
|
-
if (!
|
|
3043
|
+
if (!isRecord4(value) || !hasExactKeys(value, SAVED_CONNECTION_KEYS)) {
|
|
2079
3044
|
throw new PairingClientError(
|
|
2080
3045
|
"invalid_connection",
|
|
2081
3046
|
"The saved connection is invalid"
|
|
@@ -2099,13 +3064,13 @@ function decodeSavedConnection(value, expectedChannelId) {
|
|
|
2099
3064
|
};
|
|
2100
3065
|
}
|
|
2101
3066
|
async function readSavedConnection(channelId) {
|
|
2102
|
-
const connectionPath =
|
|
3067
|
+
const connectionPath = join13(
|
|
2103
3068
|
readStateDirectory(),
|
|
2104
3069
|
"connections",
|
|
2105
3070
|
`${channelId}.json`
|
|
2106
3071
|
);
|
|
2107
3072
|
let encoded = "";
|
|
2108
|
-
const handle = await
|
|
3073
|
+
const handle = await open5(connectionPath, "r");
|
|
2109
3074
|
try {
|
|
2110
3075
|
const metadata = await handle.stat();
|
|
2111
3076
|
if (!metadata.isFile() || metadata.size > MAX_CONNECTION_FILE_LENGTH) {
|
|
@@ -2149,12 +3114,12 @@ function assertInventoryUsable(inventory) {
|
|
|
2149
3114
|
function buildPairedDaemon(connection, connectionPath, inventory) {
|
|
2150
3115
|
assertInventoryUsable(inventory);
|
|
2151
3116
|
const relayUrl = new URL(
|
|
2152
|
-
`/api/channels/${encodeURIComponent(connection.channelId)}/daemon`,
|
|
3117
|
+
`/mobius/api/channels/${encodeURIComponent(connection.channelId)}/daemon`,
|
|
2153
3118
|
connection.relayOrigin
|
|
2154
3119
|
);
|
|
2155
3120
|
relayUrl.protocol = relayUrl.protocol === "https:" ? "wss:" : "ws:";
|
|
2156
3121
|
relayUrl.searchParams.set("token", connection.daemonToken);
|
|
2157
|
-
const auditDatabasePath =
|
|
3122
|
+
const auditDatabasePath = join13(
|
|
2158
3123
|
readStateDirectory(),
|
|
2159
3124
|
"audit",
|
|
2160
3125
|
`${connection.channelId}.sqlite`
|
|
@@ -2213,7 +3178,7 @@ async function pairLocalMachine(arguments_, signal = new AbortController().signa
|
|
|
2213
3178
|
}
|
|
2214
3179
|
async function resumeLocalMachine(arguments_, signal = new AbortController().signal) {
|
|
2215
3180
|
const channelId = parseChannelArgument(arguments_);
|
|
2216
|
-
const connectionPath =
|
|
3181
|
+
const connectionPath = join13(
|
|
2217
3182
|
readStateDirectory(),
|
|
2218
3183
|
"connections",
|
|
2219
3184
|
`${channelId}.json`
|
|
@@ -2229,6 +3194,7 @@ async function resumeLocalMachine(arguments_, signal = new AbortController().sig
|
|
|
2229
3194
|
|
|
2230
3195
|
// src/run-daemon.ts
|
|
2231
3196
|
import { basename as basename3 } from "node:path";
|
|
3197
|
+
import { styleText } from "node:util";
|
|
2232
3198
|
|
|
2233
3199
|
// ../../node_modules/.pnpm/zod@4.5.4/node_modules/zod/v4/classic/external.js
|
|
2234
3200
|
var external_exports = {};
|
|
@@ -7248,7 +8214,7 @@ function bucketFor(state, inst) {
|
|
|
7248
8214
|
return bucket;
|
|
7249
8215
|
}
|
|
7250
8216
|
var handoff;
|
|
7251
|
-
var
|
|
8217
|
+
var open6 = [];
|
|
7252
8218
|
var memo = {
|
|
7253
8219
|
alloc(_inst, payload, empty) {
|
|
7254
8220
|
const bucket = handoff;
|
|
@@ -7257,7 +8223,7 @@ var memo = {
|
|
|
7257
8223
|
handoff = void 0;
|
|
7258
8224
|
const entry = { value: empty, issues: null };
|
|
7259
8225
|
bucket.set(payload.value, entry);
|
|
7260
|
-
|
|
8226
|
+
open6.push(entry);
|
|
7261
8227
|
return empty;
|
|
7262
8228
|
},
|
|
7263
8229
|
guard(inst) {
|
|
@@ -7323,10 +8289,10 @@ var memo = {
|
|
|
7323
8289
|
return payload;
|
|
7324
8290
|
}
|
|
7325
8291
|
handoff = bucket;
|
|
7326
|
-
const depth =
|
|
8292
|
+
const depth = open6.length;
|
|
7327
8293
|
const result = base(payload, ctx);
|
|
7328
8294
|
handoff = void 0;
|
|
7329
|
-
const entry =
|
|
8295
|
+
const entry = open6.length > depth ? open6.pop() : void 0;
|
|
7330
8296
|
if (result instanceof Promise) {
|
|
7331
8297
|
return result.then((r) => {
|
|
7332
8298
|
if (entry)
|
|
@@ -21615,7 +22581,7 @@ var ProtocolMessageError = class extends Error {
|
|
|
21615
22581
|
this.name = "ProtocolMessageError";
|
|
21616
22582
|
}
|
|
21617
22583
|
};
|
|
21618
|
-
function
|
|
22584
|
+
function isRecord5(value) {
|
|
21619
22585
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
21620
22586
|
}
|
|
21621
22587
|
function parseJson2(encoded) {
|
|
@@ -21627,7 +22593,7 @@ function parseJson2(encoded) {
|
|
|
21627
22593
|
cause: error61
|
|
21628
22594
|
});
|
|
21629
22595
|
}
|
|
21630
|
-
if (!
|
|
22596
|
+
if (!isRecord5(value)) {
|
|
21631
22597
|
throw new ProtocolMessageError("Message must be a JSON object");
|
|
21632
22598
|
}
|
|
21633
22599
|
return value;
|
|
@@ -21711,7 +22677,7 @@ function readActivityContent(value) {
|
|
|
21711
22677
|
}
|
|
21712
22678
|
function readActivityDetail(value) {
|
|
21713
22679
|
const field = value["detail"];
|
|
21714
|
-
if (!
|
|
22680
|
+
if (!isRecord5(field)) {
|
|
21715
22681
|
throw new ProtocolMessageError("Invalid activity detail field");
|
|
21716
22682
|
}
|
|
21717
22683
|
const kind = readString(field, "kind", 32);
|
|
@@ -22002,7 +22968,10 @@ var sessionHistorySchema = external_exports.discriminatedUnion("status", [
|
|
|
22002
22968
|
status: external_exports.literal("available"),
|
|
22003
22969
|
messages: external_exports.array(historyMessage).max(SESSION_HISTORY_MESSAGE_LIMIT).readonly(),
|
|
22004
22970
|
truncated: external_exports.boolean(),
|
|
22005
|
-
coveredCommandIds: external_exports.array(external_exports.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/)).max(1e4).readonly()
|
|
22971
|
+
coveredCommandIds: external_exports.array(external_exports.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/)).max(1e4).readonly(),
|
|
22972
|
+
coveredMessageIds: external_exports.array(
|
|
22973
|
+
external_exports.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}:(?:user|agent)$/)
|
|
22974
|
+
).max(2e4).readonly().default([])
|
|
22006
22975
|
}).readonly(),
|
|
22007
22976
|
external_exports.strictObject({ status: external_exports.literal("unavailable") }).readonly()
|
|
22008
22977
|
]).refine(
|
|
@@ -22676,14 +23645,15 @@ import { WebSocket as WebSocket2 } from "undici";
|
|
|
22676
23645
|
// src/acp/session-manager.ts
|
|
22677
23646
|
import { spawn as spawn3 } from "node:child_process";
|
|
22678
23647
|
import {
|
|
22679
|
-
methods as
|
|
23648
|
+
methods as methods4,
|
|
22680
23649
|
ndJsonStream as ndJsonStream2,
|
|
22681
|
-
PROTOCOL_VERSION as PROTOCOL_VERSION2
|
|
23650
|
+
PROTOCOL_VERSION as PROTOCOL_VERSION2,
|
|
23651
|
+
RequestError as RequestError2
|
|
22682
23652
|
} from "@agentclientprotocol/sdk";
|
|
22683
23653
|
|
|
22684
23654
|
// src/acp/activity.ts
|
|
22685
23655
|
var TRUNCATION_MARKER = "\n\u2026 output truncated by Mobius";
|
|
22686
|
-
function
|
|
23656
|
+
function isRecord6(value) {
|
|
22687
23657
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
22688
23658
|
}
|
|
22689
23659
|
var AcpActivity = class _AcpActivity {
|
|
@@ -22957,7 +23927,7 @@ function contentPhase(content) {
|
|
|
22957
23927
|
return "";
|
|
22958
23928
|
}
|
|
22959
23929
|
const codex = metadata["codex"];
|
|
22960
|
-
if (!
|
|
23930
|
+
if (!isRecord6(codex)) {
|
|
22961
23931
|
return "";
|
|
22962
23932
|
}
|
|
22963
23933
|
const phase = codex["phase"];
|
|
@@ -23252,13 +24222,14 @@ var AcpHistoryReplay = class {
|
|
|
23252
24222
|
status: "available",
|
|
23253
24223
|
messages: [...this.#messages],
|
|
23254
24224
|
truncated: this.#truncated,
|
|
23255
|
-
coveredCommandIds: []
|
|
24225
|
+
coveredCommandIds: [],
|
|
24226
|
+
coveredMessageIds: []
|
|
23256
24227
|
});
|
|
23257
24228
|
};
|
|
23258
24229
|
|
|
23259
24230
|
// src/acp/session-store.ts
|
|
23260
24231
|
import { mkdirSync as mkdirSync2 } from "node:fs";
|
|
23261
|
-
import { dirname as
|
|
24232
|
+
import { dirname as dirname4 } from "node:path";
|
|
23262
24233
|
import { DatabaseSync as DatabaseSync2 } from "node:sqlite";
|
|
23263
24234
|
var AcpStoredSession = class {
|
|
23264
24235
|
additionalDirectories;
|
|
@@ -23361,7 +24332,7 @@ var MemoryAcpSessionStore = class {
|
|
|
23361
24332
|
var SqliteAcpSessionStore = class {
|
|
23362
24333
|
#database;
|
|
23363
24334
|
constructor(path2) {
|
|
23364
|
-
mkdirSync2(
|
|
24335
|
+
mkdirSync2(dirname4(path2), { recursive: true });
|
|
23365
24336
|
this.#database = new DatabaseSync2(path2);
|
|
23366
24337
|
this.#database.exec(`
|
|
23367
24338
|
CREATE TABLE IF NOT EXISTS acp_deleted_sessions (session_id TEXT PRIMARY KEY) STRICT;
|
|
@@ -23468,6 +24439,8 @@ var SqliteAcpSessionStore = class {
|
|
|
23468
24439
|
|
|
23469
24440
|
// src/acp/session-manager.ts
|
|
23470
24441
|
var PROCESS_STOP_TIMEOUT_MILLISECONDS = 1e3;
|
|
24442
|
+
var MAX_PRE_SESSION_UPDATES = 100;
|
|
24443
|
+
var MAX_PRE_SESSION_UPDATE_BYTES = 1024 * 1024;
|
|
23471
24444
|
var SESSION_CONTROL_COMMAND_ID = "session-control";
|
|
23472
24445
|
var NullAcpSessionObserver = class {
|
|
23473
24446
|
onCommands = () => Promise.resolve();
|
|
@@ -23588,7 +24561,7 @@ function createWritableAcpStream(output2) {
|
|
|
23588
24561
|
function truncate2(value, maximumLength) {
|
|
23589
24562
|
return value.length <= maximumLength ? value : `${value.slice(0, Math.max(0, maximumLength - 1))}\u2026`;
|
|
23590
24563
|
}
|
|
23591
|
-
function
|
|
24564
|
+
function isRecord7(value) {
|
|
23592
24565
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
23593
24566
|
}
|
|
23594
24567
|
function readString3(value, fallback = "") {
|
|
@@ -23618,7 +24591,7 @@ function normalizeConfigValues(value) {
|
|
|
23618
24591
|
}
|
|
23619
24592
|
const normalized = [];
|
|
23620
24593
|
for (const entry of value) {
|
|
23621
|
-
if (!
|
|
24594
|
+
if (!isRecord7(entry)) {
|
|
23622
24595
|
continue;
|
|
23623
24596
|
}
|
|
23624
24597
|
const groupedOptions = entry["options"];
|
|
@@ -23626,7 +24599,7 @@ function normalizeConfigValues(value) {
|
|
|
23626
24599
|
const groupId = readString3(entry["group"]);
|
|
23627
24600
|
const groupName = readString3(entry["name"]);
|
|
23628
24601
|
for (const groupedOption of groupedOptions) {
|
|
23629
|
-
if (
|
|
24602
|
+
if (isRecord7(groupedOption)) {
|
|
23630
24603
|
normalized.push(
|
|
23631
24604
|
normalizeConfigValue(groupedOption, groupId, groupName)
|
|
23632
24605
|
);
|
|
@@ -23642,7 +24615,7 @@ function normalizeConfigOptions(value, modes) {
|
|
|
23642
24615
|
const normalized = [];
|
|
23643
24616
|
if (Array.isArray(value)) {
|
|
23644
24617
|
for (const option of value) {
|
|
23645
|
-
if (!
|
|
24618
|
+
if (!isRecord7(option)) {
|
|
23646
24619
|
continue;
|
|
23647
24620
|
}
|
|
23648
24621
|
const id = truncate2(readString3(option["id"]), 128);
|
|
@@ -23681,12 +24654,12 @@ function normalizeConfigOptions(value, modes) {
|
|
|
23681
24654
|
}
|
|
23682
24655
|
}
|
|
23683
24656
|
}
|
|
23684
|
-
if (
|
|
24657
|
+
if (isRecord7(modes)) {
|
|
23685
24658
|
const values = [];
|
|
23686
24659
|
const availableModes = modes["availableModes"];
|
|
23687
24660
|
if (Array.isArray(availableModes)) {
|
|
23688
24661
|
for (const mode of availableModes) {
|
|
23689
|
-
if (!
|
|
24662
|
+
if (!isRecord7(mode)) {
|
|
23690
24663
|
continue;
|
|
23691
24664
|
}
|
|
23692
24665
|
const id = truncate2(readString3(mode["id"]), 500);
|
|
@@ -23764,7 +24737,7 @@ function normalizeElicitationOptions(schema) {
|
|
|
23764
24737
|
const oneOf = schema["oneOf"];
|
|
23765
24738
|
if (Array.isArray(oneOf)) {
|
|
23766
24739
|
for (const option of oneOf) {
|
|
23767
|
-
if (
|
|
24740
|
+
if (isRecord7(option) && typeof option["const"] === "string") {
|
|
23768
24741
|
normalized.push({
|
|
23769
24742
|
description: truncate2(readString3(option["description"]), 500),
|
|
23770
24743
|
label: truncate2(readString3(option["title"], option["const"]), 255),
|
|
@@ -23784,7 +24757,7 @@ function normalizeElicitationOptions(schema) {
|
|
|
23784
24757
|
return normalized.slice(0, 200);
|
|
23785
24758
|
}
|
|
23786
24759
|
const items = schema["items"];
|
|
23787
|
-
if (!
|
|
24760
|
+
if (!isRecord7(items)) {
|
|
23788
24761
|
return normalized;
|
|
23789
24762
|
}
|
|
23790
24763
|
const anyOf = items["anyOf"];
|
|
@@ -23797,7 +24770,7 @@ function numericString(value) {
|
|
|
23797
24770
|
return typeof value === "number" && Number.isFinite(value) ? value.toString() : "";
|
|
23798
24771
|
}
|
|
23799
24772
|
function normalizeElicitationFields(requestedSchema) {
|
|
23800
|
-
if (!
|
|
24773
|
+
if (!isRecord7(requestedSchema) || !isRecord7(requestedSchema["properties"])) {
|
|
23801
24774
|
return [];
|
|
23802
24775
|
}
|
|
23803
24776
|
const properties = requestedSchema["properties"];
|
|
@@ -23807,7 +24780,7 @@ function normalizeElicitationFields(requestedSchema) {
|
|
|
23807
24780
|
);
|
|
23808
24781
|
const normalized = [];
|
|
23809
24782
|
for (const [name, property] of Object.entries(properties)) {
|
|
23810
|
-
if (!
|
|
24783
|
+
if (!isRecord7(property)) {
|
|
23811
24784
|
continue;
|
|
23812
24785
|
}
|
|
23813
24786
|
const type = elicitationFieldType(property["type"]);
|
|
@@ -23902,7 +24875,7 @@ function validateElicitationContent(encoded, requestedSchema) {
|
|
|
23902
24875
|
"invalid_elicitation_response"
|
|
23903
24876
|
);
|
|
23904
24877
|
}
|
|
23905
|
-
if (!
|
|
24878
|
+
if (!isRecord7(decoded) || !isRecord7(requestedSchema) || !isRecord7(requestedSchema["properties"])) {
|
|
23906
24879
|
throw new AcpExecutionError(
|
|
23907
24880
|
"Elicitation response does not match the requested form",
|
|
23908
24881
|
{},
|
|
@@ -23926,7 +24899,7 @@ function validateElicitationContent(encoded, requestedSchema) {
|
|
|
23926
24899
|
const validated = {};
|
|
23927
24900
|
for (const [name, value] of Object.entries(decoded)) {
|
|
23928
24901
|
const property = properties[name];
|
|
23929
|
-
if (!
|
|
24902
|
+
if (!isRecord7(property)) {
|
|
23930
24903
|
throw new AcpExecutionError(
|
|
23931
24904
|
`Elicitation field ${name} was not requested`,
|
|
23932
24905
|
{},
|
|
@@ -24076,8 +25049,11 @@ var AcpProcessSession = class _AcpProcessSession {
|
|
|
24076
25049
|
#mobiusSessionId;
|
|
24077
25050
|
#pendingElicitations = /* @__PURE__ */ new Map();
|
|
24078
25051
|
#pendingPermissions = /* @__PURE__ */ new Map();
|
|
25052
|
+
#preSessionUpdates = [];
|
|
24079
25053
|
#processExit;
|
|
24080
25054
|
#store;
|
|
25055
|
+
#verifiedAgentVersion;
|
|
25056
|
+
#preSessionUpdateBytes = 0;
|
|
24081
25057
|
#agentName = "";
|
|
24082
25058
|
#agentVersion = "";
|
|
24083
25059
|
#capabilities = {
|
|
@@ -24111,6 +25087,7 @@ var AcpProcessSession = class _AcpProcessSession {
|
|
|
24111
25087
|
this.#getObserver = getObserver;
|
|
24112
25088
|
this.#mobiusSessionId = mobiusSessionId;
|
|
24113
25089
|
this.#store = store;
|
|
25090
|
+
this.#verifiedAgentVersion = agent.agentVersion;
|
|
24114
25091
|
this.#child = spawn3(agent.adapterPath, [...agent.arguments], {
|
|
24115
25092
|
cwd,
|
|
24116
25093
|
detached: process.platform !== "win32",
|
|
@@ -24213,7 +25190,7 @@ var AcpProcessSession = class _AcpProcessSession {
|
|
|
24213
25190
|
try {
|
|
24214
25191
|
await this.race(
|
|
24215
25192
|
this.#connection.agent.request(
|
|
24216
|
-
|
|
25193
|
+
methods4.agent.session.load,
|
|
24217
25194
|
{
|
|
24218
25195
|
additionalDirectories: [...this.#additionalDirectories],
|
|
24219
25196
|
cwd: this.#cwd,
|
|
@@ -24235,7 +25212,7 @@ var AcpProcessSession = class _AcpProcessSession {
|
|
|
24235
25212
|
async #initializeAgent(signal) {
|
|
24236
25213
|
const initialized = await this.race(
|
|
24237
25214
|
this.#connection.agent.request(
|
|
24238
|
-
|
|
25215
|
+
methods4.agent.initialize,
|
|
24239
25216
|
{
|
|
24240
25217
|
clientCapabilities: {
|
|
24241
25218
|
elicitation: { form: {}, url: {} },
|
|
@@ -24266,7 +25243,10 @@ var AcpProcessSession = class _AcpProcessSession {
|
|
|
24266
25243
|
initialized.agentInfo?.title ?? initialized.agentInfo?.name ?? this.#agentId,
|
|
24267
25244
|
255
|
|
24268
25245
|
);
|
|
24269
|
-
this.#agentVersion = truncate2(
|
|
25246
|
+
this.#agentVersion = truncate2(
|
|
25247
|
+
this.#verifiedAgentVersion.length > 0 ? this.#verifiedAgentVersion : initialized.agentInfo?.version ?? "",
|
|
25248
|
+
128
|
|
25249
|
+
);
|
|
24270
25250
|
}
|
|
24271
25251
|
initialize = async (signal, origin) => {
|
|
24272
25252
|
await this.#initializeAgent(signal);
|
|
@@ -24300,7 +25280,7 @@ var AcpProcessSession = class _AcpProcessSession {
|
|
|
24300
25280
|
);
|
|
24301
25281
|
const forked = await this.race(
|
|
24302
25282
|
this.#connection.agent.request(
|
|
24303
|
-
|
|
25283
|
+
methods4.agent.session.fork,
|
|
24304
25284
|
{
|
|
24305
25285
|
sessionId: nativeSessionIdSchema.parse(origin.nativeSessionId),
|
|
24306
25286
|
cwd: this.#cwd,
|
|
@@ -24312,7 +25292,7 @@ var AcpProcessSession = class _AcpProcessSession {
|
|
|
24312
25292
|
"ACP agent exited while forking a session",
|
|
24313
25293
|
signal
|
|
24314
25294
|
);
|
|
24315
|
-
this
|
|
25295
|
+
this.selectNativeSession(forked.sessionId);
|
|
24316
25296
|
if (this.#nativeSessionId === origin.nativeSessionId || this.#store.findNative(this.#agentId, this.#nativeSessionId).length > 0) {
|
|
24317
25297
|
throw new AcpExecutionError(
|
|
24318
25298
|
"The Agent did not create an independent fork",
|
|
@@ -24327,13 +25307,13 @@ var AcpProcessSession = class _AcpProcessSession {
|
|
|
24327
25307
|
stored.session.additionalDirectories,
|
|
24328
25308
|
this.#additionalDirectories
|
|
24329
25309
|
)) {
|
|
24330
|
-
this
|
|
25310
|
+
this.selectNativeSession(stored.session.nativeSessionId);
|
|
24331
25311
|
this.#prompted = stored.session.prompted;
|
|
24332
25312
|
this.#restored = true;
|
|
24333
25313
|
if (this.#capabilities.resumeSession) {
|
|
24334
25314
|
lifecycleResponse = await this.race(
|
|
24335
25315
|
this.#connection.agent.request(
|
|
24336
|
-
|
|
25316
|
+
methods4.agent.session.resume,
|
|
24337
25317
|
{
|
|
24338
25318
|
additionalDirectories: [...this.#additionalDirectories],
|
|
24339
25319
|
cwd: this.#cwd,
|
|
@@ -24350,7 +25330,7 @@ var AcpProcessSession = class _AcpProcessSession {
|
|
|
24350
25330
|
try {
|
|
24351
25331
|
lifecycleResponse = await this.race(
|
|
24352
25332
|
this.#connection.agent.request(
|
|
24353
|
-
|
|
25333
|
+
methods4.agent.session.load,
|
|
24354
25334
|
{
|
|
24355
25335
|
additionalDirectories: [...this.#additionalDirectories],
|
|
24356
25336
|
cwd: this.#cwd,
|
|
@@ -24386,7 +25366,7 @@ var AcpProcessSession = class _AcpProcessSession {
|
|
|
24386
25366
|
}
|
|
24387
25367
|
const created = await this.race(
|
|
24388
25368
|
this.#connection.agent.request(
|
|
24389
|
-
|
|
25369
|
+
methods4.agent.session.new,
|
|
24390
25370
|
{
|
|
24391
25371
|
additionalDirectories: [...this.#additionalDirectories],
|
|
24392
25372
|
cwd: this.#cwd,
|
|
@@ -24397,10 +25377,10 @@ var AcpProcessSession = class _AcpProcessSession {
|
|
|
24397
25377
|
"ACP agent exited while starting a session",
|
|
24398
25378
|
signal
|
|
24399
25379
|
);
|
|
24400
|
-
this
|
|
25380
|
+
this.selectNativeSession(created.sessionId);
|
|
24401
25381
|
lifecycleResponse = created;
|
|
24402
25382
|
}
|
|
24403
|
-
const lifecycleRecord =
|
|
25383
|
+
const lifecycleRecord = isRecord7(lifecycleResponse) ? lifecycleResponse : {};
|
|
24404
25384
|
this.#configOptions = normalizeConfigOptions(
|
|
24405
25385
|
lifecycleRecord["configOptions"],
|
|
24406
25386
|
lifecycleRecord["modes"]
|
|
@@ -24429,7 +25409,7 @@ var AcpProcessSession = class _AcpProcessSession {
|
|
|
24429
25409
|
);
|
|
24430
25410
|
const response = await this.race(
|
|
24431
25411
|
this.#connection.agent.request(
|
|
24432
|
-
|
|
25412
|
+
methods4.agent.session.list,
|
|
24433
25413
|
cursor === null ? {} : { cursor },
|
|
24434
25414
|
{ cancellationSignal: signal }
|
|
24435
25415
|
),
|
|
@@ -24454,7 +25434,7 @@ var AcpProcessSession = class _AcpProcessSession {
|
|
|
24454
25434
|
);
|
|
24455
25435
|
await this.race(
|
|
24456
25436
|
this.#connection.agent.request(
|
|
24457
|
-
|
|
25437
|
+
methods4.agent.session.delete,
|
|
24458
25438
|
{ sessionId: nativeSessionIdSchema.parse(nativeSessionId) },
|
|
24459
25439
|
{ cancellationSignal: signal }
|
|
24460
25440
|
),
|
|
@@ -24485,7 +25465,7 @@ var AcpProcessSession = class _AcpProcessSession {
|
|
|
24485
25465
|
if (existing.category === "mode") {
|
|
24486
25466
|
await this.race(
|
|
24487
25467
|
this.#connection.agent.request(
|
|
24488
|
-
|
|
25468
|
+
methods4.agent.session.setMode,
|
|
24489
25469
|
{ modeId: options.value, sessionId: this.#nativeSessionId },
|
|
24490
25470
|
{ cancellationSignal: options.signal }
|
|
24491
25471
|
),
|
|
@@ -24498,7 +25478,7 @@ var AcpProcessSession = class _AcpProcessSession {
|
|
|
24498
25478
|
} else {
|
|
24499
25479
|
const response = await this.race(
|
|
24500
25480
|
this.#connection.agent.request(
|
|
24501
|
-
|
|
25481
|
+
methods4.agent.session.setConfigOption,
|
|
24502
25482
|
{
|
|
24503
25483
|
configId: existing.id,
|
|
24504
25484
|
sessionId: this.#nativeSessionId,
|
|
@@ -24517,7 +25497,7 @@ var AcpProcessSession = class _AcpProcessSession {
|
|
|
24517
25497
|
} else {
|
|
24518
25498
|
const response = await this.race(
|
|
24519
25499
|
this.#connection.agent.request(
|
|
24520
|
-
|
|
25500
|
+
methods4.agent.session.setConfigOption,
|
|
24521
25501
|
{
|
|
24522
25502
|
configId: existing.id,
|
|
24523
25503
|
sessionId: this.#nativeSessionId,
|
|
@@ -24616,7 +25596,7 @@ var AcpProcessSession = class _AcpProcessSession {
|
|
|
24616
25596
|
try {
|
|
24617
25597
|
const response = await this.race(
|
|
24618
25598
|
this.#connection.agent.request(
|
|
24619
|
-
|
|
25599
|
+
methods4.agent.session.prompt,
|
|
24620
25600
|
{ prompt, sessionId: this.#nativeSessionId },
|
|
24621
25601
|
{ cancellationSignal: options.signal }
|
|
24622
25602
|
),
|
|
@@ -24659,13 +25639,17 @@ var AcpProcessSession = class _AcpProcessSession {
|
|
|
24659
25639
|
}
|
|
24660
25640
|
};
|
|
24661
25641
|
cancel = async () => {
|
|
24662
|
-
await this
|
|
24663
|
-
|
|
24664
|
-
|
|
25642
|
+
const capturedProcesses = await captureProcessTree(this.#child);
|
|
25643
|
+
try {
|
|
25644
|
+
await this.cancelPendingInteractions();
|
|
25645
|
+
if (this.#turn.running) {
|
|
25646
|
+
await this.#connection.agent.notify(methods4.agent.session.cancel, {
|
|
25647
|
+
sessionId: this.#nativeSessionId
|
|
25648
|
+
});
|
|
25649
|
+
}
|
|
25650
|
+
} finally {
|
|
25651
|
+
await this.closeProcess(capturedProcesses);
|
|
24665
25652
|
}
|
|
24666
|
-
await this.#connection.agent.notify(methods3.agent.session.cancel, {
|
|
24667
|
-
sessionId: this.#nativeSessionId
|
|
24668
|
-
});
|
|
24669
25653
|
};
|
|
24670
25654
|
respondPermission = async (options) => {
|
|
24671
25655
|
const pending = this.#pendingPermissions.get(options.interactionId);
|
|
@@ -24852,11 +25836,45 @@ var AcpProcessSession = class _AcpProcessSession {
|
|
|
24852
25836
|
});
|
|
24853
25837
|
};
|
|
24854
25838
|
onUpdate = (notification) => {
|
|
25839
|
+
if (this.#nativeSessionId.length === 0) {
|
|
25840
|
+
const notificationBytes = Buffer.byteLength(JSON.stringify(notification));
|
|
25841
|
+
if (this.#preSessionUpdates.length >= MAX_PRE_SESSION_UPDATES || this.#preSessionUpdateBytes + notificationBytes > MAX_PRE_SESSION_UPDATE_BYTES) {
|
|
25842
|
+
return Promise.reject(
|
|
25843
|
+
new AcpExecutionError(
|
|
25844
|
+
"ACP agent sent too many updates before creating its session",
|
|
25845
|
+
{},
|
|
25846
|
+
"agent_update_limit"
|
|
25847
|
+
)
|
|
25848
|
+
);
|
|
25849
|
+
}
|
|
25850
|
+
this.#preSessionUpdates.push(notification);
|
|
25851
|
+
this.#preSessionUpdateBytes += notificationBytes;
|
|
25852
|
+
return Promise.resolve();
|
|
25853
|
+
}
|
|
25854
|
+
return this.enqueueUpdate(notification);
|
|
25855
|
+
};
|
|
25856
|
+
enqueueUpdate = (notification) => {
|
|
24855
25857
|
this.#updateTail = this.#updateTail.then(
|
|
24856
25858
|
async () => await this.processUpdate(notification)
|
|
24857
25859
|
);
|
|
24858
25860
|
return this.#updateTail;
|
|
24859
25861
|
};
|
|
25862
|
+
selectNativeSession = (sessionId) => {
|
|
25863
|
+
const selected = nativeSessionIdSchema.parse(sessionId);
|
|
25864
|
+
if (this.#nativeSessionId.length > 0 && this.#nativeSessionId !== selected) {
|
|
25865
|
+
throw new AcpExecutionError(
|
|
25866
|
+
"ACP agent attempted to replace the selected session",
|
|
25867
|
+
{},
|
|
25868
|
+
"invalid_agent_session"
|
|
25869
|
+
);
|
|
25870
|
+
}
|
|
25871
|
+
this.#nativeSessionId = selected;
|
|
25872
|
+
const pending = this.#preSessionUpdates.splice(0);
|
|
25873
|
+
this.#preSessionUpdateBytes = 0;
|
|
25874
|
+
for (const notification of pending) {
|
|
25875
|
+
void this.enqueueUpdate(notification);
|
|
25876
|
+
}
|
|
25877
|
+
};
|
|
24860
25878
|
processUpdate = async (notification) => {
|
|
24861
25879
|
this.assertNativeSession(notification.sessionId);
|
|
24862
25880
|
const update = notification.update;
|
|
@@ -24981,7 +25999,7 @@ var AcpProcessSession = class _AcpProcessSession {
|
|
|
24981
25999
|
if (this.#capabilities.closeSession && this.#nativeSessionId.length > 0) {
|
|
24982
26000
|
try {
|
|
24983
26001
|
await this.#connection.agent.request(
|
|
24984
|
-
|
|
26002
|
+
methods4.agent.session.close,
|
|
24985
26003
|
{ sessionId: this.#nativeSessionId },
|
|
24986
26004
|
{
|
|
24987
26005
|
cancellationSignal: AbortSignal.timeout(
|
|
@@ -24994,9 +26012,12 @@ var AcpProcessSession = class _AcpProcessSession {
|
|
|
24994
26012
|
}
|
|
24995
26013
|
await this.closeProcess();
|
|
24996
26014
|
};
|
|
24997
|
-
closeProcess = async () => {
|
|
24998
|
-
|
|
24999
|
-
|
|
26015
|
+
closeProcess = async (capturedProcesses = []) => {
|
|
26016
|
+
try {
|
|
26017
|
+
await stopProcessTree(this.#child, capturedProcesses);
|
|
26018
|
+
} finally {
|
|
26019
|
+
this.#connection.close();
|
|
26020
|
+
}
|
|
25000
26021
|
};
|
|
25001
26022
|
race = async (operation, exitMessage, signal) => {
|
|
25002
26023
|
signal.throwIfAborted();
|
|
@@ -25012,13 +26033,25 @@ var AcpProcessSession = class _AcpProcessSession {
|
|
|
25012
26033
|
};
|
|
25013
26034
|
});
|
|
25014
26035
|
try {
|
|
25015
|
-
|
|
25016
|
-
|
|
25017
|
-
|
|
25018
|
-
|
|
25019
|
-
|
|
25020
|
-
|
|
25021
|
-
|
|
26036
|
+
try {
|
|
26037
|
+
return await Promise.race([
|
|
26038
|
+
operation,
|
|
26039
|
+
this.#processExit.then(() => {
|
|
26040
|
+
throw new AcpExecutionError(exitMessage);
|
|
26041
|
+
}),
|
|
26042
|
+
aborted2
|
|
26043
|
+
]);
|
|
26044
|
+
} catch (error61) {
|
|
26045
|
+
signal.throwIfAborted();
|
|
26046
|
+
if (error61 instanceof RequestError2 && error61.code === -32e3) {
|
|
26047
|
+
throw new AcpExecutionError(
|
|
26048
|
+
"Agent authentication is required",
|
|
26049
|
+
{ cause: error61 },
|
|
26050
|
+
"authentication_required"
|
|
26051
|
+
);
|
|
26052
|
+
}
|
|
26053
|
+
throw error61;
|
|
26054
|
+
}
|
|
25022
26055
|
} finally {
|
|
25023
26056
|
removeAbortListener();
|
|
25024
26057
|
}
|
|
@@ -25277,7 +26310,13 @@ var AcpSessionManager = class {
|
|
|
25277
26310
|
this.#cancellationRequests.add(sessionId);
|
|
25278
26311
|
const runtime = this.#sessions.get(sessionId);
|
|
25279
26312
|
if (runtime !== void 0) {
|
|
25280
|
-
|
|
26313
|
+
try {
|
|
26314
|
+
await runtime.cancel();
|
|
26315
|
+
} finally {
|
|
26316
|
+
if (this.#sessions.get(sessionId) === runtime) {
|
|
26317
|
+
this.#sessions.delete(sessionId);
|
|
26318
|
+
}
|
|
26319
|
+
}
|
|
25281
26320
|
}
|
|
25282
26321
|
};
|
|
25283
26322
|
runPrompt = async (options) => {
|
|
@@ -25330,7 +26369,19 @@ var AcpSessionManager = class {
|
|
|
25330
26369
|
if (this.#cancellationRequests.has(options.sessionId)) {
|
|
25331
26370
|
return { stopReason: "cancelled" };
|
|
25332
26371
|
}
|
|
25333
|
-
|
|
26372
|
+
try {
|
|
26373
|
+
const result = await runtime.prompt(boundedOptions);
|
|
26374
|
+
return this.#cancellationRequests.has(options.sessionId) ? { stopReason: "cancelled" } : result;
|
|
26375
|
+
} catch (error61) {
|
|
26376
|
+
if (this.#cancellationRequests.has(options.sessionId)) {
|
|
26377
|
+
if (this.#sessions.get(options.sessionId) === runtime) {
|
|
26378
|
+
this.#sessions.delete(options.sessionId);
|
|
26379
|
+
}
|
|
26380
|
+
await runtime.closeProcess();
|
|
26381
|
+
return { stopReason: "cancelled" };
|
|
26382
|
+
}
|
|
26383
|
+
throw error61;
|
|
26384
|
+
}
|
|
25334
26385
|
} catch (error61) {
|
|
25335
26386
|
const failedRuntime = this.#sessions.get(options.sessionId);
|
|
25336
26387
|
if (failedRuntime !== void 0) {
|
|
@@ -25550,7 +26601,7 @@ var AcpSessionManager = class {
|
|
|
25550
26601
|
};
|
|
25551
26602
|
|
|
25552
26603
|
// src/agent-catalog/publish-agent-catalog.ts
|
|
25553
|
-
import { fetch as
|
|
26604
|
+
import { fetch as fetch3 } from "undici";
|
|
25554
26605
|
var CATALOG_UPDATE_TIMEOUT_MILLISECONDS = 2e4;
|
|
25555
26606
|
var AgentCatalogPublishError = class extends Error {
|
|
25556
26607
|
code = "agent_catalog_update_failed";
|
|
@@ -25577,7 +26628,7 @@ async function publishAgentCatalog(config2, signal) {
|
|
|
25577
26628
|
let response;
|
|
25578
26629
|
const catalog = config2.catalog.read();
|
|
25579
26630
|
try {
|
|
25580
|
-
response = await
|
|
26631
|
+
response = await fetch3(catalogEndpoint(config2.relayUrl), {
|
|
25581
26632
|
body: JSON.stringify({
|
|
25582
26633
|
agents: catalog.agents.map((agent) => ({
|
|
25583
26634
|
id: agent.id,
|
|
@@ -25983,7 +27034,7 @@ var InstalledAutomaticAdapter = class {
|
|
|
25983
27034
|
}
|
|
25984
27035
|
};
|
|
25985
27036
|
function shouldProvisionAdapter(unavailable, options) {
|
|
25986
|
-
return AUTOMATIC_ADAPTER_FAILURE_CODES.has(unavailable.code) && options.environment[unavailable.specification.adapterOverrideVariable] === void 0 && unavailable.specification.supportsInstallation(
|
|
27037
|
+
return unavailable.specification instanceof BridgedAcpAgentDefinition && AUTOMATIC_ADAPTER_FAILURE_CODES.has(unavailable.code) && options.environment[unavailable.specification.adapterOverrideVariable] === void 0 && unavailable.specification.supportsInstallation(
|
|
25987
27038
|
options.platform ?? process.platform,
|
|
25988
27039
|
options.architecture ?? process.arch
|
|
25989
27040
|
);
|
|
@@ -26027,6 +27078,10 @@ var AutomaticAdapterProvisioner = class {
|
|
|
26027
27078
|
for (const unavailable of candidates) {
|
|
26028
27079
|
signal.throwIfAborted();
|
|
26029
27080
|
const specification = unavailable.specification;
|
|
27081
|
+
if (!(specification instanceof BridgedAcpAgentDefinition)) {
|
|
27082
|
+
attempts.push(null);
|
|
27083
|
+
continue;
|
|
27084
|
+
}
|
|
26030
27085
|
const verifiedAgent = await findVerifiedAgentExecutable(
|
|
26031
27086
|
specification,
|
|
26032
27087
|
discoveryOptions(
|
|
@@ -26065,293 +27120,100 @@ var AutomaticAdapterProvisioner = class {
|
|
|
26065
27120
|
specification.id,
|
|
26066
27121
|
{ adapterVersion: specification.adapterVersion }
|
|
26067
27122
|
);
|
|
26068
|
-
attempts.push(
|
|
26069
|
-
new InstalledAutomaticAdapter(specification, requestId, executable)
|
|
26070
|
-
);
|
|
26071
|
-
} catch (error61) {
|
|
26072
|
-
if (signal.aborted) {
|
|
26073
|
-
this.#options.audit.record(
|
|
26074
|
-
"agent_adapter_auto_install_cancelled",
|
|
26075
|
-
requestId,
|
|
26076
|
-
specification.id
|
|
26077
|
-
);
|
|
26078
|
-
signal.throwIfAborted();
|
|
26079
|
-
}
|
|
26080
|
-
this.#options.audit.record(
|
|
26081
|
-
"agent_adapter_auto_install_failed",
|
|
26082
|
-
requestId,
|
|
26083
|
-
specification.id,
|
|
26084
|
-
{ code: stableFailureCode(error61) }
|
|
26085
|
-
);
|
|
26086
|
-
process.stderr.write(
|
|
26087
|
-
`The pinned ACP adapter for ${specification.label} could not be installed automatically; the daemon will continue.
|
|
26088
|
-
`
|
|
26089
|
-
);
|
|
26090
|
-
attempts.push(null);
|
|
26091
|
-
}
|
|
26092
|
-
}
|
|
26093
|
-
signal.throwIfAborted();
|
|
26094
|
-
const installed = attempts.filter(
|
|
26095
|
-
(attempt) => attempt !== null
|
|
26096
|
-
);
|
|
26097
|
-
if (installed.length > 0) {
|
|
26098
|
-
const verificationEnvironment = {
|
|
26099
|
-
...this.#options.environment
|
|
26100
|
-
};
|
|
26101
|
-
for (const attempt of installed) {
|
|
26102
|
-
verificationEnvironment[attempt.specification.adapterOverrideVariable] = attempt.executable.path;
|
|
26103
|
-
}
|
|
26104
|
-
inventory = await discoverLocalAgentInventory(
|
|
26105
|
-
discoveryOptions(
|
|
26106
|
-
this.#options,
|
|
26107
|
-
verificationEnvironment,
|
|
26108
|
-
signal,
|
|
26109
|
-
this.#specifications
|
|
26110
|
-
)
|
|
26111
|
-
);
|
|
26112
|
-
}
|
|
26113
|
-
this.#options.catalog.transition(
|
|
26114
|
-
inventory.readyAgents(),
|
|
26115
|
-
inventory.installable
|
|
26116
|
-
);
|
|
26117
|
-
for (const attempt of installed) {
|
|
26118
|
-
const available = inventory.available.find(
|
|
26119
|
-
(candidate) => candidate instanceof AvailableAgent && candidate.specification.id === attempt.specification.id
|
|
26120
|
-
);
|
|
26121
|
-
if (available === void 0) {
|
|
26122
|
-
const unavailable = inventory.unavailable.find(
|
|
26123
|
-
(candidate) => candidate.specification.id === attempt.specification.id
|
|
26124
|
-
);
|
|
26125
|
-
this.#options.audit.record(
|
|
26126
|
-
"agent_adapter_auto_install_verification_failed",
|
|
26127
|
-
attempt.requestId,
|
|
26128
|
-
attempt.specification.id,
|
|
26129
|
-
{ code: unavailable?.code ?? "agent_verification_failed" }
|
|
26130
|
-
);
|
|
26131
|
-
continue;
|
|
26132
|
-
}
|
|
26133
|
-
this.#options.audit.record(
|
|
26134
|
-
"agent_adapter_auto_install_verified",
|
|
26135
|
-
attempt.requestId,
|
|
26136
|
-
attempt.specification.id,
|
|
26137
|
-
{
|
|
26138
|
-
adapterVersion: available.agent.adapterVersion,
|
|
26139
|
-
agentVersion: available.agent.agentVersion
|
|
26140
|
-
}
|
|
26141
|
-
);
|
|
26142
|
-
process.stdout.write(
|
|
26143
|
-
`${attempt.specification.label} ACP integration is ready.
|
|
26144
|
-
`
|
|
26145
|
-
);
|
|
26146
|
-
}
|
|
26147
|
-
return inventory;
|
|
26148
|
-
};
|
|
26149
|
-
};
|
|
26150
|
-
|
|
26151
|
-
// src/agent-installation/fixed-installation-executor.ts
|
|
26152
|
-
import { realpathSync as realpathSync2, statSync as statSync2 } from "node:fs";
|
|
26153
|
-
import { resolve as resolve4 } from "node:path";
|
|
26154
|
-
|
|
26155
|
-
// src/agent-installation/fixed-agent-install-recipes.ts
|
|
26156
|
-
import { mkdir as mkdir3, mkdtemp as mkdtemp2, rm as rm2 } from "node:fs/promises";
|
|
26157
|
-
import { join as join9 } from "node:path";
|
|
26158
|
-
|
|
26159
|
-
// src/agent-installation/verified-download.ts
|
|
26160
|
-
import { createHash } from "node:crypto";
|
|
26161
|
-
import { open as open5, unlink } from "node:fs/promises";
|
|
26162
|
-
import { fetch as fetch3 } from "undici";
|
|
26163
|
-
var MAX_REDIRECTS = 4;
|
|
26164
|
-
var REDIRECT_STATUSES = /* @__PURE__ */ new Set([301, 302, 303, 307, 308]);
|
|
26165
|
-
var InstallerDownloadError = class extends Error {
|
|
26166
|
-
code;
|
|
26167
|
-
constructor(code, message, options = {}) {
|
|
26168
|
-
super(message, options);
|
|
26169
|
-
this.code = code;
|
|
26170
|
-
this.name = "InstallerDownloadError";
|
|
26171
|
-
}
|
|
26172
|
-
};
|
|
26173
|
-
var VerifiedDownload = class {
|
|
26174
|
-
bytes;
|
|
26175
|
-
sha256;
|
|
26176
|
-
url;
|
|
26177
|
-
constructor(url2, bytes, sha256) {
|
|
26178
|
-
this.bytes = bytes;
|
|
26179
|
-
this.sha256 = sha256;
|
|
26180
|
-
this.url = url2;
|
|
26181
|
-
}
|
|
26182
|
-
};
|
|
26183
|
-
var UndiciInstallerDownloadTransport = class {
|
|
26184
|
-
get = async (url2, signal) => await fetch3(url2, {
|
|
26185
|
-
dispatcher: environmentProxyDispatcher,
|
|
26186
|
-
headers: {
|
|
26187
|
-
accept: "text/plain, application/octet-stream;q=0.9",
|
|
26188
|
-
"user-agent": "Mobius-Agent-Installer/0.0.3"
|
|
26189
|
-
},
|
|
26190
|
-
method: "GET",
|
|
26191
|
-
redirect: "manual",
|
|
26192
|
-
signal
|
|
26193
|
-
});
|
|
26194
|
-
};
|
|
26195
|
-
function validateUrl(url2, allowedHosts) {
|
|
26196
|
-
if (url2.protocol !== "https:" || url2.username.length > 0 || url2.password.length > 0 || url2.port.length > 0 || !allowedHosts.has(url2.hostname)) {
|
|
26197
|
-
throw new InstallerDownloadError(
|
|
26198
|
-
"installer_host_not_allowed",
|
|
26199
|
-
"The installer download target is not allowed"
|
|
26200
|
-
);
|
|
26201
|
-
}
|
|
26202
|
-
}
|
|
26203
|
-
async function fetchInstaller(options, signal, transport) {
|
|
26204
|
-
let url2 = new URL(options.url);
|
|
26205
|
-
for (let redirectCount = 0; redirectCount <= MAX_REDIRECTS; redirectCount += 1) {
|
|
26206
|
-
validateUrl(url2, options.allowedHosts);
|
|
26207
|
-
const response = await transport.get(url2, signal);
|
|
26208
|
-
if (!REDIRECT_STATUSES.has(response.status)) {
|
|
26209
|
-
return { response, url: url2 };
|
|
26210
|
-
}
|
|
26211
|
-
await response.body?.cancel();
|
|
26212
|
-
const location = response.headers.get("location");
|
|
26213
|
-
if (location === null || redirectCount === MAX_REDIRECTS) {
|
|
26214
|
-
throw new InstallerDownloadError(
|
|
26215
|
-
"installer_redirect_invalid",
|
|
26216
|
-
"The installer returned an invalid redirect"
|
|
26217
|
-
);
|
|
26218
|
-
}
|
|
26219
|
-
let redirected;
|
|
26220
|
-
try {
|
|
26221
|
-
redirected = new URL(location, url2);
|
|
26222
|
-
} catch (error61) {
|
|
26223
|
-
throw new InstallerDownloadError(
|
|
26224
|
-
"installer_redirect_invalid",
|
|
26225
|
-
"The installer returned an invalid redirect",
|
|
26226
|
-
{ cause: error61 }
|
|
26227
|
-
);
|
|
26228
|
-
}
|
|
26229
|
-
try {
|
|
26230
|
-
validateUrl(redirected, options.allowedHosts);
|
|
26231
|
-
} catch (error61) {
|
|
26232
|
-
throw new InstallerDownloadError(
|
|
26233
|
-
"installer_redirect_not_allowed",
|
|
26234
|
-
"The installer redirect left the approved host allowlist",
|
|
26235
|
-
{ cause: error61 }
|
|
26236
|
-
);
|
|
26237
|
-
}
|
|
26238
|
-
url2 = redirected;
|
|
26239
|
-
}
|
|
26240
|
-
throw new InstallerDownloadError(
|
|
26241
|
-
"installer_redirect_invalid",
|
|
26242
|
-
"The installer returned too many redirects"
|
|
26243
|
-
);
|
|
26244
|
-
}
|
|
26245
|
-
async function writeCompleteChunk(handle, chunk) {
|
|
26246
|
-
let offset = 0;
|
|
26247
|
-
while (offset < chunk.byteLength) {
|
|
26248
|
-
const written = await handle.write(
|
|
26249
|
-
chunk,
|
|
26250
|
-
offset,
|
|
26251
|
-
chunk.byteLength - offset
|
|
26252
|
-
);
|
|
26253
|
-
if (written.bytesWritten < 1) {
|
|
26254
|
-
throw new InstallerDownloadError(
|
|
26255
|
-
"installer_write_failed",
|
|
26256
|
-
"The verified installer could not be stored"
|
|
26257
|
-
);
|
|
26258
|
-
}
|
|
26259
|
-
offset += written.bytesWritten;
|
|
26260
|
-
}
|
|
26261
|
-
}
|
|
26262
|
-
async function downloadVerifiedFile(options, transport = new UndiciInstallerDownloadTransport()) {
|
|
26263
|
-
options.signal.throwIfAborted();
|
|
26264
|
-
const timeoutSignal = AbortSignal.timeout(options.timeoutMilliseconds);
|
|
26265
|
-
const signal = AbortSignal.any([options.signal, timeoutSignal]);
|
|
26266
|
-
let handle = null;
|
|
26267
|
-
let responseBody = null;
|
|
26268
|
-
try {
|
|
26269
|
-
const fetched = await fetchInstaller(options, signal, transport);
|
|
26270
|
-
responseBody = fetched.response.body;
|
|
26271
|
-
if (!fetched.response.ok || fetched.response.body === null) {
|
|
26272
|
-
throw new InstallerDownloadError(
|
|
26273
|
-
"installer_download_failed",
|
|
26274
|
-
"The approved installer could not be downloaded"
|
|
26275
|
-
);
|
|
26276
|
-
}
|
|
26277
|
-
const contentLength = fetched.response.headers.get("content-length");
|
|
26278
|
-
if (contentLength !== null) {
|
|
26279
|
-
const declaredLength = Number(contentLength);
|
|
26280
|
-
if (!Number.isSafeInteger(declaredLength) || declaredLength < 1 || declaredLength > options.maximumBytes) {
|
|
26281
|
-
throw new InstallerDownloadError(
|
|
26282
|
-
"installer_size_invalid",
|
|
26283
|
-
"The installer size is outside the approved limit"
|
|
27123
|
+
attempts.push(
|
|
27124
|
+
new InstalledAutomaticAdapter(specification, requestId, executable)
|
|
26284
27125
|
);
|
|
26285
|
-
}
|
|
26286
|
-
|
|
26287
|
-
|
|
26288
|
-
|
|
26289
|
-
|
|
26290
|
-
|
|
26291
|
-
try {
|
|
26292
|
-
while (true) {
|
|
26293
|
-
signal.throwIfAborted();
|
|
26294
|
-
const chunk = await reader.read();
|
|
26295
|
-
if (chunk.done) {
|
|
26296
|
-
break;
|
|
26297
|
-
}
|
|
26298
|
-
bytes += chunk.value.byteLength;
|
|
26299
|
-
if (bytes > options.maximumBytes) {
|
|
26300
|
-
throw new InstallerDownloadError(
|
|
26301
|
-
"installer_size_invalid",
|
|
26302
|
-
"The installer exceeded the approved size limit"
|
|
27126
|
+
} catch (error61) {
|
|
27127
|
+
if (signal.aborted) {
|
|
27128
|
+
this.#options.audit.record(
|
|
27129
|
+
"agent_adapter_auto_install_cancelled",
|
|
27130
|
+
requestId,
|
|
27131
|
+
specification.id
|
|
26303
27132
|
);
|
|
27133
|
+
signal.throwIfAborted();
|
|
26304
27134
|
}
|
|
26305
|
-
|
|
26306
|
-
|
|
27135
|
+
this.#options.audit.record(
|
|
27136
|
+
"agent_adapter_auto_install_failed",
|
|
27137
|
+
requestId,
|
|
27138
|
+
specification.id,
|
|
27139
|
+
{ code: stableFailureCode(error61) }
|
|
27140
|
+
);
|
|
27141
|
+
process.stderr.write(
|
|
27142
|
+
`The pinned ACP adapter for ${specification.label} could not be installed automatically; the daemon will continue.
|
|
27143
|
+
`
|
|
27144
|
+
);
|
|
27145
|
+
attempts.push(null);
|
|
26307
27146
|
}
|
|
26308
|
-
} finally {
|
|
26309
|
-
await reader.cancel().catch(() => void 0);
|
|
26310
|
-
reader.releaseLock();
|
|
26311
27147
|
}
|
|
26312
|
-
|
|
26313
|
-
|
|
26314
|
-
|
|
26315
|
-
|
|
27148
|
+
signal.throwIfAborted();
|
|
27149
|
+
const installed = attempts.filter(
|
|
27150
|
+
(attempt) => attempt !== null
|
|
27151
|
+
);
|
|
27152
|
+
if (installed.length > 0) {
|
|
27153
|
+
const verificationEnvironment = {
|
|
27154
|
+
...this.#options.environment
|
|
27155
|
+
};
|
|
27156
|
+
for (const attempt of installed) {
|
|
27157
|
+
verificationEnvironment[attempt.specification.adapterOverrideVariable] = attempt.executable.path;
|
|
27158
|
+
}
|
|
27159
|
+
inventory = await discoverLocalAgentInventory(
|
|
27160
|
+
discoveryOptions(
|
|
27161
|
+
this.#options,
|
|
27162
|
+
verificationEnvironment,
|
|
27163
|
+
signal,
|
|
27164
|
+
this.#specifications
|
|
27165
|
+
)
|
|
26316
27166
|
);
|
|
26317
27167
|
}
|
|
26318
|
-
|
|
26319
|
-
|
|
26320
|
-
|
|
26321
|
-
|
|
26322
|
-
|
|
26323
|
-
|
|
26324
|
-
|
|
26325
|
-
|
|
26326
|
-
|
|
26327
|
-
|
|
26328
|
-
|
|
26329
|
-
|
|
26330
|
-
|
|
26331
|
-
|
|
26332
|
-
|
|
26333
|
-
|
|
26334
|
-
|
|
27168
|
+
this.#options.catalog.transition(
|
|
27169
|
+
inventory.readyAgents(),
|
|
27170
|
+
inventory.installable
|
|
27171
|
+
);
|
|
27172
|
+
for (const attempt of installed) {
|
|
27173
|
+
const available = inventory.available.find(
|
|
27174
|
+
(candidate) => candidate instanceof AvailableAgent && candidate.specification.id === attempt.specification.id
|
|
27175
|
+
);
|
|
27176
|
+
if (available === void 0) {
|
|
27177
|
+
const unavailable = inventory.unavailable.find(
|
|
27178
|
+
(candidate) => candidate.specification.id === attempt.specification.id
|
|
27179
|
+
);
|
|
27180
|
+
this.#options.audit.record(
|
|
27181
|
+
"agent_adapter_auto_install_verification_failed",
|
|
27182
|
+
attempt.requestId,
|
|
27183
|
+
attempt.specification.id,
|
|
27184
|
+
{ code: unavailable?.code ?? "agent_verification_failed" }
|
|
27185
|
+
);
|
|
27186
|
+
continue;
|
|
27187
|
+
}
|
|
27188
|
+
this.#options.audit.record(
|
|
27189
|
+
"agent_adapter_auto_install_verified",
|
|
27190
|
+
attempt.requestId,
|
|
27191
|
+
attempt.specification.id,
|
|
27192
|
+
{
|
|
27193
|
+
adapterVersion: available.agent.adapterVersion,
|
|
27194
|
+
agentVersion: available.agent.agentVersion
|
|
27195
|
+
}
|
|
27196
|
+
);
|
|
27197
|
+
process.stdout.write(
|
|
27198
|
+
`${attempt.specification.label} ACP integration is ready.
|
|
27199
|
+
`
|
|
26335
27200
|
);
|
|
26336
27201
|
}
|
|
26337
|
-
|
|
26338
|
-
|
|
26339
|
-
|
|
26340
|
-
|
|
26341
|
-
|
|
26342
|
-
|
|
26343
|
-
|
|
26344
|
-
);
|
|
26345
|
-
} finally {
|
|
26346
|
-
await responseBody?.cancel().catch(() => void 0);
|
|
26347
|
-
}
|
|
26348
|
-
}
|
|
27202
|
+
return inventory;
|
|
27203
|
+
};
|
|
27204
|
+
};
|
|
27205
|
+
|
|
27206
|
+
// src/agent-installation/fixed-installation-executor.ts
|
|
27207
|
+
import { realpathSync as realpathSync2, statSync as statSync2 } from "node:fs";
|
|
27208
|
+
import { resolve as resolve4 } from "node:path";
|
|
26349
27209
|
|
|
26350
27210
|
// src/agent-installation/fixed-agent-install-recipes.ts
|
|
27211
|
+
import { mkdir as mkdir4, mkdtemp as mkdtemp3, rm as rm3 } from "node:fs/promises";
|
|
27212
|
+
import { join as join14 } from "node:path";
|
|
26351
27213
|
var INSTALLER_DOWNLOAD_LIMIT_BYTES = 1024 * 1024;
|
|
26352
27214
|
var INSTALLER_DOWNLOAD_TIMEOUT_MILLISECONDS = 6e4;
|
|
26353
27215
|
var AGENT_INSTALL_TIMEOUT_MILLISECONDS = 5 * 60 * 1e3;
|
|
26354
|
-
var
|
|
27216
|
+
var MINIMAL_PATH2 = "/usr/bin:/bin";
|
|
26355
27217
|
var FixedAgentInstallRecipe = class {
|
|
26356
27218
|
assertSupportedPlatform = () => {
|
|
26357
27219
|
if (process.platform !== "darwin" && process.platform !== "linux" || process.arch !== "arm64" && process.arch !== "x64") {
|
|
@@ -26378,22 +27240,22 @@ var CodexInstallRecipe = class extends FixedAgentInstallRecipe {
|
|
|
26378
27240
|
releaseChannel = "latest";
|
|
26379
27241
|
install = async (options) => {
|
|
26380
27242
|
this.assertSupportedPlatform();
|
|
26381
|
-
const root =
|
|
26382
|
-
const temporaryRoot =
|
|
27243
|
+
const root = join14(options.stateDirectory, "agents", this.id);
|
|
27244
|
+
const temporaryRoot = join14(options.stateDirectory, "temporary");
|
|
26383
27245
|
await Promise.all([
|
|
26384
|
-
|
|
26385
|
-
|
|
27246
|
+
mkdir4(root, { mode: 448, recursive: true }),
|
|
27247
|
+
mkdir4(temporaryRoot, { mode: 448, recursive: true })
|
|
26386
27248
|
]);
|
|
26387
|
-
const temporaryDirectory = await
|
|
26388
|
-
|
|
27249
|
+
const temporaryDirectory = await mkdtemp3(
|
|
27250
|
+
join14(temporaryRoot, ".codex-install-")
|
|
26389
27251
|
);
|
|
26390
|
-
const installerPath =
|
|
26391
|
-
const installDirectory =
|
|
26392
|
-
const codexHome =
|
|
27252
|
+
const installerPath = join14(temporaryDirectory, "install.sh");
|
|
27253
|
+
const installDirectory = join14(root, "bin");
|
|
27254
|
+
const codexHome = join14(root, "home");
|
|
26393
27255
|
try {
|
|
26394
27256
|
await Promise.all([
|
|
26395
|
-
|
|
26396
|
-
|
|
27257
|
+
mkdir4(installDirectory, { mode: 448, recursive: true }),
|
|
27258
|
+
mkdir4(codexHome, { mode: 448, recursive: true })
|
|
26397
27259
|
]);
|
|
26398
27260
|
await options.report("downloading");
|
|
26399
27261
|
const download = await downloadVerifiedFile({
|
|
@@ -26426,14 +27288,14 @@ var CodexInstallRecipe = class extends FixedAgentInstallRecipe {
|
|
|
26426
27288
|
CODEX_NON_INTERACTIVE: "1",
|
|
26427
27289
|
CODEX_RELEASE: this.releaseChannel,
|
|
26428
27290
|
HOME: codexHome,
|
|
26429
|
-
PATH:
|
|
27291
|
+
PATH: MINIMAL_PATH2
|
|
26430
27292
|
},
|
|
26431
27293
|
outputLimitBytes: 64 * 1024,
|
|
26432
27294
|
signal: options.signal,
|
|
26433
27295
|
timeoutMilliseconds: AGENT_INSTALL_TIMEOUT_MILLISECONDS
|
|
26434
27296
|
});
|
|
26435
27297
|
return await this.requireInstalledExecutable(
|
|
26436
|
-
|
|
27298
|
+
join14(installDirectory, "codex")
|
|
26437
27299
|
);
|
|
26438
27300
|
} catch (error61) {
|
|
26439
27301
|
if (options.signal.aborted) {
|
|
@@ -26447,7 +27309,7 @@ var CodexInstallRecipe = class extends FixedAgentInstallRecipe {
|
|
|
26447
27309
|
"The fixed Codex installation recipe failed"
|
|
26448
27310
|
);
|
|
26449
27311
|
} finally {
|
|
26450
|
-
await
|
|
27312
|
+
await rm3(temporaryDirectory, { force: true, recursive: true });
|
|
26451
27313
|
}
|
|
26452
27314
|
};
|
|
26453
27315
|
};
|
|
@@ -26457,17 +27319,17 @@ var ClaudeCodeInstallRecipe = class extends FixedAgentInstallRecipe {
|
|
|
26457
27319
|
releaseChannel = "stable";
|
|
26458
27320
|
install = async (options) => {
|
|
26459
27321
|
this.assertSupportedPlatform();
|
|
26460
|
-
const root =
|
|
26461
|
-
const managedHome =
|
|
26462
|
-
const temporaryRoot =
|
|
27322
|
+
const root = join14(options.stateDirectory, "agents", this.id);
|
|
27323
|
+
const managedHome = join14(root, "home");
|
|
27324
|
+
const temporaryRoot = join14(options.stateDirectory, "temporary");
|
|
26463
27325
|
await Promise.all([
|
|
26464
|
-
|
|
26465
|
-
|
|
27326
|
+
mkdir4(managedHome, { mode: 448, recursive: true }),
|
|
27327
|
+
mkdir4(temporaryRoot, { mode: 448, recursive: true })
|
|
26466
27328
|
]);
|
|
26467
|
-
const temporaryDirectory = await
|
|
26468
|
-
|
|
27329
|
+
const temporaryDirectory = await mkdtemp3(
|
|
27330
|
+
join14(temporaryRoot, ".claude-install-")
|
|
26469
27331
|
);
|
|
26470
|
-
const installerPath =
|
|
27332
|
+
const installerPath = join14(temporaryDirectory, "install.sh");
|
|
26471
27333
|
try {
|
|
26472
27334
|
await options.report("downloading");
|
|
26473
27335
|
const download = await downloadVerifiedFile({
|
|
@@ -26496,7 +27358,7 @@ var ClaudeCodeInstallRecipe = class extends FixedAgentInstallRecipe {
|
|
|
26496
27358
|
cwd: temporaryDirectory,
|
|
26497
27359
|
environment: {
|
|
26498
27360
|
HOME: managedHome,
|
|
26499
|
-
PATH:
|
|
27361
|
+
PATH: MINIMAL_PATH2,
|
|
26500
27362
|
SHELL: "/bin/bash"
|
|
26501
27363
|
},
|
|
26502
27364
|
outputLimitBytes: 64 * 1024,
|
|
@@ -26504,7 +27366,7 @@ var ClaudeCodeInstallRecipe = class extends FixedAgentInstallRecipe {
|
|
|
26504
27366
|
timeoutMilliseconds: AGENT_INSTALL_TIMEOUT_MILLISECONDS
|
|
26505
27367
|
});
|
|
26506
27368
|
return await this.requireInstalledExecutable(
|
|
26507
|
-
|
|
27369
|
+
join14(managedHome, ".local", "bin", "claude")
|
|
26508
27370
|
);
|
|
26509
27371
|
} catch (error61) {
|
|
26510
27372
|
if (options.signal.aborted) {
|
|
@@ -26518,7 +27380,7 @@ var ClaudeCodeInstallRecipe = class extends FixedAgentInstallRecipe {
|
|
|
26518
27380
|
"The fixed Claude Code installation recipe failed"
|
|
26519
27381
|
);
|
|
26520
27382
|
} finally {
|
|
26521
|
-
await
|
|
27383
|
+
await rm3(temporaryDirectory, { force: true, recursive: true });
|
|
26522
27384
|
}
|
|
26523
27385
|
};
|
|
26524
27386
|
};
|
|
@@ -26538,7 +27400,7 @@ var PiInstallRecipe = class extends FixedAgentInstallRecipe {
|
|
|
26538
27400
|
await options.report("verifying");
|
|
26539
27401
|
await options.report("installing_agent");
|
|
26540
27402
|
const executable = await this.#npmInstaller.install(
|
|
26541
|
-
|
|
27403
|
+
join14(
|
|
26542
27404
|
options.stateDirectory,
|
|
26543
27405
|
"agents",
|
|
26544
27406
|
this.id,
|
|
@@ -26593,11 +27455,161 @@ var PiInstallRecipe = class extends FixedAgentInstallRecipe {
|
|
|
26593
27455
|
}
|
|
26594
27456
|
};
|
|
26595
27457
|
};
|
|
27458
|
+
var DeepSeekHarnessInstallRecipe = class extends FixedAgentInstallRecipe {
|
|
27459
|
+
#npmInstaller;
|
|
27460
|
+
id = "deepseek-harness";
|
|
27461
|
+
label = "DeepSeek Harness";
|
|
27462
|
+
releaseChannel = DEEPSEEK_HARNESS_PACKAGE.version;
|
|
27463
|
+
constructor(npmInstaller = new ManagedNpmPackageInstaller()) {
|
|
27464
|
+
super();
|
|
27465
|
+
this.#npmInstaller = npmInstaller;
|
|
27466
|
+
}
|
|
27467
|
+
install = async (options) => {
|
|
27468
|
+
this.assertSupportedPlatform();
|
|
27469
|
+
try {
|
|
27470
|
+
const managedHome = join14(
|
|
27471
|
+
options.stateDirectory,
|
|
27472
|
+
"agents",
|
|
27473
|
+
this.id,
|
|
27474
|
+
"home"
|
|
27475
|
+
);
|
|
27476
|
+
await mkdir4(managedHome, { mode: 448, recursive: true });
|
|
27477
|
+
await options.report("downloading");
|
|
27478
|
+
await options.report("verifying");
|
|
27479
|
+
await options.report("installing_agent");
|
|
27480
|
+
const executable = await this.#npmInstaller.install(
|
|
27481
|
+
join14(
|
|
27482
|
+
options.stateDirectory,
|
|
27483
|
+
"agents",
|
|
27484
|
+
this.id,
|
|
27485
|
+
DEEPSEEK_HARNESS_PACKAGE.version
|
|
27486
|
+
),
|
|
27487
|
+
DEEPSEEK_HARNESS_PACKAGE,
|
|
27488
|
+
options.environment,
|
|
27489
|
+
options.signal
|
|
27490
|
+
);
|
|
27491
|
+
options.audit.record(
|
|
27492
|
+
"agent_npm_package_verified",
|
|
27493
|
+
options.requestId,
|
|
27494
|
+
this.id,
|
|
27495
|
+
{
|
|
27496
|
+
integrity: DEEPSEEK_HARNESS_PACKAGE.integrity,
|
|
27497
|
+
package: DEEPSEEK_HARNESS_PACKAGE.packageName,
|
|
27498
|
+
version: DEEPSEEK_HARNESS_PACKAGE.version
|
|
27499
|
+
}
|
|
27500
|
+
);
|
|
27501
|
+
return executable;
|
|
27502
|
+
} catch (error61) {
|
|
27503
|
+
if (options.signal.aborted) {
|
|
27504
|
+
options.signal.throwIfAborted();
|
|
27505
|
+
}
|
|
27506
|
+
if (error61 instanceof ManagedNpmPackageError) {
|
|
27507
|
+
if (error61.code === "managed_package_verification_failed") {
|
|
27508
|
+
throw new InstallationManagerError(
|
|
27509
|
+
"agent_verification_failed",
|
|
27510
|
+
"The managed DeepSeek Harness package did not match its pinned artifact",
|
|
27511
|
+
{ cause: error61 }
|
|
27512
|
+
);
|
|
27513
|
+
}
|
|
27514
|
+
if (error61.code === "managed_package_publish_failed") {
|
|
27515
|
+
throw new InstallationManagerError(
|
|
27516
|
+
"agent_publish_failed",
|
|
27517
|
+
"The managed DeepSeek Harness package could not be published",
|
|
27518
|
+
{ cause: error61 }
|
|
27519
|
+
);
|
|
27520
|
+
}
|
|
27521
|
+
throw new InstallationManagerError(error61.code, error61.message, {
|
|
27522
|
+
cause: error61
|
|
27523
|
+
});
|
|
27524
|
+
}
|
|
27525
|
+
if (error61 instanceof InstallationManagerError) {
|
|
27526
|
+
throw error61;
|
|
27527
|
+
}
|
|
27528
|
+
throw new InstallationManagerError(
|
|
27529
|
+
"agent_install_failed",
|
|
27530
|
+
"The fixed DeepSeek Harness installation recipe failed",
|
|
27531
|
+
{ cause: error61 }
|
|
27532
|
+
);
|
|
27533
|
+
}
|
|
27534
|
+
};
|
|
27535
|
+
};
|
|
27536
|
+
var OpenCodeInstallRecipe = class extends FixedAgentInstallRecipe {
|
|
27537
|
+
#archiveInstaller;
|
|
27538
|
+
id = "opencode";
|
|
27539
|
+
label = "OpenCode";
|
|
27540
|
+
releaseChannel = OPENCODE_MANAGED_VERSION;
|
|
27541
|
+
constructor(archiveInstaller = new ManagedAgentArchiveInstaller()) {
|
|
27542
|
+
super();
|
|
27543
|
+
this.#archiveInstaller = archiveInstaller;
|
|
27544
|
+
}
|
|
27545
|
+
install = async (options) => {
|
|
27546
|
+
this.assertSupportedPlatform();
|
|
27547
|
+
const definition = openCodeManagedArchive(process.platform, process.arch);
|
|
27548
|
+
try {
|
|
27549
|
+
await options.report("downloading");
|
|
27550
|
+
await options.report("verifying");
|
|
27551
|
+
await options.report("installing_agent");
|
|
27552
|
+
const executable = await this.#archiveInstaller.install(
|
|
27553
|
+
join14(
|
|
27554
|
+
options.stateDirectory,
|
|
27555
|
+
"agents",
|
|
27556
|
+
this.id,
|
|
27557
|
+
OPENCODE_MANAGED_VERSION
|
|
27558
|
+
),
|
|
27559
|
+
definition,
|
|
27560
|
+
options.signal
|
|
27561
|
+
);
|
|
27562
|
+
options.audit.record(
|
|
27563
|
+
"agent_archive_verified",
|
|
27564
|
+
options.requestId,
|
|
27565
|
+
this.id,
|
|
27566
|
+
{
|
|
27567
|
+
sha256: definition.archiveSha256,
|
|
27568
|
+
version: definition.version
|
|
27569
|
+
}
|
|
27570
|
+
);
|
|
27571
|
+
return executable;
|
|
27572
|
+
} catch (error61) {
|
|
27573
|
+
if (options.signal.aborted) {
|
|
27574
|
+
options.signal.throwIfAborted();
|
|
27575
|
+
}
|
|
27576
|
+
if (error61 instanceof ManagedAgentArchiveError) {
|
|
27577
|
+
if (error61.code === "managed_archive_verification_failed") {
|
|
27578
|
+
throw new InstallationManagerError(
|
|
27579
|
+
"agent_verification_failed",
|
|
27580
|
+
"The managed OpenCode archive did not match its pinned artifact",
|
|
27581
|
+
{ cause: error61 }
|
|
27582
|
+
);
|
|
27583
|
+
}
|
|
27584
|
+
if (error61.code === "managed_archive_publish_failed") {
|
|
27585
|
+
throw new InstallationManagerError(
|
|
27586
|
+
"agent_publish_failed",
|
|
27587
|
+
"The managed OpenCode archive could not be published",
|
|
27588
|
+
{ cause: error61 }
|
|
27589
|
+
);
|
|
27590
|
+
}
|
|
27591
|
+
throw new InstallationManagerError(error61.code, error61.message, {
|
|
27592
|
+
cause: error61
|
|
27593
|
+
});
|
|
27594
|
+
}
|
|
27595
|
+
if (error61 instanceof InstallationManagerError) {
|
|
27596
|
+
throw error61;
|
|
27597
|
+
}
|
|
27598
|
+
throw new InstallationManagerError(
|
|
27599
|
+
"agent_install_failed",
|
|
27600
|
+
"The fixed OpenCode installation recipe failed",
|
|
27601
|
+
{ cause: error61 }
|
|
27602
|
+
);
|
|
27603
|
+
}
|
|
27604
|
+
};
|
|
27605
|
+
};
|
|
26596
27606
|
function fixedAgentInstallRecipes() {
|
|
26597
27607
|
return Object.freeze([
|
|
26598
27608
|
new CodexInstallRecipe(),
|
|
26599
27609
|
new ClaudeCodeInstallRecipe(),
|
|
26600
|
-
new PiInstallRecipe()
|
|
27610
|
+
new PiInstallRecipe(),
|
|
27611
|
+
new DeepSeekHarnessInstallRecipe(),
|
|
27612
|
+
new OpenCodeInstallRecipe()
|
|
26601
27613
|
]);
|
|
26602
27614
|
}
|
|
26603
27615
|
|
|
@@ -26735,12 +27747,15 @@ var FixedInstallationExecutor = class {
|
|
|
26735
27747
|
});
|
|
26736
27748
|
installedAgent = true;
|
|
26737
27749
|
}
|
|
26738
|
-
let adapter = await resolveAdapterExecutable(
|
|
26739
|
-
specification,
|
|
26740
|
-
discoveryOptions2
|
|
26741
|
-
);
|
|
27750
|
+
let adapter = specification instanceof DirectAcpAgentDefinition ? agent : await resolveAdapterExecutable(specification, discoveryOptions2);
|
|
26742
27751
|
let installedAdapter = false;
|
|
26743
27752
|
if (adapter === null) {
|
|
27753
|
+
if (!(specification instanceof BridgedAcpAgentDefinition)) {
|
|
27754
|
+
throw new InstallationManagerError(
|
|
27755
|
+
"agent_verification_failed",
|
|
27756
|
+
"The direct Agent executable is unavailable"
|
|
27757
|
+
);
|
|
27758
|
+
}
|
|
26744
27759
|
await report("installing_adapter");
|
|
26745
27760
|
adapter = await this.#adapterInstaller.install(specification, signal);
|
|
26746
27761
|
installedAdapter = true;
|
|
@@ -26797,7 +27812,7 @@ var FixedInstallationExecutor = class {
|
|
|
26797
27812
|
"The complete Agent ACP path did not pass verification"
|
|
26798
27813
|
);
|
|
26799
27814
|
}
|
|
26800
|
-
if (!installedAdapter && requiresAdapterReplacement(unavailable.code)) {
|
|
27815
|
+
if (!installedAdapter && specification instanceof BridgedAcpAgentDefinition && requiresAdapterReplacement(unavailable.code)) {
|
|
26801
27816
|
await report("installing_adapter");
|
|
26802
27817
|
adapter = await this.#adapterInstaller.install(specification, signal);
|
|
26803
27818
|
installedAdapter = true;
|
|
@@ -26816,6 +27831,9 @@ var FixedInstallationExecutor = class {
|
|
|
26816
27831
|
stateDirectory: this.#stateDirectory
|
|
26817
27832
|
});
|
|
26818
27833
|
installedAgent = true;
|
|
27834
|
+
if (specification instanceof DirectAcpAgentDefinition) {
|
|
27835
|
+
adapter = agent;
|
|
27836
|
+
}
|
|
26819
27837
|
continue;
|
|
26820
27838
|
}
|
|
26821
27839
|
throw new InstallationManagerError(
|
|
@@ -26877,15 +27895,15 @@ var LocalAuthorizationError = class extends Error {
|
|
|
26877
27895
|
};
|
|
26878
27896
|
|
|
26879
27897
|
// src/authorization/workspace-directory.ts
|
|
26880
|
-
import { readdir, realpath as
|
|
27898
|
+
import { readdir, realpath as realpath6, stat as stat6 } from "node:fs/promises";
|
|
26881
27899
|
import { homedir as homedir2 } from "node:os";
|
|
26882
27900
|
import {
|
|
26883
27901
|
basename as basename2,
|
|
26884
|
-
dirname as
|
|
26885
|
-
isAbsolute as
|
|
26886
|
-
join as
|
|
26887
|
-
normalize,
|
|
26888
|
-
relative as
|
|
27902
|
+
dirname as dirname5,
|
|
27903
|
+
isAbsolute as isAbsolute5,
|
|
27904
|
+
join as join15,
|
|
27905
|
+
normalize as normalize2,
|
|
27906
|
+
relative as relative3
|
|
26889
27907
|
} from "node:path";
|
|
26890
27908
|
var WorkspaceDirectoryListing = class {
|
|
26891
27909
|
directoryId;
|
|
@@ -26913,7 +27931,7 @@ function decodePath(value, prefix) {
|
|
|
26913
27931
|
if (encoded.length === 0 || encoded.length > 2e3 || !/^[a-zA-Z0-9_-]+$/.test(encoded))
|
|
26914
27932
|
throw new LocalAuthorizationError("The directory identifier is invalid");
|
|
26915
27933
|
const decoded = Buffer.from(encoded, "base64url").toString("utf8");
|
|
26916
|
-
if (Buffer.from(decoded, "utf8").toString("base64url") !== encoded || decoded.includes("\0") ||
|
|
27934
|
+
if (Buffer.from(decoded, "utf8").toString("base64url") !== encoded || decoded.includes("\0") || normalize2(decoded) !== decoded)
|
|
26917
27935
|
throw new LocalAuthorizationError("The directory identifier is invalid");
|
|
26918
27936
|
return decoded;
|
|
26919
27937
|
}
|
|
@@ -26935,20 +27953,20 @@ var WorkspaceDirectoryService = class {
|
|
|
26935
27953
|
if (id === "home") return homedir2();
|
|
26936
27954
|
if (id.startsWith("path-")) {
|
|
26937
27955
|
const path2 = decodePath(id, "path-");
|
|
26938
|
-
if (
|
|
27956
|
+
if (isAbsolute5(path2)) return path2;
|
|
26939
27957
|
}
|
|
26940
27958
|
throw new LocalAuthorizationError("The directory identifier is invalid");
|
|
26941
27959
|
};
|
|
26942
27960
|
resolvePath = async (requested, signal) => {
|
|
26943
27961
|
signal.throwIfAborted();
|
|
26944
|
-
if (!
|
|
27962
|
+
if (!isAbsolute5(requested) || requested.includes("\0") || normalize2(requested) !== requested)
|
|
26945
27963
|
throw new LocalAuthorizationError("The local directory path is invalid");
|
|
26946
27964
|
try {
|
|
26947
|
-
const target = await
|
|
27965
|
+
const target = await realpath6(requested);
|
|
26948
27966
|
signal.throwIfAborted();
|
|
26949
|
-
const metadata = await
|
|
27967
|
+
const metadata = await stat6(target);
|
|
26950
27968
|
signal.throwIfAborted();
|
|
26951
|
-
if (!
|
|
27969
|
+
if (!isAbsolute5(target) || normalize2(target) !== target || !metadata.isDirectory())
|
|
26952
27970
|
throw new LocalAuthorizationError(
|
|
26953
27971
|
"The selected location is not a directory"
|
|
26954
27972
|
);
|
|
@@ -26963,8 +27981,8 @@ var WorkspaceDirectoryService = class {
|
|
|
26963
27981
|
}
|
|
26964
27982
|
};
|
|
26965
27983
|
label = (path2) => {
|
|
26966
|
-
const suffix =
|
|
26967
|
-
return suffix === "" ? "~" : !
|
|
27984
|
+
const suffix = relative3(homedir2(), path2);
|
|
27985
|
+
return suffix === "" ? "~" : !isAbsolute5(suffix) && suffix !== ".." && !suffix.startsWith(`..${process.platform === "win32" ? "\\" : "/"}`) ? `~/${suffix.replaceAll("\\", "/")}` : path2;
|
|
26968
27986
|
};
|
|
26969
27987
|
identify = async (bindingId, requestedPath, signal) => {
|
|
26970
27988
|
this.authorizeMachine(bindingId);
|
|
@@ -26992,7 +28010,7 @@ var WorkspaceDirectoryService = class {
|
|
|
26992
28010
|
continue;
|
|
26993
28011
|
}
|
|
26994
28012
|
try {
|
|
26995
|
-
const path2 = await this.resolvePath(
|
|
28013
|
+
const path2 = await this.resolvePath(join15(target, child.name), signal);
|
|
26996
28014
|
entries.push({ directoryId: encodePath(path2), name: child.name });
|
|
26997
28015
|
} catch (cause) {
|
|
26998
28016
|
signal.throwIfAborted();
|
|
@@ -27000,7 +28018,7 @@ var WorkspaceDirectoryService = class {
|
|
|
27000
28018
|
}
|
|
27001
28019
|
}
|
|
27002
28020
|
entries.sort((a, b) => a.name.localeCompare(b.name));
|
|
27003
|
-
const parent =
|
|
28021
|
+
const parent = dirname5(target);
|
|
27004
28022
|
return new WorkspaceDirectoryListing(
|
|
27005
28023
|
id,
|
|
27006
28024
|
this.label(target),
|
|
@@ -27115,7 +28133,8 @@ function decodeHistory(thread, value) {
|
|
|
27115
28133
|
status: "available",
|
|
27116
28134
|
messages,
|
|
27117
28135
|
truncated,
|
|
27118
|
-
coveredCommandIds: []
|
|
28136
|
+
coveredCommandIds: [],
|
|
28137
|
+
coveredMessageIds: []
|
|
27119
28138
|
}
|
|
27120
28139
|
};
|
|
27121
28140
|
}
|
|
@@ -27792,7 +28811,7 @@ var RelayConnectionLiveness = class {
|
|
|
27792
28811
|
|
|
27793
28812
|
// src/relay-connection/session-event-outbox.ts
|
|
27794
28813
|
import { mkdirSync as mkdirSync3 } from "node:fs";
|
|
27795
|
-
import { dirname as
|
|
28814
|
+
import { dirname as dirname6 } from "node:path";
|
|
27796
28815
|
import { DatabaseSync as DatabaseSync3 } from "node:sqlite";
|
|
27797
28816
|
function readPendingEnvelope(row) {
|
|
27798
28817
|
if (typeof row !== "object" || row === null || Array.isArray(row)) {
|
|
@@ -27807,7 +28826,7 @@ function readPendingEnvelope(row) {
|
|
|
27807
28826
|
var SessionEventOutbox = class {
|
|
27808
28827
|
#database;
|
|
27809
28828
|
constructor(path2) {
|
|
27810
|
-
mkdirSync3(
|
|
28829
|
+
mkdirSync3(dirname6(path2), { recursive: true });
|
|
27811
28830
|
this.#database = new DatabaseSync3(path2);
|
|
27812
28831
|
this.#database.exec(`
|
|
27813
28832
|
CREATE TABLE IF NOT EXISTS relay_session_event_outbox (
|
|
@@ -28551,10 +29570,11 @@ function waitForRelayRetry(signal, timer) {
|
|
|
28551
29570
|
signal.addEventListener("abort", finish, { once: true });
|
|
28552
29571
|
});
|
|
28553
29572
|
}
|
|
28554
|
-
async function runRelayConnection(config2, directories, audit, sessions, installations, installationObserver, nativeSessions, outbox, signal, timer) {
|
|
29573
|
+
async function runRelayConnection(config2, directories, audit, sessions, installations, installationObserver, nativeSessions, outbox, onConnected, signal, timer) {
|
|
28555
29574
|
const relayUrl = new URL(config2.relayUrl);
|
|
28556
29575
|
relayUrl.searchParams.set("liveness", "1");
|
|
28557
29576
|
const socket = await connectRelay(relayUrl, signal);
|
|
29577
|
+
onConnected();
|
|
28558
29578
|
const activeTurns = /* @__PURE__ */ new Map();
|
|
28559
29579
|
const activeAttemptIds = /* @__PURE__ */ new Map();
|
|
28560
29580
|
const connectionController = new AbortController();
|
|
@@ -28989,6 +30009,24 @@ async function runDaemon(config2, audit, signal, timer = systemDaemonTimer) {
|
|
|
28989
30009
|
installationAudit
|
|
28990
30010
|
);
|
|
28991
30011
|
let retryAnnounced = false;
|
|
30012
|
+
let connectionAnnounced = false;
|
|
30013
|
+
const announceConnection = () => {
|
|
30014
|
+
if (connectionAnnounced) {
|
|
30015
|
+
return;
|
|
30016
|
+
}
|
|
30017
|
+
connectionAnnounced = true;
|
|
30018
|
+
const reconnectCommand = `npx --yes @moxt-ai/mobius start --channel ${config2.channelId}`;
|
|
30019
|
+
process.stdout.write("Mobius daemon connected to the relay.\n\n");
|
|
30020
|
+
process.stdout.write(
|
|
30021
|
+
`${styleText(
|
|
30022
|
+
["bold", "yellow"],
|
|
30023
|
+
`Reconnect this channel later:
|
|
30024
|
+
${reconnectCommand}`
|
|
30025
|
+
)}
|
|
30026
|
+
|
|
30027
|
+
`
|
|
30028
|
+
);
|
|
30029
|
+
};
|
|
28992
30030
|
try {
|
|
28993
30031
|
while (!signal.aborted) {
|
|
28994
30032
|
try {
|
|
@@ -29002,6 +30040,7 @@ async function runDaemon(config2, audit, signal, timer = systemDaemonTimer) {
|
|
|
29002
30040
|
installationObserver,
|
|
29003
30041
|
nativeSessions,
|
|
29004
30042
|
outbox,
|
|
30043
|
+
announceConnection,
|
|
29005
30044
|
signal,
|
|
29006
30045
|
timer
|
|
29007
30046
|
);
|
|
@@ -29064,7 +30103,7 @@ async function main() {
|
|
|
29064
30103
|
if (arguments_.length > 1 || arguments_.length === 1 && arguments_[0] !== "--json") {
|
|
29065
30104
|
throw new Error("Usage: mobius agents [--json]");
|
|
29066
30105
|
}
|
|
29067
|
-
await
|
|
30106
|
+
await mkdir5(loadDefaultWorkspace(), { recursive: true, mode: 448 });
|
|
29068
30107
|
const inventory = await discoverLocalAgentInventory({
|
|
29069
30108
|
defaultWorkspace: loadDefaultWorkspace(),
|
|
29070
30109
|
environment: process.env,
|