@moxt-ai/mobius 0.0.13 → 0.0.15
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/create-client.d.ts.map +1 -1
- package/dist/acp/create-client.js +16 -1
- package/dist/acp/create-client.js.map +1 -1
- package/dist/agent-catalog/agent-discovery.d.ts +1 -1
- package/dist/agent-catalog/agent-discovery.d.ts.map +1 -1
- package/dist/agent-catalog/agent-discovery.js +2 -2
- package/dist/agent-catalog/agent-discovery.js.map +1 -1
- package/dist/agent-catalog/agents/cursor-cli-agent.d.ts +13 -0
- package/dist/agent-catalog/agents/cursor-cli-agent.d.ts.map +1 -0
- package/dist/agent-catalog/agents/cursor-cli-agent.js +25 -0
- package/dist/agent-catalog/agents/cursor-cli-agent.js.map +1 -0
- package/dist/agent-catalog/agents/grok-build-agent.d.ts +18 -0
- package/dist/agent-catalog/agents/grok-build-agent.d.ts.map +1 -0
- package/dist/agent-catalog/agents/grok-build-agent.js +75 -0
- package/dist/agent-catalog/agents/grok-build-agent.js.map +1 -0
- package/dist/agent-catalog/agents/supported-agent-specifications.d.ts.map +1 -1
- package/dist/agent-catalog/agents/supported-agent-specifications.js +6 -0
- package/dist/agent-catalog/agents/supported-agent-specifications.js.map +1 -1
- package/dist/agent-catalog/agents/verify-session-creation.d.ts +3 -0
- package/dist/agent-catalog/agents/verify-session-creation.d.ts.map +1 -0
- package/dist/agent-catalog/agents/verify-session-creation.js +16 -0
- package/dist/agent-catalog/agents/verify-session-creation.js.map +1 -0
- package/dist/agent-catalog/agents/workbuddy-agent.d.ts +15 -0
- package/dist/agent-catalog/agents/workbuddy-agent.d.ts.map +1 -0
- package/dist/agent-catalog/agents/workbuddy-agent.js +41 -0
- package/dist/agent-catalog/agents/workbuddy-agent.js.map +1 -0
- package/dist/agent-catalog/discover-local-agents.d.ts +3 -0
- package/dist/agent-catalog/discover-local-agents.d.ts.map +1 -1
- package/dist/agent-catalog/discover-local-agents.js +4 -10
- package/dist/agent-catalog/discover-local-agents.js.map +1 -1
- package/dist/agent-catalog/local-agent.d.ts +1 -2
- package/dist/agent-catalog/local-agent.d.ts.map +1 -1
- package/dist/agent-catalog/local-agent.js +1 -3
- package/dist/agent-catalog/local-agent.js.map +1 -1
- package/dist/agent-catalog/publish-agent-catalog.d.ts.map +1 -1
- package/dist/agent-catalog/publish-agent-catalog.js +0 -1
- package/dist/agent-catalog/publish-agent-catalog.js.map +1 -1
- package/dist/agent-installation/agent-installation-manager.d.ts +1 -8
- package/dist/agent-installation/agent-installation-manager.d.ts.map +1 -1
- package/dist/agent-installation/agent-installation-manager.js +7 -24
- package/dist/agent-installation/agent-installation-manager.js.map +1 -1
- package/dist/agent-installation/fixed-agent-install-recipe.d.ts +20 -0
- package/dist/agent-installation/fixed-agent-install-recipe.d.ts.map +1 -0
- package/dist/agent-installation/fixed-agent-install-recipe.js +18 -0
- package/dist/agent-installation/fixed-agent-install-recipe.js.map +1 -0
- package/dist/agent-installation/fixed-agent-install-recipes.d.ts +5 -18
- package/dist/agent-installation/fixed-agent-install-recipes.d.ts.map +1 -1
- package/dist/agent-installation/fixed-agent-install-recipes.js +9 -16
- package/dist/agent-installation/fixed-agent-install-recipes.js.map +1 -1
- package/dist/agent-installation/grok-build-install-recipe.d.ts +12 -0
- package/dist/agent-installation/grok-build-install-recipe.d.ts.map +1 -0
- package/dist/agent-installation/grok-build-install-recipe.js +102 -0
- package/dist/agent-installation/grok-build-install-recipe.js.map +1 -0
- package/dist/agent-installation/grok-managed-package.d.ts +4 -0
- package/dist/agent-installation/grok-managed-package.d.ts.map +1 -0
- package/dist/agent-installation/grok-managed-package.js +34 -0
- package/dist/agent-installation/grok-managed-package.js.map +1 -0
- package/dist/agent-installation/managed-npm-package.d.ts +8 -0
- package/dist/agent-installation/managed-npm-package.d.ts.map +1 -1
- package/dist/agent-installation/managed-npm-package.js +32 -3
- package/dist/agent-installation/managed-npm-package.js.map +1 -1
- package/dist/agent-installation/workbuddy-install-recipe.d.ts +12 -0
- package/dist/agent-installation/workbuddy-install-recipe.d.ts.map +1 -0
- package/dist/agent-installation/workbuddy-install-recipe.js +51 -0
- package/dist/agent-installation/workbuddy-install-recipe.js.map +1 -0
- package/dist/agent-installation/workbuddy-managed-package.d.ts +10 -0
- package/dist/agent-installation/workbuddy-managed-package.d.ts.map +1 -0
- package/dist/agent-installation/workbuddy-managed-package.js +11 -0
- package/dist/agent-installation/workbuddy-managed-package.js.map +1 -0
- package/dist/cli.js +1289 -837
- package/dist/cli.js.map +4 -4
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +2 -1
- package/dist/config.js.map +1 -1
- package/dist/index.js +1411 -959
- package/dist/index.js.map +4 -4
- package/dist/pairing/pair-local-machine.d.ts.map +1 -1
- package/dist/pairing/pair-local-machine.js +3 -3
- package/dist/pairing/pair-local-machine.js.map +1 -1
- package/dist/run-daemon.d.ts.map +1 -1
- package/dist/run-daemon.js +3 -12
- package/dist/run-daemon.js.map +1 -1
- package/package.json +2 -2
- package/dist/agent-installation/installation-grants.d.ts +0 -2
- package/dist/agent-installation/installation-grants.d.ts.map +0 -1
- package/dist/agent-installation/installation-grants.js +0 -51
- package/dist/agent-installation/installation-grants.js.map +0 -1
- package/dist/agent-installation/local-installation-authorizer.d.ts +0 -7
- package/dist/agent-installation/local-installation-authorizer.d.ts.map +0 -1
- package/dist/agent-installation/local-installation-authorizer.js +0 -32
- package/dist/agent-installation/local-installation-authorizer.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -9,6 +9,9 @@ import {
|
|
|
9
9
|
client,
|
|
10
10
|
methods
|
|
11
11
|
} from "@agentclientprotocol/sdk";
|
|
12
|
+
function discardExtensionParams(_params) {
|
|
13
|
+
return Object.freeze({});
|
|
14
|
+
}
|
|
12
15
|
var createAcpClient = (handler) => client({ name: "mobius" }).onRequest(
|
|
13
16
|
methods.client.session.requestPermission,
|
|
14
17
|
async (context) => await handler.onPermission(context.params, context.signal)
|
|
@@ -19,652 +22,31 @@ var createAcpClient = (handler) => client({ name: "mobius" }).onRequest(
|
|
|
19
22
|
await handler.onUpdate(context.params);
|
|
20
23
|
}).onNotification(methods.client.elicitation.complete, async (context) => {
|
|
21
24
|
await handler.onElicitationComplete(context.params);
|
|
22
|
-
})
|
|
25
|
+
}).onRequest("cursor/ask_question", discardExtensionParams, async () => ({
|
|
26
|
+
outcome: {
|
|
27
|
+
outcome: "skipped",
|
|
28
|
+
reason: "Mobius does not expose Cursor question extensions"
|
|
29
|
+
}
|
|
30
|
+
})).onRequest("cursor/create_plan", discardExtensionParams, async () => ({
|
|
31
|
+
outcome: { outcome: "cancelled" }
|
|
32
|
+
})).onNotification(
|
|
33
|
+
"cursor/update_todos",
|
|
34
|
+
discardExtensionParams,
|
|
35
|
+
async () => Promise.resolve()
|
|
36
|
+
).onNotification(
|
|
37
|
+
"cursor/task",
|
|
38
|
+
discardExtensionParams,
|
|
39
|
+
async () => Promise.resolve()
|
|
40
|
+
).onNotification(
|
|
41
|
+
"cursor/generate_image",
|
|
42
|
+
discardExtensionParams,
|
|
43
|
+
async () => Promise.resolve()
|
|
44
|
+
);
|
|
23
45
|
|
|
24
46
|
// src/config.ts
|
|
25
47
|
import { join as join3 } from "node:path";
|
|
26
48
|
import { fileURLToPath } from "node:url";
|
|
27
49
|
|
|
28
|
-
// src/agent-catalog/local-agent.ts
|
|
29
|
-
import { realpathSync, statSync } from "node:fs";
|
|
30
|
-
|
|
31
|
-
// src/process/executable.ts
|
|
32
|
-
import { execFile, spawn } from "node:child_process";
|
|
33
|
-
import { constants } from "node:fs";
|
|
34
|
-
import { access, realpath, stat } from "node:fs/promises";
|
|
35
|
-
import { join, resolve } from "node:path";
|
|
36
|
-
var DEFAULT_OUTPUT_LIMIT_BYTES = 16 * 1024;
|
|
37
|
-
var PROCESS_GRACEFUL_STOP_TIMEOUT_MILLISECONDS = 1e3;
|
|
38
|
-
var PROCESS_FORCED_STOP_TIMEOUT_MILLISECONDS = 5e3;
|
|
39
|
-
var PROCESS_TABLE_TIMEOUT_MILLISECONDS = 1e3;
|
|
40
|
-
var PROCESS_TABLE_OUTPUT_LIMIT_BYTES = 1024 * 1024;
|
|
41
|
-
var PROCESS_EXIT_CHECK_ATTEMPTS = 8;
|
|
42
|
-
var GRACEFUL_STOP_SIGNAL = 15;
|
|
43
|
-
var FORCED_STOP_SIGNAL = 9;
|
|
44
|
-
var ExecutableIdentity = class {
|
|
45
|
-
changedAtMilliseconds;
|
|
46
|
-
device;
|
|
47
|
-
inode;
|
|
48
|
-
realPath;
|
|
49
|
-
requestedPath;
|
|
50
|
-
size;
|
|
51
|
-
constructor(requestedPath, realPath_, device, inode, size, changedAtMilliseconds) {
|
|
52
|
-
this.changedAtMilliseconds = changedAtMilliseconds;
|
|
53
|
-
this.device = device;
|
|
54
|
-
this.inode = inode;
|
|
55
|
-
this.realPath = realPath_;
|
|
56
|
-
this.requestedPath = requestedPath;
|
|
57
|
-
this.size = size;
|
|
58
|
-
}
|
|
59
|
-
matches = (candidate) => this.requestedPath === candidate.requestedPath && this.realPath === candidate.realPath && this.device === candidate.device && this.inode === candidate.inode && this.size === candidate.size && this.changedAtMilliseconds === candidate.changedAtMilliseconds;
|
|
60
|
-
};
|
|
61
|
-
var ResolvedExecutable = class {
|
|
62
|
-
identity;
|
|
63
|
-
path;
|
|
64
|
-
constructor(identity2) {
|
|
65
|
-
this.identity = identity2;
|
|
66
|
-
this.path = identity2.realPath;
|
|
67
|
-
}
|
|
68
|
-
};
|
|
69
|
-
var ProcessExecutionError = class extends Error {
|
|
70
|
-
code;
|
|
71
|
-
constructor(code, message, options = {}) {
|
|
72
|
-
super(message, options);
|
|
73
|
-
this.code = code;
|
|
74
|
-
this.name = "ProcessExecutionError";
|
|
75
|
-
}
|
|
76
|
-
};
|
|
77
|
-
var ProcessResult = class {
|
|
78
|
-
stderr;
|
|
79
|
-
stdout;
|
|
80
|
-
constructor(stdout, stderr) {
|
|
81
|
-
this.stderr = stderr;
|
|
82
|
-
this.stdout = stdout;
|
|
83
|
-
}
|
|
84
|
-
};
|
|
85
|
-
function executableExtensions(executableName, environment, platform) {
|
|
86
|
-
if (platform !== "win32") {
|
|
87
|
-
return [""];
|
|
88
|
-
}
|
|
89
|
-
if (/\.[a-zA-Z0-9]+$/.test(executableName)) {
|
|
90
|
-
return [""];
|
|
91
|
-
}
|
|
92
|
-
const configured = environment["PATHEXT"] ?? ".COM;.EXE;.BAT;.CMD";
|
|
93
|
-
const extensions = configured.split(";").map((extension) => extension.trim()).filter((extension) => extension.length > 0).map(
|
|
94
|
-
(extension) => extension.startsWith(".") ? extension : `.${extension}`
|
|
95
|
-
);
|
|
96
|
-
return extensions.length > 0 ? extensions : [".EXE"];
|
|
97
|
-
}
|
|
98
|
-
async function resolveExecutablePath(requestedPath, platform = process.platform) {
|
|
99
|
-
const absoluteRequestedPath = resolve(requestedPath);
|
|
100
|
-
try {
|
|
101
|
-
const resolvedPath = await realpath(absoluteRequestedPath);
|
|
102
|
-
const metadata = await stat(resolvedPath);
|
|
103
|
-
if (!metadata.isFile()) {
|
|
104
|
-
return null;
|
|
105
|
-
}
|
|
106
|
-
if (platform !== "win32") {
|
|
107
|
-
await access(resolvedPath, constants.X_OK);
|
|
108
|
-
}
|
|
109
|
-
return new ResolvedExecutable(
|
|
110
|
-
new ExecutableIdentity(
|
|
111
|
-
absoluteRequestedPath,
|
|
112
|
-
resolvedPath,
|
|
113
|
-
metadata.dev,
|
|
114
|
-
metadata.ino,
|
|
115
|
-
metadata.size,
|
|
116
|
-
metadata.ctimeMs
|
|
117
|
-
)
|
|
118
|
-
);
|
|
119
|
-
} catch {
|
|
120
|
-
return null;
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
async function findExecutableOnPath(executableName, environment, platform = process.platform) {
|
|
124
|
-
const encodedPath = environment["PATH"] ?? "";
|
|
125
|
-
const separator = platform === "win32" ? ";" : ":";
|
|
126
|
-
const extensions = executableExtensions(
|
|
127
|
-
executableName,
|
|
128
|
-
environment,
|
|
129
|
-
platform
|
|
130
|
-
);
|
|
131
|
-
for (const entry of encodedPath.split(separator)) {
|
|
132
|
-
if (entry.length === 0) {
|
|
133
|
-
continue;
|
|
134
|
-
}
|
|
135
|
-
for (const extension of extensions) {
|
|
136
|
-
const requestedPath = resolve(
|
|
137
|
-
join(entry, `${executableName}${extension}`)
|
|
138
|
-
);
|
|
139
|
-
const executable = await resolveExecutablePath(requestedPath, platform);
|
|
140
|
-
if (executable !== null) {
|
|
141
|
-
return executable;
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
return null;
|
|
146
|
-
}
|
|
147
|
-
async function revalidateExecutable(identity2, platform = process.platform) {
|
|
148
|
-
const current = await resolveExecutablePath(identity2.requestedPath, platform);
|
|
149
|
-
return current !== null && identity2.matches(current.identity);
|
|
150
|
-
}
|
|
151
|
-
function appendBounded(chunks, chunk, currentBytes, limitBytes) {
|
|
152
|
-
const nextBytes = currentBytes + chunk.byteLength;
|
|
153
|
-
if (nextBytes > limitBytes) {
|
|
154
|
-
throw new ProcessExecutionError(
|
|
155
|
-
"process_output_limit",
|
|
156
|
-
"The executable produced too much output"
|
|
157
|
-
);
|
|
158
|
-
}
|
|
159
|
-
chunks.push(chunk);
|
|
160
|
-
return nextBytes;
|
|
161
|
-
}
|
|
162
|
-
function parseProcessTable(output2) {
|
|
163
|
-
const entries = [];
|
|
164
|
-
for (const line of output2.split("\n")) {
|
|
165
|
-
const groups = /^\s*(?<pid>\d+)\s+(?<ppid>\d+)\s+(?<pgid>\d+)\s*$/.exec(
|
|
166
|
-
line
|
|
167
|
-
)?.groups;
|
|
168
|
-
if (groups === void 0) {
|
|
169
|
-
continue;
|
|
170
|
-
}
|
|
171
|
-
const processId = Number(groups["pid"]);
|
|
172
|
-
const parentProcessId = Number(groups["ppid"]);
|
|
173
|
-
const processGroupId = Number(groups["pgid"]);
|
|
174
|
-
if (!Number.isSafeInteger(processId) || processId <= 0 || !Number.isSafeInteger(parentProcessId) || parentProcessId < 0 || !Number.isSafeInteger(processGroupId) || processGroupId <= 0) {
|
|
175
|
-
continue;
|
|
176
|
-
}
|
|
177
|
-
entries.push({ parentProcessId, processGroupId, processId });
|
|
178
|
-
}
|
|
179
|
-
return entries;
|
|
180
|
-
}
|
|
181
|
-
function readProcessTable() {
|
|
182
|
-
if (process.platform === "win32") {
|
|
183
|
-
return Promise.resolve([]);
|
|
184
|
-
}
|
|
185
|
-
const executable = process.platform === "darwin" ? "/bin/ps" : "/usr/bin/ps";
|
|
186
|
-
return new Promise((resolveTable) => {
|
|
187
|
-
execFile(
|
|
188
|
-
executable,
|
|
189
|
-
["-axo", "pid=,ppid=,pgid="],
|
|
190
|
-
{
|
|
191
|
-
encoding: "utf8",
|
|
192
|
-
maxBuffer: PROCESS_TABLE_OUTPUT_LIMIT_BYTES,
|
|
193
|
-
signal: AbortSignal.timeout(PROCESS_TABLE_TIMEOUT_MILLISECONDS),
|
|
194
|
-
timeout: PROCESS_TABLE_TIMEOUT_MILLISECONDS
|
|
195
|
-
},
|
|
196
|
-
(error61, stdout) => {
|
|
197
|
-
resolveTable(error61 === null ? parseProcessTable(stdout) : []);
|
|
198
|
-
}
|
|
199
|
-
);
|
|
200
|
-
});
|
|
201
|
-
}
|
|
202
|
-
function selectProcessTree(entries, rootProcessId) {
|
|
203
|
-
const processIds = /* @__PURE__ */ new Set([rootProcessId]);
|
|
204
|
-
let previousSize = 0;
|
|
205
|
-
while (previousSize !== processIds.size) {
|
|
206
|
-
previousSize = processIds.size;
|
|
207
|
-
for (const entry of entries) {
|
|
208
|
-
if (processIds.has(entry.parentProcessId)) {
|
|
209
|
-
processIds.add(entry.processId);
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
return entries.filter((entry) => processIds.has(entry.processId)).map((entry) => ({
|
|
214
|
-
processGroupId: entry.processGroupId,
|
|
215
|
-
processId: entry.processId
|
|
216
|
-
}));
|
|
217
|
-
}
|
|
218
|
-
function mergeProcessTrees(captured, current) {
|
|
219
|
-
const processes = /* @__PURE__ */ new Map();
|
|
220
|
-
for (const identity2 of captured) {
|
|
221
|
-
processes.set(identity2.processId, identity2);
|
|
222
|
-
}
|
|
223
|
-
for (const identity2 of current) {
|
|
224
|
-
processes.set(identity2.processId, identity2);
|
|
225
|
-
}
|
|
226
|
-
return [...processes.values()];
|
|
227
|
-
}
|
|
228
|
-
async function captureProcessTree(child) {
|
|
229
|
-
if (process.platform === "win32" || child.pid === void 0) {
|
|
230
|
-
return [];
|
|
231
|
-
}
|
|
232
|
-
return selectProcessTree(await readProcessTable(), child.pid);
|
|
233
|
-
}
|
|
234
|
-
function signalDetachedProcessGroups(processes, rootProcessId, signal) {
|
|
235
|
-
const processIds = new Set(processes.map((identity2) => identity2.processId));
|
|
236
|
-
const signalledGroups = /* @__PURE__ */ new Set();
|
|
237
|
-
for (const identity2 of processes) {
|
|
238
|
-
if (identity2.processGroupId === rootProcessId || !processIds.has(identity2.processGroupId) || signalledGroups.has(identity2.processGroupId)) {
|
|
239
|
-
continue;
|
|
240
|
-
}
|
|
241
|
-
try {
|
|
242
|
-
process.kill(-identity2.processGroupId, signal);
|
|
243
|
-
signalledGroups.add(identity2.processGroupId);
|
|
244
|
-
} catch {
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
for (const identity2 of processes) {
|
|
248
|
-
if (identity2.processId === rootProcessId || identity2.processGroupId === rootProcessId || signalledGroups.has(identity2.processGroupId)) {
|
|
249
|
-
continue;
|
|
250
|
-
}
|
|
251
|
-
try {
|
|
252
|
-
process.kill(identity2.processId, signal);
|
|
253
|
-
} catch {
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
function processExists(processId) {
|
|
258
|
-
try {
|
|
259
|
-
process.kill(processId, 0);
|
|
260
|
-
return true;
|
|
261
|
-
} catch {
|
|
262
|
-
return false;
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
async function waitForCapturedProcessesExit(processes, rootProcessId) {
|
|
266
|
-
const processIds = processes.map((identity2) => identity2.processId).filter((processId) => processId !== rootProcessId);
|
|
267
|
-
for (let attempt = 0; attempt < PROCESS_EXIT_CHECK_ATTEMPTS; attempt += 1) {
|
|
268
|
-
if (processIds.every((processId) => !processExists(processId))) {
|
|
269
|
-
return true;
|
|
270
|
-
}
|
|
271
|
-
await readProcessTable();
|
|
272
|
-
}
|
|
273
|
-
return processIds.every((processId) => !processExists(processId));
|
|
274
|
-
}
|
|
275
|
-
function terminateProcess(child) {
|
|
276
|
-
if (child.exitCode !== null || child.signalCode !== null || child.pid === void 0) {
|
|
277
|
-
return;
|
|
278
|
-
}
|
|
279
|
-
if (process.platform !== "win32") {
|
|
280
|
-
try {
|
|
281
|
-
process.kill(-child.pid, "SIGTERM");
|
|
282
|
-
return;
|
|
283
|
-
} catch {
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
child.kill("SIGTERM");
|
|
287
|
-
}
|
|
288
|
-
function forceTerminateProcess(child) {
|
|
289
|
-
if (child.exitCode !== null || child.signalCode !== null || child.pid === void 0) {
|
|
290
|
-
return;
|
|
291
|
-
}
|
|
292
|
-
if (process.platform !== "win32") {
|
|
293
|
-
try {
|
|
294
|
-
process.kill(-child.pid, "SIGKILL");
|
|
295
|
-
return;
|
|
296
|
-
} catch {
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
child.kill("SIGKILL");
|
|
300
|
-
}
|
|
301
|
-
async function stopProcessTree(child, capturedProcesses = []) {
|
|
302
|
-
const childProcessId = child.pid;
|
|
303
|
-
if (childProcessId === void 0) {
|
|
304
|
-
return;
|
|
305
|
-
}
|
|
306
|
-
const childExited = child.exitCode !== null || child.signalCode !== null;
|
|
307
|
-
if (childExited && capturedProcesses.length === 0) {
|
|
308
|
-
return;
|
|
309
|
-
}
|
|
310
|
-
const processes = mergeProcessTrees(
|
|
311
|
-
capturedProcesses,
|
|
312
|
-
childExited ? [] : await captureProcessTree(child)
|
|
313
|
-
);
|
|
314
|
-
signalDetachedProcessGroups(processes, childProcessId, GRACEFUL_STOP_SIGNAL);
|
|
315
|
-
terminateProcess(child);
|
|
316
|
-
const [exitedAfterTermination, descendantsExitedAfterTermination] = await Promise.all([
|
|
317
|
-
waitForProcessExit(child, PROCESS_GRACEFUL_STOP_TIMEOUT_MILLISECONDS),
|
|
318
|
-
waitForCapturedProcessesExit(processes, childProcessId)
|
|
319
|
-
]);
|
|
320
|
-
if (exitedAfterTermination && descendantsExitedAfterTermination) {
|
|
321
|
-
return;
|
|
322
|
-
}
|
|
323
|
-
signalDetachedProcessGroups(processes, childProcessId, FORCED_STOP_SIGNAL);
|
|
324
|
-
forceTerminateProcess(child);
|
|
325
|
-
const [exitedAfterForce, descendantsExitedAfterForce] = await Promise.all([
|
|
326
|
-
waitForProcessExit(child, PROCESS_FORCED_STOP_TIMEOUT_MILLISECONDS),
|
|
327
|
-
waitForCapturedProcessesExit(processes, childProcessId)
|
|
328
|
-
]);
|
|
329
|
-
if (!exitedAfterForce || !descendantsExitedAfterForce) {
|
|
330
|
-
throw new ProcessExecutionError(
|
|
331
|
-
"process_termination_timeout",
|
|
332
|
-
"The executable process could not be stopped"
|
|
333
|
-
);
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
function waitForProcessExit(child, timeoutMilliseconds) {
|
|
337
|
-
if (child.exitCode !== null || child.signalCode !== null) {
|
|
338
|
-
return Promise.resolve(true);
|
|
339
|
-
}
|
|
340
|
-
return new Promise((resolveExit) => {
|
|
341
|
-
let settled = false;
|
|
342
|
-
const finish = (exited) => {
|
|
343
|
-
if (settled) {
|
|
344
|
-
return;
|
|
345
|
-
}
|
|
346
|
-
settled = true;
|
|
347
|
-
clearTimeout(timeout);
|
|
348
|
-
child.removeListener("exit", handleExit);
|
|
349
|
-
resolveExit(exited);
|
|
350
|
-
};
|
|
351
|
-
const handleExit = () => finish(true);
|
|
352
|
-
const timeout = setTimeout(() => finish(false), timeoutMilliseconds);
|
|
353
|
-
child.once("exit", handleExit);
|
|
354
|
-
if (child.exitCode !== null || child.signalCode !== null) {
|
|
355
|
-
finish(true);
|
|
356
|
-
}
|
|
357
|
-
});
|
|
358
|
-
}
|
|
359
|
-
async function runBoundedProcess(options) {
|
|
360
|
-
options.signal.throwIfAborted();
|
|
361
|
-
const outputLimitBytes = options.outputLimitBytes ?? DEFAULT_OUTPUT_LIMIT_BYTES;
|
|
362
|
-
const child = spawn(options.command, [...options.arguments], {
|
|
363
|
-
cwd: options.cwd,
|
|
364
|
-
detached: process.platform !== "win32",
|
|
365
|
-
env: { ...options.environment },
|
|
366
|
-
shell: false,
|
|
367
|
-
stdio: ["ignore", "pipe", "pipe"]
|
|
368
|
-
});
|
|
369
|
-
const stdout = [];
|
|
370
|
-
const stderr = [];
|
|
371
|
-
let stdoutBytes = 0;
|
|
372
|
-
let stderrBytes = 0;
|
|
373
|
-
let interruptionFailure = null;
|
|
374
|
-
let interruptionCleanupFailure = null;
|
|
375
|
-
let stopping = false;
|
|
376
|
-
const interrupted = Promise.withResolvers();
|
|
377
|
-
const interrupt = (failure) => {
|
|
378
|
-
if (stopping) {
|
|
379
|
-
return;
|
|
380
|
-
}
|
|
381
|
-
stopping = true;
|
|
382
|
-
interruptionFailure = failure;
|
|
383
|
-
const stop = async () => {
|
|
384
|
-
try {
|
|
385
|
-
await stopProcessTree(child);
|
|
386
|
-
} catch (error61) {
|
|
387
|
-
interruptionCleanupFailure = error61 instanceof ProcessExecutionError ? error61 : new ProcessExecutionError(
|
|
388
|
-
"process_termination_failed",
|
|
389
|
-
"The executable process could not be stopped",
|
|
390
|
-
{ cause: error61 }
|
|
391
|
-
);
|
|
392
|
-
} finally {
|
|
393
|
-
interrupted.resolve();
|
|
394
|
-
}
|
|
395
|
-
};
|
|
396
|
-
void stop();
|
|
397
|
-
};
|
|
398
|
-
const collectStdout = (chunk) => {
|
|
399
|
-
if (interruptionFailure !== null) {
|
|
400
|
-
return;
|
|
401
|
-
}
|
|
402
|
-
try {
|
|
403
|
-
stdoutBytes = appendBounded(stdout, chunk, stdoutBytes, outputLimitBytes);
|
|
404
|
-
} catch (error61) {
|
|
405
|
-
const failure = error61 instanceof ProcessExecutionError ? error61 : new ProcessExecutionError(
|
|
406
|
-
"process_output_limit",
|
|
407
|
-
"The executable produced too much output",
|
|
408
|
-
{ cause: error61 }
|
|
409
|
-
);
|
|
410
|
-
interrupt(failure);
|
|
411
|
-
}
|
|
412
|
-
};
|
|
413
|
-
const collectStderr = (chunk) => {
|
|
414
|
-
if (interruptionFailure !== null) {
|
|
415
|
-
return;
|
|
416
|
-
}
|
|
417
|
-
try {
|
|
418
|
-
stderrBytes = appendBounded(stderr, chunk, stderrBytes, outputLimitBytes);
|
|
419
|
-
} catch (error61) {
|
|
420
|
-
const failure = error61 instanceof ProcessExecutionError ? error61 : new ProcessExecutionError(
|
|
421
|
-
"process_output_limit",
|
|
422
|
-
"The executable produced too much output",
|
|
423
|
-
{ cause: error61 }
|
|
424
|
-
);
|
|
425
|
-
interrupt(failure);
|
|
426
|
-
}
|
|
427
|
-
};
|
|
428
|
-
child.stdout?.on("data", collectStdout);
|
|
429
|
-
child.stderr?.on("data", collectStderr);
|
|
430
|
-
const timeout = setTimeout(() => {
|
|
431
|
-
interrupt(
|
|
432
|
-
new ProcessExecutionError(
|
|
433
|
-
"process_timeout",
|
|
434
|
-
"The executable probe timed out"
|
|
435
|
-
)
|
|
436
|
-
);
|
|
437
|
-
}, options.timeoutMilliseconds);
|
|
438
|
-
const abort = () => interrupt(
|
|
439
|
-
new ProcessExecutionError(
|
|
440
|
-
"process_cancelled",
|
|
441
|
-
"The executable probe was cancelled",
|
|
442
|
-
{ cause: options.signal.reason }
|
|
443
|
-
)
|
|
444
|
-
);
|
|
445
|
-
options.signal.addEventListener("abort", abort, { once: true });
|
|
446
|
-
if (options.signal.aborted) {
|
|
447
|
-
abort();
|
|
448
|
-
}
|
|
449
|
-
try {
|
|
450
|
-
const exit = new Promise((resolveExit, rejectExit) => {
|
|
451
|
-
child.once("error", rejectExit);
|
|
452
|
-
child.once("exit", (code) => resolveExit(code ?? 1));
|
|
453
|
-
});
|
|
454
|
-
const exitCode = await Promise.race([
|
|
455
|
-
exit,
|
|
456
|
-
interrupted.promise.then(() => -1)
|
|
457
|
-
]);
|
|
458
|
-
if (interruptionCleanupFailure !== null) {
|
|
459
|
-
throw interruptionCleanupFailure;
|
|
460
|
-
}
|
|
461
|
-
if (interruptionFailure !== null) {
|
|
462
|
-
throw interruptionFailure;
|
|
463
|
-
}
|
|
464
|
-
if (exitCode !== 0) {
|
|
465
|
-
throw new ProcessExecutionError(
|
|
466
|
-
"process_exit_failed",
|
|
467
|
-
"The executable probe failed"
|
|
468
|
-
);
|
|
469
|
-
}
|
|
470
|
-
return new ProcessResult(
|
|
471
|
-
Buffer.concat(stdout).toString("utf8"),
|
|
472
|
-
Buffer.concat(stderr).toString("utf8")
|
|
473
|
-
);
|
|
474
|
-
} catch (error61) {
|
|
475
|
-
if (error61 instanceof ProcessExecutionError) {
|
|
476
|
-
throw error61;
|
|
477
|
-
}
|
|
478
|
-
throw new ProcessExecutionError(
|
|
479
|
-
"process_spawn_failed",
|
|
480
|
-
"The executable could not be started",
|
|
481
|
-
{ cause: error61 }
|
|
482
|
-
);
|
|
483
|
-
} finally {
|
|
484
|
-
clearTimeout(timeout);
|
|
485
|
-
options.signal.removeEventListener("abort", abort);
|
|
486
|
-
child.stdout?.removeListener("data", collectStdout);
|
|
487
|
-
child.stderr?.removeListener("data", collectStderr);
|
|
488
|
-
if (stopping) {
|
|
489
|
-
await interrupted.promise;
|
|
490
|
-
} else {
|
|
491
|
-
await stopProcessTree(child);
|
|
492
|
-
}
|
|
493
|
-
}
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
// src/agent-catalog/local-agent.ts
|
|
497
|
-
function readTrustedIdentity(path2) {
|
|
498
|
-
const resolvedPath = realpathSync(path2);
|
|
499
|
-
const metadata = statSync(resolvedPath);
|
|
500
|
-
return new ExecutableIdentity(
|
|
501
|
-
resolvedPath,
|
|
502
|
-
resolvedPath,
|
|
503
|
-
metadata.dev,
|
|
504
|
-
metadata.ino,
|
|
505
|
-
metadata.size,
|
|
506
|
-
metadata.ctimeMs
|
|
507
|
-
);
|
|
508
|
-
}
|
|
509
|
-
var LocalAgentDefinition = class {
|
|
510
|
-
adapterIdentity;
|
|
511
|
-
adapterPath;
|
|
512
|
-
adapterVersion;
|
|
513
|
-
agentIdentity;
|
|
514
|
-
agentVersion;
|
|
515
|
-
arguments;
|
|
516
|
-
command;
|
|
517
|
-
environment;
|
|
518
|
-
id;
|
|
519
|
-
label;
|
|
520
|
-
promptTimeoutMilliseconds;
|
|
521
|
-
constructor(id, label, command, arguments_, environment = {}, adapterVersion = "", agentVersion = "", adapterIdentity = readTrustedIdentity(command), agentIdentity = adapterIdentity, promptTimeoutMilliseconds = 30 * 60 * 1e3) {
|
|
522
|
-
if (!Number.isSafeInteger(promptTimeoutMilliseconds) || promptTimeoutMilliseconds < 1) {
|
|
523
|
-
throw new Error("The local Agent prompt deadline is invalid");
|
|
524
|
-
}
|
|
525
|
-
this.adapterIdentity = adapterIdentity;
|
|
526
|
-
this.adapterPath = adapterIdentity.realPath;
|
|
527
|
-
this.adapterVersion = adapterVersion;
|
|
528
|
-
this.agentIdentity = agentIdentity;
|
|
529
|
-
this.agentVersion = agentVersion;
|
|
530
|
-
this.id = id;
|
|
531
|
-
this.label = label;
|
|
532
|
-
this.promptTimeoutMilliseconds = promptTimeoutMilliseconds;
|
|
533
|
-
this.command = adapterIdentity.realPath;
|
|
534
|
-
this.arguments = Object.freeze([...arguments_]);
|
|
535
|
-
this.environment = Object.freeze({ ...environment });
|
|
536
|
-
}
|
|
537
|
-
};
|
|
538
|
-
var InstallableAgentDefinition = class {
|
|
539
|
-
id;
|
|
540
|
-
label;
|
|
541
|
-
requiresLocalApproval;
|
|
542
|
-
constructor(id, label, requiresLocalApproval = true) {
|
|
543
|
-
this.id = id;
|
|
544
|
-
this.label = label;
|
|
545
|
-
this.requiresLocalApproval = requiresLocalApproval;
|
|
546
|
-
}
|
|
547
|
-
};
|
|
548
|
-
var LocalAgentCatalogSnapshot = class {
|
|
549
|
-
agents;
|
|
550
|
-
installableAgents;
|
|
551
|
-
constructor(agents, installableAgents) {
|
|
552
|
-
this.agents = Object.freeze([...agents]);
|
|
553
|
-
this.installableAgents = Object.freeze([...installableAgents]);
|
|
554
|
-
}
|
|
555
|
-
};
|
|
556
|
-
var LocalAgentCatalogError = class extends Error {
|
|
557
|
-
code = "agent_not_ready";
|
|
558
|
-
constructor() {
|
|
559
|
-
super("The requested local Agent is not ready");
|
|
560
|
-
this.name = "LocalAgentCatalogError";
|
|
561
|
-
}
|
|
562
|
-
};
|
|
563
|
-
var LocalAgentCatalog = class {
|
|
564
|
-
#snapshot;
|
|
565
|
-
constructor(agents, installableAgents) {
|
|
566
|
-
this.#snapshot = this.validate(agents, installableAgents);
|
|
567
|
-
}
|
|
568
|
-
find = (agentId) => {
|
|
569
|
-
for (const agent of this.#snapshot.agents) {
|
|
570
|
-
if (agent.id === agentId) {
|
|
571
|
-
return agent;
|
|
572
|
-
}
|
|
573
|
-
}
|
|
574
|
-
throw new LocalAgentCatalogError();
|
|
575
|
-
};
|
|
576
|
-
read = () => this.#snapshot;
|
|
577
|
-
transition = (agents, installableAgents) => {
|
|
578
|
-
const next = this.validate(agents, installableAgents);
|
|
579
|
-
this.#snapshot = next;
|
|
580
|
-
return next;
|
|
581
|
-
};
|
|
582
|
-
validate = (agents, installableAgents) => {
|
|
583
|
-
const identifiers = /* @__PURE__ */ new Set();
|
|
584
|
-
for (const agent of agents) {
|
|
585
|
-
if (identifiers.has(agent.id)) {
|
|
586
|
-
throw new Error("The local Agent catalog contains duplicate entries");
|
|
587
|
-
}
|
|
588
|
-
identifiers.add(agent.id);
|
|
589
|
-
}
|
|
590
|
-
for (const agent of installableAgents) {
|
|
591
|
-
if (identifiers.has(agent.id)) {
|
|
592
|
-
throw new Error("A local Agent cannot be ready and installable");
|
|
593
|
-
}
|
|
594
|
-
identifiers.add(agent.id);
|
|
595
|
-
}
|
|
596
|
-
return new LocalAgentCatalogSnapshot(agents, installableAgents);
|
|
597
|
-
};
|
|
598
|
-
};
|
|
599
|
-
|
|
600
|
-
// src/storage/state-directory.ts
|
|
601
|
-
import { homedir } from "node:os";
|
|
602
|
-
import { join as join2, resolve as resolve2 } from "node:path";
|
|
603
|
-
function readStateDirectory(environment = process.env) {
|
|
604
|
-
const configured = environment["MOBIUS_STATE_DIRECTORY"]?.trim();
|
|
605
|
-
if (configured !== void 0 && configured.length > 0) {
|
|
606
|
-
return resolve2(configured);
|
|
607
|
-
}
|
|
608
|
-
return join2(homedir(), ".mobius");
|
|
609
|
-
}
|
|
610
|
-
|
|
611
|
-
// src/config.ts
|
|
612
|
-
function loadDefaultWorkspace() {
|
|
613
|
-
const { MOBIUS_DEFAULT_WORKSPACE: configuredWorkspace } = process.env;
|
|
614
|
-
return configuredWorkspace ?? join3(readStateDirectory(), "workspace");
|
|
615
|
-
}
|
|
616
|
-
function createDaemonConfig(connection, agents = [], installableAgents = []) {
|
|
617
|
-
return {
|
|
618
|
-
agents,
|
|
619
|
-
defaultWorkspace: connection.defaultWorkspace,
|
|
620
|
-
auditDatabasePath: connection.auditDatabasePath,
|
|
621
|
-
bindingId: "workspace",
|
|
622
|
-
catalog: new LocalAgentCatalog(agents, installableAgents),
|
|
623
|
-
channelId: connection.channelId,
|
|
624
|
-
installableAgents,
|
|
625
|
-
relayUrl: connection.relayUrl
|
|
626
|
-
};
|
|
627
|
-
}
|
|
628
|
-
function loadDaemonConfig() {
|
|
629
|
-
const relayUrl = new URL(
|
|
630
|
-
// biome-ignore lint/complexity/useLiteralKeys: Environment variables use an index signature.
|
|
631
|
-
process.env["MOBIUS_RELAY_URL"] ?? "ws://127.0.0.1:8787/mobius/api/channels/local/daemon"
|
|
632
|
-
);
|
|
633
|
-
relayUrl.searchParams.set(
|
|
634
|
-
"token",
|
|
635
|
-
// biome-ignore lint/complexity/useLiteralKeys: Environment variables use an index signature.
|
|
636
|
-
process.env["MOBIUS_RELAY_TOKEN"] ?? "local-development-token"
|
|
637
|
-
);
|
|
638
|
-
if (relayUrl.protocol !== "ws:" && relayUrl.protocol !== "wss:") {
|
|
639
|
-
throw new Error("MOBIUS_RELAY_URL must use ws or wss");
|
|
640
|
-
}
|
|
641
|
-
return createDaemonConfig(
|
|
642
|
-
{
|
|
643
|
-
defaultWorkspace: loadDefaultWorkspace(),
|
|
644
|
-
auditDatabasePath: (
|
|
645
|
-
// biome-ignore lint/complexity/useLiteralKeys: Environment variables use an index signature.
|
|
646
|
-
process.env["MOBIUS_AUDIT_DATABASE"] ?? fileURLToPath(
|
|
647
|
-
new URL("../../../.mobius/daemon.sqlite", import.meta.url)
|
|
648
|
-
)
|
|
649
|
-
),
|
|
650
|
-
// biome-ignore lint/complexity/useLiteralKeys: Environment variables use an index signature.
|
|
651
|
-
channelId: process.env["MOBIUS_CHANNEL_ID"] ?? "local",
|
|
652
|
-
relayUrl
|
|
653
|
-
},
|
|
654
|
-
[],
|
|
655
|
-
[]
|
|
656
|
-
);
|
|
657
|
-
}
|
|
658
|
-
|
|
659
|
-
// src/acp/session-manager.ts
|
|
660
|
-
import { spawn as spawn2 } from "node:child_process";
|
|
661
|
-
import {
|
|
662
|
-
methods as methods2,
|
|
663
|
-
ndJsonStream,
|
|
664
|
-
PROTOCOL_VERSION,
|
|
665
|
-
RequestError
|
|
666
|
-
} from "@agentclientprotocol/sdk";
|
|
667
|
-
|
|
668
50
|
// ../../node_modules/.pnpm/zod@4.5.4/node_modules/zod/v4/classic/external.js
|
|
669
51
|
var external_exports = {};
|
|
670
52
|
__export(external_exports, {
|
|
@@ -2625,8 +2007,8 @@ function emoji() {
|
|
|
2625
2007
|
}
|
|
2626
2008
|
var ipv4 = /^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$/;
|
|
2627
2009
|
var ipv6 = /^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:))$/;
|
|
2628
|
-
var mac = (
|
|
2629
|
-
const escapedDelim = escapeRegex(
|
|
2010
|
+
var mac = (delimiter3) => {
|
|
2011
|
+
const escapedDelim = escapeRegex(delimiter3 ?? ":");
|
|
2630
2012
|
return new RegExp(`^(?:[0-9A-F]{2}${escapedDelim}){5}[0-9A-F]{2}$|^(?:[0-9a-f]{2}${escapedDelim}){5}[0-9a-f]{2}$`);
|
|
2631
2013
|
};
|
|
2632
2014
|
var cidrv4 = /^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\/([0-9]|[1-2][0-9]|3[0-2])$/;
|
|
@@ -19601,7 +18983,6 @@ var SESSION_OPERATION_FAILED_KIND = "session.operation.failed";
|
|
|
19601
18983
|
var AGENT_CONTENT_KIND = "agent.content";
|
|
19602
18984
|
var AGENT_INSTALL_REQUEST_KIND = "agent.install.request";
|
|
19603
18985
|
var AGENT_INSTALL_CANCEL_KIND = "agent.install.cancel";
|
|
19604
|
-
var AGENT_INSTALL_AWAITING_APPROVAL_KIND = "agent.install.awaiting_approval";
|
|
19605
18986
|
var AGENT_INSTALL_STARTED_KIND = "agent.install.started";
|
|
19606
18987
|
var AGENT_INSTALL_PROGRESS_KIND = "agent.install.progress";
|
|
19607
18988
|
var AGENT_INSTALL_COMPLETED_KIND = "agent.install.completed";
|
|
@@ -19907,10 +19288,6 @@ var agentInstallCancelCommandSchema = external_exports.strictObject({
|
|
|
19907
19288
|
kind: external_exports.literal(AGENT_INSTALL_CANCEL_KIND),
|
|
19908
19289
|
requestId: IDENTIFIER
|
|
19909
19290
|
}).readonly();
|
|
19910
|
-
var agentInstallAwaitingApprovalEventSchema = external_exports.strictObject({
|
|
19911
|
-
...agentInstallIdentityFields,
|
|
19912
|
-
kind: external_exports.literal(AGENT_INSTALL_AWAITING_APPROVAL_KIND)
|
|
19913
|
-
}).readonly();
|
|
19914
19291
|
var agentInstallStartedEventSchema = external_exports.strictObject({
|
|
19915
19292
|
...agentInstallIdentityFields,
|
|
19916
19293
|
kind: external_exports.literal(AGENT_INSTALL_STARTED_KIND)
|
|
@@ -19993,7 +19370,6 @@ var encodeSessionOperationFailedEvent = (message) => encode3(message, sessionOpe
|
|
|
19993
19370
|
var encodeAgentContentEvent = (message) => encode3(message, agentContentEventSchema);
|
|
19994
19371
|
var decodeAgentInstallRequestCommand = (encoded) => decode3(encoded, agentInstallRequestCommandSchema);
|
|
19995
19372
|
var decodeAgentInstallCancelCommand = (encoded) => decode3(encoded, agentInstallCancelCommandSchema);
|
|
19996
|
-
var encodeAgentInstallAwaitingApprovalEvent = (message) => encode3(message, agentInstallAwaitingApprovalEventSchema);
|
|
19997
19373
|
var encodeAgentInstallStartedEvent = (message) => encode3(message, agentInstallStartedEventSchema);
|
|
19998
19374
|
var encodeAgentInstallProgressEvent = (message) => encode3(message, agentInstallProgressEventSchema);
|
|
19999
19375
|
var encodeAgentInstallCompletedEvent = (message) => encode3(message, agentInstallCompletedEventSchema);
|
|
@@ -20393,6 +19769,29 @@ function encodeSessionFailedEvent(message) {
|
|
|
20393
19769
|
return JSON.stringify(decodeSessionFailedEvent(JSON.stringify(message)));
|
|
20394
19770
|
}
|
|
20395
19771
|
|
|
19772
|
+
// ../protocol/src/mobius-api.ts
|
|
19773
|
+
var MOBIUS_API_PREFIX = "/mobius/api";
|
|
19774
|
+
var API_PREFIX_PATTERN = /^\/[a-zA-Z0-9._~-]+(?:\/[a-zA-Z0-9._~-]+)*$/;
|
|
19775
|
+
var MobiusApiConfigurationError = class extends Error {
|
|
19776
|
+
code = "invalid_api_prefix";
|
|
19777
|
+
constructor() {
|
|
19778
|
+
super("The Mobius API prefix must be an absolute path without parameters");
|
|
19779
|
+
this.name = "MobiusApiConfigurationError";
|
|
19780
|
+
}
|
|
19781
|
+
};
|
|
19782
|
+
function parseMobiusApiPrefix(value) {
|
|
19783
|
+
if (typeof value !== "string" || !API_PREFIX_PATTERN.test(value)) {
|
|
19784
|
+
throw new MobiusApiConfigurationError();
|
|
19785
|
+
}
|
|
19786
|
+
return value;
|
|
19787
|
+
}
|
|
19788
|
+
function mobiusApiPath(resourcePath, apiPrefix = MOBIUS_API_PREFIX) {
|
|
19789
|
+
return `${parseMobiusApiPrefix(apiPrefix)}${resourcePath}`;
|
|
19790
|
+
}
|
|
19791
|
+
function mobiusApiUrl(origin, resourcePath, apiPrefix = MOBIUS_API_PREFIX) {
|
|
19792
|
+
return new URL(mobiusApiPath(resourcePath, apiPrefix), origin);
|
|
19793
|
+
}
|
|
19794
|
+
|
|
20396
19795
|
// ../protocol/src/session-history.ts
|
|
20397
19796
|
var SESSION_HISTORY_CHARACTER_LIMIT = 256e3;
|
|
20398
19797
|
var SESSION_HISTORY_MESSAGE_LIMIT = 1e3;
|
|
@@ -21084,29 +20483,667 @@ var eventAcknowledgementSchema = external_exports.strictObject({
|
|
|
21084
20483
|
function decode5(encoded, schema) {
|
|
21085
20484
|
let value;
|
|
21086
20485
|
try {
|
|
21087
|
-
value = JSON.parse(encoded);
|
|
21088
|
-
} catch (cause) {
|
|
21089
|
-
throw new ProtocolMessageError("Message is not valid JSON", { cause });
|
|
20486
|
+
value = JSON.parse(encoded);
|
|
20487
|
+
} catch (cause) {
|
|
20488
|
+
throw new ProtocolMessageError("Message is not valid JSON", { cause });
|
|
20489
|
+
}
|
|
20490
|
+
const decoded = schema.safeParse(value);
|
|
20491
|
+
if (!decoded.success) {
|
|
20492
|
+
throw new ProtocolMessageError("Message does not match its schema", {
|
|
20493
|
+
cause: decoded.error
|
|
20494
|
+
});
|
|
20495
|
+
}
|
|
20496
|
+
return decoded.data;
|
|
20497
|
+
}
|
|
20498
|
+
var encode4 = (message, schema) => {
|
|
20499
|
+
const decoded = schema.safeParse(message);
|
|
20500
|
+
if (!decoded.success) {
|
|
20501
|
+
throw new ProtocolMessageError("Message does not match its schema", {
|
|
20502
|
+
cause: decoded.error
|
|
20503
|
+
});
|
|
20504
|
+
}
|
|
20505
|
+
return JSON.stringify(decoded.data);
|
|
20506
|
+
};
|
|
20507
|
+
var encodeSessionEventEnvelope = (message) => encode4(message, eventEnvelopeSchema);
|
|
20508
|
+
var decodeSessionEventAcknowledgement = (encoded) => decode5(encoded, eventAcknowledgementSchema);
|
|
20509
|
+
|
|
20510
|
+
// src/agent-catalog/local-agent.ts
|
|
20511
|
+
import { realpathSync, statSync } from "node:fs";
|
|
20512
|
+
|
|
20513
|
+
// src/process/executable.ts
|
|
20514
|
+
import { execFile, spawn } from "node:child_process";
|
|
20515
|
+
import { constants } from "node:fs";
|
|
20516
|
+
import { access, realpath, stat } from "node:fs/promises";
|
|
20517
|
+
import { join, resolve } from "node:path";
|
|
20518
|
+
var DEFAULT_OUTPUT_LIMIT_BYTES = 16 * 1024;
|
|
20519
|
+
var PROCESS_GRACEFUL_STOP_TIMEOUT_MILLISECONDS = 1e3;
|
|
20520
|
+
var PROCESS_FORCED_STOP_TIMEOUT_MILLISECONDS = 5e3;
|
|
20521
|
+
var PROCESS_TABLE_TIMEOUT_MILLISECONDS = 1e3;
|
|
20522
|
+
var PROCESS_TABLE_OUTPUT_LIMIT_BYTES = 1024 * 1024;
|
|
20523
|
+
var PROCESS_EXIT_CHECK_ATTEMPTS = 8;
|
|
20524
|
+
var GRACEFUL_STOP_SIGNAL = 15;
|
|
20525
|
+
var FORCED_STOP_SIGNAL = 9;
|
|
20526
|
+
var ExecutableIdentity = class {
|
|
20527
|
+
changedAtMilliseconds;
|
|
20528
|
+
device;
|
|
20529
|
+
inode;
|
|
20530
|
+
realPath;
|
|
20531
|
+
requestedPath;
|
|
20532
|
+
size;
|
|
20533
|
+
constructor(requestedPath, realPath_, device, inode, size, changedAtMilliseconds) {
|
|
20534
|
+
this.changedAtMilliseconds = changedAtMilliseconds;
|
|
20535
|
+
this.device = device;
|
|
20536
|
+
this.inode = inode;
|
|
20537
|
+
this.realPath = realPath_;
|
|
20538
|
+
this.requestedPath = requestedPath;
|
|
20539
|
+
this.size = size;
|
|
20540
|
+
}
|
|
20541
|
+
matches = (candidate) => this.requestedPath === candidate.requestedPath && this.realPath === candidate.realPath && this.device === candidate.device && this.inode === candidate.inode && this.size === candidate.size && this.changedAtMilliseconds === candidate.changedAtMilliseconds;
|
|
20542
|
+
};
|
|
20543
|
+
var ResolvedExecutable = class {
|
|
20544
|
+
identity;
|
|
20545
|
+
path;
|
|
20546
|
+
constructor(identity2) {
|
|
20547
|
+
this.identity = identity2;
|
|
20548
|
+
this.path = identity2.realPath;
|
|
20549
|
+
}
|
|
20550
|
+
};
|
|
20551
|
+
var ProcessExecutionError = class extends Error {
|
|
20552
|
+
code;
|
|
20553
|
+
constructor(code, message, options = {}) {
|
|
20554
|
+
super(message, options);
|
|
20555
|
+
this.code = code;
|
|
20556
|
+
this.name = "ProcessExecutionError";
|
|
20557
|
+
}
|
|
20558
|
+
};
|
|
20559
|
+
var ProcessResult = class {
|
|
20560
|
+
stderr;
|
|
20561
|
+
stdout;
|
|
20562
|
+
constructor(stdout, stderr) {
|
|
20563
|
+
this.stderr = stderr;
|
|
20564
|
+
this.stdout = stdout;
|
|
20565
|
+
}
|
|
20566
|
+
};
|
|
20567
|
+
function executableExtensions(executableName, environment, platform) {
|
|
20568
|
+
if (platform !== "win32") {
|
|
20569
|
+
return [""];
|
|
20570
|
+
}
|
|
20571
|
+
if (/\.[a-zA-Z0-9]+$/.test(executableName)) {
|
|
20572
|
+
return [""];
|
|
20573
|
+
}
|
|
20574
|
+
const configured = environment["PATHEXT"] ?? ".COM;.EXE;.BAT;.CMD";
|
|
20575
|
+
const extensions = configured.split(";").map((extension) => extension.trim()).filter((extension) => extension.length > 0).map(
|
|
20576
|
+
(extension) => extension.startsWith(".") ? extension : `.${extension}`
|
|
20577
|
+
);
|
|
20578
|
+
return extensions.length > 0 ? extensions : [".EXE"];
|
|
20579
|
+
}
|
|
20580
|
+
async function resolveExecutablePath(requestedPath, platform = process.platform) {
|
|
20581
|
+
const absoluteRequestedPath = resolve(requestedPath);
|
|
20582
|
+
try {
|
|
20583
|
+
const resolvedPath = await realpath(absoluteRequestedPath);
|
|
20584
|
+
const metadata = await stat(resolvedPath);
|
|
20585
|
+
if (!metadata.isFile()) {
|
|
20586
|
+
return null;
|
|
20587
|
+
}
|
|
20588
|
+
if (platform !== "win32") {
|
|
20589
|
+
await access(resolvedPath, constants.X_OK);
|
|
20590
|
+
}
|
|
20591
|
+
return new ResolvedExecutable(
|
|
20592
|
+
new ExecutableIdentity(
|
|
20593
|
+
absoluteRequestedPath,
|
|
20594
|
+
resolvedPath,
|
|
20595
|
+
metadata.dev,
|
|
20596
|
+
metadata.ino,
|
|
20597
|
+
metadata.size,
|
|
20598
|
+
metadata.ctimeMs
|
|
20599
|
+
)
|
|
20600
|
+
);
|
|
20601
|
+
} catch {
|
|
20602
|
+
return null;
|
|
20603
|
+
}
|
|
20604
|
+
}
|
|
20605
|
+
async function findExecutableOnPath(executableName, environment, platform = process.platform) {
|
|
20606
|
+
const encodedPath = environment["PATH"] ?? "";
|
|
20607
|
+
const separator = platform === "win32" ? ";" : ":";
|
|
20608
|
+
const extensions = executableExtensions(
|
|
20609
|
+
executableName,
|
|
20610
|
+
environment,
|
|
20611
|
+
platform
|
|
20612
|
+
);
|
|
20613
|
+
for (const entry of encodedPath.split(separator)) {
|
|
20614
|
+
if (entry.length === 0) {
|
|
20615
|
+
continue;
|
|
20616
|
+
}
|
|
20617
|
+
for (const extension of extensions) {
|
|
20618
|
+
const requestedPath = resolve(
|
|
20619
|
+
join(entry, `${executableName}${extension}`)
|
|
20620
|
+
);
|
|
20621
|
+
const executable = await resolveExecutablePath(requestedPath, platform);
|
|
20622
|
+
if (executable !== null) {
|
|
20623
|
+
return executable;
|
|
20624
|
+
}
|
|
20625
|
+
}
|
|
20626
|
+
}
|
|
20627
|
+
return null;
|
|
20628
|
+
}
|
|
20629
|
+
async function revalidateExecutable(identity2, platform = process.platform) {
|
|
20630
|
+
const current = await resolveExecutablePath(identity2.requestedPath, platform);
|
|
20631
|
+
return current !== null && identity2.matches(current.identity);
|
|
20632
|
+
}
|
|
20633
|
+
function appendBounded(chunks, chunk, currentBytes, limitBytes) {
|
|
20634
|
+
const nextBytes = currentBytes + chunk.byteLength;
|
|
20635
|
+
if (nextBytes > limitBytes) {
|
|
20636
|
+
throw new ProcessExecutionError(
|
|
20637
|
+
"process_output_limit",
|
|
20638
|
+
"The executable produced too much output"
|
|
20639
|
+
);
|
|
20640
|
+
}
|
|
20641
|
+
chunks.push(chunk);
|
|
20642
|
+
return nextBytes;
|
|
20643
|
+
}
|
|
20644
|
+
function parseProcessTable(output2) {
|
|
20645
|
+
const entries = [];
|
|
20646
|
+
for (const line of output2.split("\n")) {
|
|
20647
|
+
const groups = /^\s*(?<pid>\d+)\s+(?<ppid>\d+)\s+(?<pgid>\d+)\s*$/.exec(
|
|
20648
|
+
line
|
|
20649
|
+
)?.groups;
|
|
20650
|
+
if (groups === void 0) {
|
|
20651
|
+
continue;
|
|
20652
|
+
}
|
|
20653
|
+
const processId = Number(groups["pid"]);
|
|
20654
|
+
const parentProcessId = Number(groups["ppid"]);
|
|
20655
|
+
const processGroupId = Number(groups["pgid"]);
|
|
20656
|
+
if (!Number.isSafeInteger(processId) || processId <= 0 || !Number.isSafeInteger(parentProcessId) || parentProcessId < 0 || !Number.isSafeInteger(processGroupId) || processGroupId <= 0) {
|
|
20657
|
+
continue;
|
|
20658
|
+
}
|
|
20659
|
+
entries.push({ parentProcessId, processGroupId, processId });
|
|
20660
|
+
}
|
|
20661
|
+
return entries;
|
|
20662
|
+
}
|
|
20663
|
+
function readProcessTable() {
|
|
20664
|
+
if (process.platform === "win32") {
|
|
20665
|
+
return Promise.resolve([]);
|
|
20666
|
+
}
|
|
20667
|
+
const executable = process.platform === "darwin" ? "/bin/ps" : "/usr/bin/ps";
|
|
20668
|
+
return new Promise((resolveTable) => {
|
|
20669
|
+
execFile(
|
|
20670
|
+
executable,
|
|
20671
|
+
["-axo", "pid=,ppid=,pgid="],
|
|
20672
|
+
{
|
|
20673
|
+
encoding: "utf8",
|
|
20674
|
+
maxBuffer: PROCESS_TABLE_OUTPUT_LIMIT_BYTES,
|
|
20675
|
+
signal: AbortSignal.timeout(PROCESS_TABLE_TIMEOUT_MILLISECONDS),
|
|
20676
|
+
timeout: PROCESS_TABLE_TIMEOUT_MILLISECONDS
|
|
20677
|
+
},
|
|
20678
|
+
(error61, stdout) => {
|
|
20679
|
+
resolveTable(error61 === null ? parseProcessTable(stdout) : []);
|
|
20680
|
+
}
|
|
20681
|
+
);
|
|
20682
|
+
});
|
|
20683
|
+
}
|
|
20684
|
+
function selectProcessTree(entries, rootProcessId) {
|
|
20685
|
+
const processIds = /* @__PURE__ */ new Set([rootProcessId]);
|
|
20686
|
+
let previousSize = 0;
|
|
20687
|
+
while (previousSize !== processIds.size) {
|
|
20688
|
+
previousSize = processIds.size;
|
|
20689
|
+
for (const entry of entries) {
|
|
20690
|
+
if (processIds.has(entry.parentProcessId)) {
|
|
20691
|
+
processIds.add(entry.processId);
|
|
20692
|
+
}
|
|
20693
|
+
}
|
|
20694
|
+
}
|
|
20695
|
+
return entries.filter((entry) => processIds.has(entry.processId)).map((entry) => ({
|
|
20696
|
+
processGroupId: entry.processGroupId,
|
|
20697
|
+
processId: entry.processId
|
|
20698
|
+
}));
|
|
20699
|
+
}
|
|
20700
|
+
function mergeProcessTrees(captured, current) {
|
|
20701
|
+
const processes = /* @__PURE__ */ new Map();
|
|
20702
|
+
for (const identity2 of captured) {
|
|
20703
|
+
processes.set(identity2.processId, identity2);
|
|
20704
|
+
}
|
|
20705
|
+
for (const identity2 of current) {
|
|
20706
|
+
processes.set(identity2.processId, identity2);
|
|
20707
|
+
}
|
|
20708
|
+
return [...processes.values()];
|
|
20709
|
+
}
|
|
20710
|
+
async function captureProcessTree(child) {
|
|
20711
|
+
if (process.platform === "win32" || child.pid === void 0) {
|
|
20712
|
+
return [];
|
|
20713
|
+
}
|
|
20714
|
+
return selectProcessTree(await readProcessTable(), child.pid);
|
|
20715
|
+
}
|
|
20716
|
+
function signalDetachedProcessGroups(processes, rootProcessId, signal) {
|
|
20717
|
+
const processIds = new Set(processes.map((identity2) => identity2.processId));
|
|
20718
|
+
const signalledGroups = /* @__PURE__ */ new Set();
|
|
20719
|
+
for (const identity2 of processes) {
|
|
20720
|
+
if (identity2.processGroupId === rootProcessId || !processIds.has(identity2.processGroupId) || signalledGroups.has(identity2.processGroupId)) {
|
|
20721
|
+
continue;
|
|
20722
|
+
}
|
|
20723
|
+
try {
|
|
20724
|
+
process.kill(-identity2.processGroupId, signal);
|
|
20725
|
+
signalledGroups.add(identity2.processGroupId);
|
|
20726
|
+
} catch {
|
|
20727
|
+
}
|
|
20728
|
+
}
|
|
20729
|
+
for (const identity2 of processes) {
|
|
20730
|
+
if (identity2.processId === rootProcessId || identity2.processGroupId === rootProcessId || signalledGroups.has(identity2.processGroupId)) {
|
|
20731
|
+
continue;
|
|
20732
|
+
}
|
|
20733
|
+
try {
|
|
20734
|
+
process.kill(identity2.processId, signal);
|
|
20735
|
+
} catch {
|
|
20736
|
+
}
|
|
20737
|
+
}
|
|
20738
|
+
}
|
|
20739
|
+
function processExists(processId) {
|
|
20740
|
+
try {
|
|
20741
|
+
process.kill(processId, 0);
|
|
20742
|
+
return true;
|
|
20743
|
+
} catch {
|
|
20744
|
+
return false;
|
|
20745
|
+
}
|
|
20746
|
+
}
|
|
20747
|
+
async function waitForCapturedProcessesExit(processes, rootProcessId) {
|
|
20748
|
+
const processIds = processes.map((identity2) => identity2.processId).filter((processId) => processId !== rootProcessId);
|
|
20749
|
+
for (let attempt = 0; attempt < PROCESS_EXIT_CHECK_ATTEMPTS; attempt += 1) {
|
|
20750
|
+
if (processIds.every((processId) => !processExists(processId))) {
|
|
20751
|
+
return true;
|
|
20752
|
+
}
|
|
20753
|
+
await readProcessTable();
|
|
20754
|
+
}
|
|
20755
|
+
return processIds.every((processId) => !processExists(processId));
|
|
20756
|
+
}
|
|
20757
|
+
function terminateProcess(child) {
|
|
20758
|
+
if (child.exitCode !== null || child.signalCode !== null || child.pid === void 0) {
|
|
20759
|
+
return;
|
|
20760
|
+
}
|
|
20761
|
+
if (process.platform !== "win32") {
|
|
20762
|
+
try {
|
|
20763
|
+
process.kill(-child.pid, "SIGTERM");
|
|
20764
|
+
return;
|
|
20765
|
+
} catch {
|
|
20766
|
+
}
|
|
20767
|
+
}
|
|
20768
|
+
child.kill("SIGTERM");
|
|
20769
|
+
}
|
|
20770
|
+
function forceTerminateProcess(child) {
|
|
20771
|
+
if (child.exitCode !== null || child.signalCode !== null || child.pid === void 0) {
|
|
20772
|
+
return;
|
|
20773
|
+
}
|
|
20774
|
+
if (process.platform !== "win32") {
|
|
20775
|
+
try {
|
|
20776
|
+
process.kill(-child.pid, "SIGKILL");
|
|
20777
|
+
return;
|
|
20778
|
+
} catch {
|
|
20779
|
+
}
|
|
20780
|
+
}
|
|
20781
|
+
child.kill("SIGKILL");
|
|
20782
|
+
}
|
|
20783
|
+
async function stopProcessTree(child, capturedProcesses = []) {
|
|
20784
|
+
const childProcessId = child.pid;
|
|
20785
|
+
if (childProcessId === void 0) {
|
|
20786
|
+
return;
|
|
20787
|
+
}
|
|
20788
|
+
const childExited = child.exitCode !== null || child.signalCode !== null;
|
|
20789
|
+
if (childExited && capturedProcesses.length === 0) {
|
|
20790
|
+
return;
|
|
20791
|
+
}
|
|
20792
|
+
const processes = mergeProcessTrees(
|
|
20793
|
+
capturedProcesses,
|
|
20794
|
+
childExited ? [] : await captureProcessTree(child)
|
|
20795
|
+
);
|
|
20796
|
+
signalDetachedProcessGroups(processes, childProcessId, GRACEFUL_STOP_SIGNAL);
|
|
20797
|
+
terminateProcess(child);
|
|
20798
|
+
const [exitedAfterTermination, descendantsExitedAfterTermination] = await Promise.all([
|
|
20799
|
+
waitForProcessExit(child, PROCESS_GRACEFUL_STOP_TIMEOUT_MILLISECONDS),
|
|
20800
|
+
waitForCapturedProcessesExit(processes, childProcessId)
|
|
20801
|
+
]);
|
|
20802
|
+
if (exitedAfterTermination && descendantsExitedAfterTermination) {
|
|
20803
|
+
return;
|
|
20804
|
+
}
|
|
20805
|
+
signalDetachedProcessGroups(processes, childProcessId, FORCED_STOP_SIGNAL);
|
|
20806
|
+
forceTerminateProcess(child);
|
|
20807
|
+
const [exitedAfterForce, descendantsExitedAfterForce] = await Promise.all([
|
|
20808
|
+
waitForProcessExit(child, PROCESS_FORCED_STOP_TIMEOUT_MILLISECONDS),
|
|
20809
|
+
waitForCapturedProcessesExit(processes, childProcessId)
|
|
20810
|
+
]);
|
|
20811
|
+
if (!exitedAfterForce || !descendantsExitedAfterForce) {
|
|
20812
|
+
throw new ProcessExecutionError(
|
|
20813
|
+
"process_termination_timeout",
|
|
20814
|
+
"The executable process could not be stopped"
|
|
20815
|
+
);
|
|
20816
|
+
}
|
|
20817
|
+
}
|
|
20818
|
+
function waitForProcessExit(child, timeoutMilliseconds) {
|
|
20819
|
+
if (child.exitCode !== null || child.signalCode !== null) {
|
|
20820
|
+
return Promise.resolve(true);
|
|
20821
|
+
}
|
|
20822
|
+
return new Promise((resolveExit) => {
|
|
20823
|
+
let settled = false;
|
|
20824
|
+
const finish = (exited) => {
|
|
20825
|
+
if (settled) {
|
|
20826
|
+
return;
|
|
20827
|
+
}
|
|
20828
|
+
settled = true;
|
|
20829
|
+
clearTimeout(timeout);
|
|
20830
|
+
child.removeListener("exit", handleExit);
|
|
20831
|
+
resolveExit(exited);
|
|
20832
|
+
};
|
|
20833
|
+
const handleExit = () => finish(true);
|
|
20834
|
+
const timeout = setTimeout(() => finish(false), timeoutMilliseconds);
|
|
20835
|
+
child.once("exit", handleExit);
|
|
20836
|
+
if (child.exitCode !== null || child.signalCode !== null) {
|
|
20837
|
+
finish(true);
|
|
20838
|
+
}
|
|
20839
|
+
});
|
|
20840
|
+
}
|
|
20841
|
+
async function runBoundedProcess(options) {
|
|
20842
|
+
options.signal.throwIfAborted();
|
|
20843
|
+
const outputLimitBytes = options.outputLimitBytes ?? DEFAULT_OUTPUT_LIMIT_BYTES;
|
|
20844
|
+
const child = spawn(options.command, [...options.arguments], {
|
|
20845
|
+
cwd: options.cwd,
|
|
20846
|
+
detached: process.platform !== "win32",
|
|
20847
|
+
env: { ...options.environment },
|
|
20848
|
+
shell: false,
|
|
20849
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
20850
|
+
});
|
|
20851
|
+
const stdout = [];
|
|
20852
|
+
const stderr = [];
|
|
20853
|
+
let stdoutBytes = 0;
|
|
20854
|
+
let stderrBytes = 0;
|
|
20855
|
+
let interruptionFailure = null;
|
|
20856
|
+
let interruptionCleanupFailure = null;
|
|
20857
|
+
let stopping = false;
|
|
20858
|
+
const interrupted = Promise.withResolvers();
|
|
20859
|
+
const interrupt = (failure) => {
|
|
20860
|
+
if (stopping) {
|
|
20861
|
+
return;
|
|
20862
|
+
}
|
|
20863
|
+
stopping = true;
|
|
20864
|
+
interruptionFailure = failure;
|
|
20865
|
+
const stop = async () => {
|
|
20866
|
+
try {
|
|
20867
|
+
await stopProcessTree(child);
|
|
20868
|
+
} catch (error61) {
|
|
20869
|
+
interruptionCleanupFailure = error61 instanceof ProcessExecutionError ? error61 : new ProcessExecutionError(
|
|
20870
|
+
"process_termination_failed",
|
|
20871
|
+
"The executable process could not be stopped",
|
|
20872
|
+
{ cause: error61 }
|
|
20873
|
+
);
|
|
20874
|
+
} finally {
|
|
20875
|
+
interrupted.resolve();
|
|
20876
|
+
}
|
|
20877
|
+
};
|
|
20878
|
+
void stop();
|
|
20879
|
+
};
|
|
20880
|
+
const collectStdout = (chunk) => {
|
|
20881
|
+
if (interruptionFailure !== null) {
|
|
20882
|
+
return;
|
|
20883
|
+
}
|
|
20884
|
+
try {
|
|
20885
|
+
stdoutBytes = appendBounded(stdout, chunk, stdoutBytes, outputLimitBytes);
|
|
20886
|
+
} catch (error61) {
|
|
20887
|
+
const failure = error61 instanceof ProcessExecutionError ? error61 : new ProcessExecutionError(
|
|
20888
|
+
"process_output_limit",
|
|
20889
|
+
"The executable produced too much output",
|
|
20890
|
+
{ cause: error61 }
|
|
20891
|
+
);
|
|
20892
|
+
interrupt(failure);
|
|
20893
|
+
}
|
|
20894
|
+
};
|
|
20895
|
+
const collectStderr = (chunk) => {
|
|
20896
|
+
if (interruptionFailure !== null) {
|
|
20897
|
+
return;
|
|
20898
|
+
}
|
|
20899
|
+
try {
|
|
20900
|
+
stderrBytes = appendBounded(stderr, chunk, stderrBytes, outputLimitBytes);
|
|
20901
|
+
} catch (error61) {
|
|
20902
|
+
const failure = error61 instanceof ProcessExecutionError ? error61 : new ProcessExecutionError(
|
|
20903
|
+
"process_output_limit",
|
|
20904
|
+
"The executable produced too much output",
|
|
20905
|
+
{ cause: error61 }
|
|
20906
|
+
);
|
|
20907
|
+
interrupt(failure);
|
|
20908
|
+
}
|
|
20909
|
+
};
|
|
20910
|
+
child.stdout?.on("data", collectStdout);
|
|
20911
|
+
child.stderr?.on("data", collectStderr);
|
|
20912
|
+
const timeout = setTimeout(() => {
|
|
20913
|
+
interrupt(
|
|
20914
|
+
new ProcessExecutionError(
|
|
20915
|
+
"process_timeout",
|
|
20916
|
+
"The executable probe timed out"
|
|
20917
|
+
)
|
|
20918
|
+
);
|
|
20919
|
+
}, options.timeoutMilliseconds);
|
|
20920
|
+
const abort = () => interrupt(
|
|
20921
|
+
new ProcessExecutionError(
|
|
20922
|
+
"process_cancelled",
|
|
20923
|
+
"The executable probe was cancelled",
|
|
20924
|
+
{ cause: options.signal.reason }
|
|
20925
|
+
)
|
|
20926
|
+
);
|
|
20927
|
+
options.signal.addEventListener("abort", abort, { once: true });
|
|
20928
|
+
if (options.signal.aborted) {
|
|
20929
|
+
abort();
|
|
21090
20930
|
}
|
|
21091
|
-
|
|
21092
|
-
|
|
21093
|
-
|
|
21094
|
-
|
|
20931
|
+
try {
|
|
20932
|
+
const exit = new Promise((resolveExit, rejectExit) => {
|
|
20933
|
+
child.once("error", rejectExit);
|
|
20934
|
+
child.once("exit", (code) => resolveExit(code ?? 1));
|
|
21095
20935
|
});
|
|
20936
|
+
const exitCode = await Promise.race([
|
|
20937
|
+
exit,
|
|
20938
|
+
interrupted.promise.then(() => -1)
|
|
20939
|
+
]);
|
|
20940
|
+
if (interruptionCleanupFailure !== null) {
|
|
20941
|
+
throw interruptionCleanupFailure;
|
|
20942
|
+
}
|
|
20943
|
+
if (interruptionFailure !== null) {
|
|
20944
|
+
throw interruptionFailure;
|
|
20945
|
+
}
|
|
20946
|
+
if (exitCode !== 0) {
|
|
20947
|
+
throw new ProcessExecutionError(
|
|
20948
|
+
"process_exit_failed",
|
|
20949
|
+
"The executable probe failed"
|
|
20950
|
+
);
|
|
20951
|
+
}
|
|
20952
|
+
return new ProcessResult(
|
|
20953
|
+
Buffer.concat(stdout).toString("utf8"),
|
|
20954
|
+
Buffer.concat(stderr).toString("utf8")
|
|
20955
|
+
);
|
|
20956
|
+
} catch (error61) {
|
|
20957
|
+
if (error61 instanceof ProcessExecutionError) {
|
|
20958
|
+
throw error61;
|
|
20959
|
+
}
|
|
20960
|
+
throw new ProcessExecutionError(
|
|
20961
|
+
"process_spawn_failed",
|
|
20962
|
+
"The executable could not be started",
|
|
20963
|
+
{ cause: error61 }
|
|
20964
|
+
);
|
|
20965
|
+
} finally {
|
|
20966
|
+
clearTimeout(timeout);
|
|
20967
|
+
options.signal.removeEventListener("abort", abort);
|
|
20968
|
+
child.stdout?.removeListener("data", collectStdout);
|
|
20969
|
+
child.stderr?.removeListener("data", collectStderr);
|
|
20970
|
+
if (stopping) {
|
|
20971
|
+
await interrupted.promise;
|
|
20972
|
+
} else {
|
|
20973
|
+
await stopProcessTree(child);
|
|
20974
|
+
}
|
|
20975
|
+
}
|
|
20976
|
+
}
|
|
20977
|
+
|
|
20978
|
+
// src/agent-catalog/local-agent.ts
|
|
20979
|
+
function readTrustedIdentity(path2) {
|
|
20980
|
+
const resolvedPath = realpathSync(path2);
|
|
20981
|
+
const metadata = statSync(resolvedPath);
|
|
20982
|
+
return new ExecutableIdentity(
|
|
20983
|
+
resolvedPath,
|
|
20984
|
+
resolvedPath,
|
|
20985
|
+
metadata.dev,
|
|
20986
|
+
metadata.ino,
|
|
20987
|
+
metadata.size,
|
|
20988
|
+
metadata.ctimeMs
|
|
20989
|
+
);
|
|
20990
|
+
}
|
|
20991
|
+
var LocalAgentDefinition = class {
|
|
20992
|
+
adapterIdentity;
|
|
20993
|
+
adapterPath;
|
|
20994
|
+
adapterVersion;
|
|
20995
|
+
agentIdentity;
|
|
20996
|
+
agentVersion;
|
|
20997
|
+
arguments;
|
|
20998
|
+
command;
|
|
20999
|
+
environment;
|
|
21000
|
+
id;
|
|
21001
|
+
label;
|
|
21002
|
+
promptTimeoutMilliseconds;
|
|
21003
|
+
constructor(id, label, command, arguments_, environment = {}, adapterVersion = "", agentVersion = "", adapterIdentity = readTrustedIdentity(command), agentIdentity = adapterIdentity, promptTimeoutMilliseconds = 30 * 60 * 1e3) {
|
|
21004
|
+
if (!Number.isSafeInteger(promptTimeoutMilliseconds) || promptTimeoutMilliseconds < 1) {
|
|
21005
|
+
throw new Error("The local Agent prompt deadline is invalid");
|
|
21006
|
+
}
|
|
21007
|
+
this.adapterIdentity = adapterIdentity;
|
|
21008
|
+
this.adapterPath = adapterIdentity.realPath;
|
|
21009
|
+
this.adapterVersion = adapterVersion;
|
|
21010
|
+
this.agentIdentity = agentIdentity;
|
|
21011
|
+
this.agentVersion = agentVersion;
|
|
21012
|
+
this.id = id;
|
|
21013
|
+
this.label = label;
|
|
21014
|
+
this.promptTimeoutMilliseconds = promptTimeoutMilliseconds;
|
|
21015
|
+
this.command = adapterIdentity.realPath;
|
|
21016
|
+
this.arguments = Object.freeze([...arguments_]);
|
|
21017
|
+
this.environment = Object.freeze({ ...environment });
|
|
21018
|
+
}
|
|
21019
|
+
};
|
|
21020
|
+
var InstallableAgentDefinition = class {
|
|
21021
|
+
id;
|
|
21022
|
+
label;
|
|
21023
|
+
constructor(id, label) {
|
|
21024
|
+
this.id = id;
|
|
21025
|
+
this.label = label;
|
|
21026
|
+
}
|
|
21027
|
+
};
|
|
21028
|
+
var LocalAgentCatalogSnapshot = class {
|
|
21029
|
+
agents;
|
|
21030
|
+
installableAgents;
|
|
21031
|
+
constructor(agents, installableAgents) {
|
|
21032
|
+
this.agents = Object.freeze([...agents]);
|
|
21033
|
+
this.installableAgents = Object.freeze([...installableAgents]);
|
|
21034
|
+
}
|
|
21035
|
+
};
|
|
21036
|
+
var LocalAgentCatalogError = class extends Error {
|
|
21037
|
+
code = "agent_not_ready";
|
|
21038
|
+
constructor() {
|
|
21039
|
+
super("The requested local Agent is not ready");
|
|
21040
|
+
this.name = "LocalAgentCatalogError";
|
|
21041
|
+
}
|
|
21042
|
+
};
|
|
21043
|
+
var LocalAgentCatalog = class {
|
|
21044
|
+
#snapshot;
|
|
21045
|
+
constructor(agents, installableAgents) {
|
|
21046
|
+
this.#snapshot = this.validate(agents, installableAgents);
|
|
21047
|
+
}
|
|
21048
|
+
find = (agentId) => {
|
|
21049
|
+
for (const agent of this.#snapshot.agents) {
|
|
21050
|
+
if (agent.id === agentId) {
|
|
21051
|
+
return agent;
|
|
21052
|
+
}
|
|
21053
|
+
}
|
|
21054
|
+
throw new LocalAgentCatalogError();
|
|
21055
|
+
};
|
|
21056
|
+
read = () => this.#snapshot;
|
|
21057
|
+
transition = (agents, installableAgents) => {
|
|
21058
|
+
const next = this.validate(agents, installableAgents);
|
|
21059
|
+
this.#snapshot = next;
|
|
21060
|
+
return next;
|
|
21061
|
+
};
|
|
21062
|
+
validate = (agents, installableAgents) => {
|
|
21063
|
+
const identifiers = /* @__PURE__ */ new Set();
|
|
21064
|
+
for (const agent of agents) {
|
|
21065
|
+
if (identifiers.has(agent.id)) {
|
|
21066
|
+
throw new Error("The local Agent catalog contains duplicate entries");
|
|
21067
|
+
}
|
|
21068
|
+
identifiers.add(agent.id);
|
|
21069
|
+
}
|
|
21070
|
+
for (const agent of installableAgents) {
|
|
21071
|
+
if (identifiers.has(agent.id)) {
|
|
21072
|
+
throw new Error("A local Agent cannot be ready and installable");
|
|
21073
|
+
}
|
|
21074
|
+
identifiers.add(agent.id);
|
|
21075
|
+
}
|
|
21076
|
+
return new LocalAgentCatalogSnapshot(agents, installableAgents);
|
|
21077
|
+
};
|
|
21078
|
+
};
|
|
21079
|
+
|
|
21080
|
+
// src/storage/state-directory.ts
|
|
21081
|
+
import { homedir } from "node:os";
|
|
21082
|
+
import { join as join2, resolve as resolve2 } from "node:path";
|
|
21083
|
+
function readStateDirectory(environment = process.env) {
|
|
21084
|
+
const configured = environment["MOBIUS_STATE_DIRECTORY"]?.trim();
|
|
21085
|
+
if (configured !== void 0 && configured.length > 0) {
|
|
21086
|
+
return resolve2(configured);
|
|
21096
21087
|
}
|
|
21097
|
-
return
|
|
21088
|
+
return join2(homedir(), ".mobius");
|
|
21098
21089
|
}
|
|
21099
|
-
|
|
21100
|
-
|
|
21101
|
-
|
|
21102
|
-
|
|
21103
|
-
|
|
21104
|
-
|
|
21090
|
+
|
|
21091
|
+
// src/config.ts
|
|
21092
|
+
function loadDefaultWorkspace() {
|
|
21093
|
+
const { MOBIUS_DEFAULT_WORKSPACE: configuredWorkspace } = process.env;
|
|
21094
|
+
return configuredWorkspace ?? join3(readStateDirectory(), "workspace");
|
|
21095
|
+
}
|
|
21096
|
+
function createDaemonConfig(connection, agents = [], installableAgents = []) {
|
|
21097
|
+
return {
|
|
21098
|
+
agents,
|
|
21099
|
+
defaultWorkspace: connection.defaultWorkspace,
|
|
21100
|
+
auditDatabasePath: connection.auditDatabasePath,
|
|
21101
|
+
bindingId: "workspace",
|
|
21102
|
+
catalog: new LocalAgentCatalog(agents, installableAgents),
|
|
21103
|
+
channelId: connection.channelId,
|
|
21104
|
+
installableAgents,
|
|
21105
|
+
relayUrl: connection.relayUrl
|
|
21106
|
+
};
|
|
21107
|
+
}
|
|
21108
|
+
function loadDaemonConfig() {
|
|
21109
|
+
const relayUrl = new URL(
|
|
21110
|
+
// biome-ignore lint/complexity/useLiteralKeys: Environment variables use an index signature.
|
|
21111
|
+
process.env["MOBIUS_RELAY_URL"] ?? `ws://127.0.0.1:8787${mobiusApiPath("/channels/local/daemon")}`
|
|
21112
|
+
);
|
|
21113
|
+
relayUrl.searchParams.set(
|
|
21114
|
+
"token",
|
|
21115
|
+
// biome-ignore lint/complexity/useLiteralKeys: Environment variables use an index signature.
|
|
21116
|
+
process.env["MOBIUS_RELAY_TOKEN"] ?? "local-development-token"
|
|
21117
|
+
);
|
|
21118
|
+
if (relayUrl.protocol !== "ws:" && relayUrl.protocol !== "wss:") {
|
|
21119
|
+
throw new Error("MOBIUS_RELAY_URL must use ws or wss");
|
|
21105
21120
|
}
|
|
21106
|
-
return
|
|
21107
|
-
|
|
21108
|
-
|
|
21109
|
-
|
|
21121
|
+
return createDaemonConfig(
|
|
21122
|
+
{
|
|
21123
|
+
defaultWorkspace: loadDefaultWorkspace(),
|
|
21124
|
+
auditDatabasePath: (
|
|
21125
|
+
// biome-ignore lint/complexity/useLiteralKeys: Environment variables use an index signature.
|
|
21126
|
+
process.env["MOBIUS_AUDIT_DATABASE"] ?? fileURLToPath(
|
|
21127
|
+
new URL("../../../.mobius/daemon.sqlite", import.meta.url)
|
|
21128
|
+
)
|
|
21129
|
+
),
|
|
21130
|
+
// biome-ignore lint/complexity/useLiteralKeys: Environment variables use an index signature.
|
|
21131
|
+
channelId: process.env["MOBIUS_CHANNEL_ID"] ?? "local",
|
|
21132
|
+
relayUrl
|
|
21133
|
+
},
|
|
21134
|
+
[],
|
|
21135
|
+
[]
|
|
21136
|
+
);
|
|
21137
|
+
}
|
|
21138
|
+
|
|
21139
|
+
// src/acp/session-manager.ts
|
|
21140
|
+
import { spawn as spawn2 } from "node:child_process";
|
|
21141
|
+
import {
|
|
21142
|
+
methods as methods2,
|
|
21143
|
+
ndJsonStream,
|
|
21144
|
+
PROTOCOL_VERSION,
|
|
21145
|
+
RequestError
|
|
21146
|
+
} from "@agentclientprotocol/sdk";
|
|
21110
21147
|
|
|
21111
21148
|
// src/acp/activity.ts
|
|
21112
21149
|
var TRUNCATION_MARKER = "\n\u2026 output truncated by Mobius";
|
|
@@ -24147,58 +24184,16 @@ var LocalAuthorizationError = class extends Error {
|
|
|
24147
24184
|
import { randomUUID } from "node:crypto";
|
|
24148
24185
|
import {
|
|
24149
24186
|
mkdir as mkdir3,
|
|
24150
|
-
open as
|
|
24151
|
-
realpath as
|
|
24187
|
+
open as open5,
|
|
24188
|
+
realpath as realpath6,
|
|
24152
24189
|
rename as rename3,
|
|
24153
24190
|
stat as stat5,
|
|
24154
24191
|
writeFile as writeFile2
|
|
24155
24192
|
} from "node:fs/promises";
|
|
24156
24193
|
import { hostname as hostname3 } from "node:os";
|
|
24157
|
-
import { basename, join as
|
|
24194
|
+
import { basename, join as join14, resolve as resolve3 } from "node:path";
|
|
24158
24195
|
import { fetch as fetch2 } from "undici";
|
|
24159
24196
|
|
|
24160
|
-
// src/agent-installation/installation-grants.ts
|
|
24161
|
-
import { open as open2 } from "node:fs/promises";
|
|
24162
|
-
import { join as join4 } from "node:path";
|
|
24163
|
-
var MAX_GRANT_FILE_LENGTH = 16 * 1024;
|
|
24164
|
-
var AGENT_ID_PATTERN = /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/;
|
|
24165
|
-
function isRecord4(value) {
|
|
24166
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
24167
|
-
}
|
|
24168
|
-
async function readGrantedAgents(stateDirectory) {
|
|
24169
|
-
const path2 = join4(stateDirectory, "installation-grants.json");
|
|
24170
|
-
let handle;
|
|
24171
|
-
try {
|
|
24172
|
-
handle = await open2(path2, "r");
|
|
24173
|
-
} catch (error61) {
|
|
24174
|
-
if (error61 instanceof Error && "code" in error61 && error61.code === "ENOENT") {
|
|
24175
|
-
return /* @__PURE__ */ new Set();
|
|
24176
|
-
}
|
|
24177
|
-
throw error61;
|
|
24178
|
-
}
|
|
24179
|
-
try {
|
|
24180
|
-
const metadata = await handle.stat();
|
|
24181
|
-
if (!metadata.isFile() || metadata.size > MAX_GRANT_FILE_LENGTH || typeof process.getuid === "function" && metadata.uid !== process.getuid() || process.platform !== "win32" && (metadata.mode & 63) !== 0) {
|
|
24182
|
-
throw new Error("The local installation grant file is not private");
|
|
24183
|
-
}
|
|
24184
|
-
const encoded = await handle.readFile({ encoding: "utf8" });
|
|
24185
|
-
const value = JSON.parse(encoded);
|
|
24186
|
-
if (!isRecord4(value) || Object.keys(value).length !== 1 || !Array.isArray(value["agents"])) {
|
|
24187
|
-
throw new Error("The local installation grant file is invalid");
|
|
24188
|
-
}
|
|
24189
|
-
const agents = /* @__PURE__ */ new Set();
|
|
24190
|
-
for (const candidate of value["agents"]) {
|
|
24191
|
-
if (typeof candidate !== "string" || !AGENT_ID_PATTERN.test(candidate) || agents.has(candidate)) {
|
|
24192
|
-
throw new Error("The local installation grant file is invalid");
|
|
24193
|
-
}
|
|
24194
|
-
agents.add(candidate);
|
|
24195
|
-
}
|
|
24196
|
-
return agents;
|
|
24197
|
-
} finally {
|
|
24198
|
-
await handle.close();
|
|
24199
|
-
}
|
|
24200
|
-
}
|
|
24201
|
-
|
|
24202
24197
|
// src/agent-catalog/agent-discovery.ts
|
|
24203
24198
|
var AgentDiscovery = class {
|
|
24204
24199
|
specification;
|
|
@@ -24263,7 +24258,7 @@ var LocalAgentInventory = class {
|
|
|
24263
24258
|
discoveries;
|
|
24264
24259
|
installable;
|
|
24265
24260
|
unavailable;
|
|
24266
|
-
constructor(discoveries,
|
|
24261
|
+
constructor(discoveries, platform = process.platform, architecture = process.arch) {
|
|
24267
24262
|
const available = [];
|
|
24268
24263
|
const unavailable = [];
|
|
24269
24264
|
for (const discovery of discoveries) {
|
|
@@ -24286,8 +24281,7 @@ var LocalAgentInventory = class {
|
|
|
24286
24281
|
).map(
|
|
24287
24282
|
(discovery) => new InstallableAgentDefinition(
|
|
24288
24283
|
discovery.specification.id,
|
|
24289
|
-
discovery.specification.label
|
|
24290
|
-
!grantedAgents.has(discovery.specification.id)
|
|
24284
|
+
discovery.specification.label
|
|
24291
24285
|
)
|
|
24292
24286
|
)
|
|
24293
24287
|
);
|
|
@@ -24300,13 +24294,13 @@ var LocalAgentInventory = class {
|
|
|
24300
24294
|
import {
|
|
24301
24295
|
mkdir,
|
|
24302
24296
|
mkdtemp,
|
|
24303
|
-
open as
|
|
24297
|
+
open as open2,
|
|
24304
24298
|
realpath as realpath2,
|
|
24305
24299
|
rename,
|
|
24306
24300
|
rm,
|
|
24307
24301
|
stat as stat2
|
|
24308
24302
|
} from "node:fs/promises";
|
|
24309
|
-
import { delimiter, dirname as dirname3, isAbsolute, join as
|
|
24303
|
+
import { delimiter, dirname as dirname3, isAbsolute, join as join4, relative, sep } from "node:path";
|
|
24310
24304
|
var INSTALL_TIMEOUT_MILLISECONDS = 5 * 60 * 1e3;
|
|
24311
24305
|
var PACKAGE_METADATA_LIMIT_BYTES = 64 * 1024;
|
|
24312
24306
|
var PACKAGE_LOCK_LIMIT_BYTES = 8 * 1024 * 1024;
|
|
@@ -24325,6 +24319,7 @@ var ManagedNpmPackageDefinition = class {
|
|
|
24325
24319
|
};
|
|
24326
24320
|
var SriManagedNpmPackageDefinition = class extends ManagedNpmPackageDefinition {
|
|
24327
24321
|
integrity;
|
|
24322
|
+
requiredDependencies = Object.freeze([]);
|
|
24328
24323
|
tarballUrl;
|
|
24329
24324
|
constructor(packageName, version2, executableName, integrity, tarballUrl) {
|
|
24330
24325
|
super(packageName, version2, executableName);
|
|
@@ -24332,6 +24327,18 @@ var SriManagedNpmPackageDefinition = class extends ManagedNpmPackageDefinition {
|
|
|
24332
24327
|
this.tarballUrl = tarballUrl;
|
|
24333
24328
|
}
|
|
24334
24329
|
};
|
|
24330
|
+
var SriManagedNpmDependencyDefinition = class {
|
|
24331
|
+
integrity;
|
|
24332
|
+
packageName;
|
|
24333
|
+
tarballUrl;
|
|
24334
|
+
version;
|
|
24335
|
+
constructor(packageName, version2, integrity, tarballUrl) {
|
|
24336
|
+
this.integrity = integrity;
|
|
24337
|
+
this.packageName = packageName;
|
|
24338
|
+
this.tarballUrl = tarballUrl;
|
|
24339
|
+
this.version = version2;
|
|
24340
|
+
}
|
|
24341
|
+
};
|
|
24335
24342
|
var ManagedNpmPackageError = class extends Error {
|
|
24336
24343
|
code;
|
|
24337
24344
|
constructor(code, message, options = {}) {
|
|
@@ -24340,11 +24347,11 @@ var ManagedNpmPackageError = class extends Error {
|
|
|
24340
24347
|
this.name = "ManagedNpmPackageError";
|
|
24341
24348
|
}
|
|
24342
24349
|
};
|
|
24343
|
-
function
|
|
24350
|
+
function isRecord4(value) {
|
|
24344
24351
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
24345
24352
|
}
|
|
24346
24353
|
function packagePath(root, packageName) {
|
|
24347
|
-
return
|
|
24354
|
+
return join4(root, "node_modules", ...packageName.split("/"));
|
|
24348
24355
|
}
|
|
24349
24356
|
function isContainedPath(root, candidate) {
|
|
24350
24357
|
const difference = relative(root, candidate);
|
|
@@ -24352,7 +24359,7 @@ function isContainedPath(root, candidate) {
|
|
|
24352
24359
|
}
|
|
24353
24360
|
async function readJsonRecord(path2, maximumBytes) {
|
|
24354
24361
|
try {
|
|
24355
|
-
const handle = await
|
|
24362
|
+
const handle = await open2(path2, "r");
|
|
24356
24363
|
try {
|
|
24357
24364
|
const metadata = await handle.stat();
|
|
24358
24365
|
if (!metadata.isFile() || metadata.size > maximumBytes) {
|
|
@@ -24364,7 +24371,7 @@ async function readJsonRecord(path2, maximumBytes) {
|
|
|
24364
24371
|
const value = JSON.parse(
|
|
24365
24372
|
await handle.readFile({ encoding: "utf8" })
|
|
24366
24373
|
);
|
|
24367
|
-
if (!
|
|
24374
|
+
if (!isRecord4(value)) {
|
|
24368
24375
|
throw new ManagedNpmPackageError(
|
|
24369
24376
|
"managed_package_verification_failed",
|
|
24370
24377
|
"The managed npm package metadata is invalid"
|
|
@@ -24390,7 +24397,7 @@ function readBinPath(packageMetadata, executableName) {
|
|
|
24390
24397
|
if (typeof bin === "string") {
|
|
24391
24398
|
return bin;
|
|
24392
24399
|
}
|
|
24393
|
-
if (
|
|
24400
|
+
if (isRecord4(bin) && typeof bin[executableName] === "string") {
|
|
24394
24401
|
return bin[executableName];
|
|
24395
24402
|
}
|
|
24396
24403
|
throw new ManagedNpmPackageError(
|
|
@@ -24398,7 +24405,7 @@ function readBinPath(packageMetadata, executableName) {
|
|
|
24398
24405
|
"The managed npm package executable declaration is invalid"
|
|
24399
24406
|
);
|
|
24400
24407
|
}
|
|
24401
|
-
function
|
|
24408
|
+
function verifyPackageLockEntry(lock, definition, verifyDependencyClosure) {
|
|
24402
24409
|
if (lock["lockfileVersion"] !== 3) {
|
|
24403
24410
|
throw new ManagedNpmPackageError(
|
|
24404
24411
|
"managed_package_verification_failed",
|
|
@@ -24406,7 +24413,7 @@ function verifyPackageLock(lock, definition) {
|
|
|
24406
24413
|
);
|
|
24407
24414
|
}
|
|
24408
24415
|
const packages = lock["packages"];
|
|
24409
|
-
if (!
|
|
24416
|
+
if (!isRecord4(packages)) {
|
|
24410
24417
|
throw new ManagedNpmPackageError(
|
|
24411
24418
|
"managed_package_verification_failed",
|
|
24412
24419
|
"The managed npm package lockfile is invalid"
|
|
@@ -24417,10 +24424,10 @@ function verifyPackageLock(lock, definition) {
|
|
|
24417
24424
|
let matches = 0;
|
|
24418
24425
|
for (const [key, candidate] of Object.entries(packages)) {
|
|
24419
24426
|
const normalizedKey = key.replaceAll("\\", "/");
|
|
24420
|
-
if (
|
|
24427
|
+
if (verifyDependencyClosure && normalizedKey.length > 0) {
|
|
24421
24428
|
let resolved;
|
|
24422
24429
|
try {
|
|
24423
|
-
if (!normalizedKey.split("/").includes("node_modules") || !
|
|
24430
|
+
if (!normalizedKey.split("/").includes("node_modules") || !isRecord4(candidate) || typeof candidate["version"] !== "string" || candidate["version"].length === 0 || typeof candidate["integrity"] !== "string" || !/^sha512-[A-Za-z0-9+/]{86}==$/.test(candidate["integrity"]) || typeof candidate["resolved"] !== "string") {
|
|
24424
24431
|
throw new Error("Invalid locked dependency");
|
|
24425
24432
|
}
|
|
24426
24433
|
resolved = new URL(candidate["resolved"]);
|
|
@@ -24443,13 +24450,35 @@ function verifyPackageLock(lock, definition) {
|
|
|
24443
24450
|
matches += 1;
|
|
24444
24451
|
}
|
|
24445
24452
|
}
|
|
24446
|
-
if (matches !== 1 || !
|
|
24453
|
+
if (matches !== 1 || !isRecord4(entry) || entry["integrity"] !== definition.integrity || entry["resolved"] !== definition.tarballUrl || entry["version"] !== definition.version) {
|
|
24447
24454
|
throw new ManagedNpmPackageError(
|
|
24448
24455
|
"managed_package_verification_failed",
|
|
24449
24456
|
"The managed npm package lockfile does not match the pinned artifact"
|
|
24450
24457
|
);
|
|
24451
24458
|
}
|
|
24452
24459
|
}
|
|
24460
|
+
async function verifyRequiredDependency(rootPath, lock, definition) {
|
|
24461
|
+
const dependencyRoot = await realpath2(
|
|
24462
|
+
packagePath(rootPath, definition.packageName)
|
|
24463
|
+
);
|
|
24464
|
+
if (!isContainedPath(rootPath, dependencyRoot)) {
|
|
24465
|
+
throw new ManagedNpmPackageError(
|
|
24466
|
+
"managed_package_verification_failed",
|
|
24467
|
+
"The required managed npm dependency escaped its private cache"
|
|
24468
|
+
);
|
|
24469
|
+
}
|
|
24470
|
+
const metadata = await readJsonRecord(
|
|
24471
|
+
join4(dependencyRoot, "package.json"),
|
|
24472
|
+
PACKAGE_METADATA_LIMIT_BYTES
|
|
24473
|
+
);
|
|
24474
|
+
if (metadata["name"] !== definition.packageName || metadata["version"] !== definition.version) {
|
|
24475
|
+
throw new ManagedNpmPackageError(
|
|
24476
|
+
"managed_package_verification_failed",
|
|
24477
|
+
"The required managed npm dependency identity is invalid"
|
|
24478
|
+
);
|
|
24479
|
+
}
|
|
24480
|
+
verifyPackageLockEntry(lock, definition, false);
|
|
24481
|
+
}
|
|
24453
24482
|
async function validateManagedNpmPackage(root, definition) {
|
|
24454
24483
|
try {
|
|
24455
24484
|
return await validateManagedNpmPackageContents(root, definition);
|
|
@@ -24476,7 +24505,7 @@ async function validateManagedNpmPackageContents(root, definition) {
|
|
|
24476
24505
|
);
|
|
24477
24506
|
}
|
|
24478
24507
|
const metadata = await readJsonRecord(
|
|
24479
|
-
|
|
24508
|
+
join4(packageRoot, "package.json"),
|
|
24480
24509
|
PACKAGE_METADATA_LIMIT_BYTES
|
|
24481
24510
|
);
|
|
24482
24511
|
if (metadata["name"] !== definition.packageName || metadata["version"] !== definition.version) {
|
|
@@ -24486,17 +24515,22 @@ async function validateManagedNpmPackageContents(root, definition) {
|
|
|
24486
24515
|
);
|
|
24487
24516
|
}
|
|
24488
24517
|
if (definition instanceof SriManagedNpmPackageDefinition) {
|
|
24489
|
-
|
|
24490
|
-
|
|
24491
|
-
|
|
24492
|
-
PACKAGE_LOCK_LIMIT_BYTES
|
|
24493
|
-
),
|
|
24494
|
-
definition
|
|
24518
|
+
const lock = await readJsonRecord(
|
|
24519
|
+
join4(rootPath, "package-lock.json"),
|
|
24520
|
+
PACKAGE_LOCK_LIMIT_BYTES
|
|
24495
24521
|
);
|
|
24522
|
+
verifyPackageLockEntry(
|
|
24523
|
+
lock,
|
|
24524
|
+
definition,
|
|
24525
|
+
definition.verifyDependencyClosure
|
|
24526
|
+
);
|
|
24527
|
+
for (const dependency of definition.requiredDependencies) {
|
|
24528
|
+
await verifyRequiredDependency(rootPath, lock, dependency);
|
|
24529
|
+
}
|
|
24496
24530
|
}
|
|
24497
24531
|
const declaredBin = readBinPath(metadata, definition.executableName);
|
|
24498
24532
|
const executable = await resolveExecutablePath(
|
|
24499
|
-
|
|
24533
|
+
join4(packageRoot, declaredBin)
|
|
24500
24534
|
);
|
|
24501
24535
|
if (executable === null || !isContainedPath(rootPath, executable.path)) {
|
|
24502
24536
|
throw new ManagedNpmPackageError(
|
|
@@ -24522,7 +24556,7 @@ var ManagedNpmPackageInstaller = class {
|
|
|
24522
24556
|
const parent = dirname3(root);
|
|
24523
24557
|
await mkdir(parent, { mode: 448, recursive: true });
|
|
24524
24558
|
const staging = await mkdtemp(
|
|
24525
|
-
|
|
24559
|
+
join4(parent, `.${definition.version}.staging-`)
|
|
24526
24560
|
);
|
|
24527
24561
|
try {
|
|
24528
24562
|
const npm = await findExecutableOnPath(
|
|
@@ -24552,9 +24586,9 @@ var ManagedNpmPackageInstaller = class {
|
|
|
24552
24586
|
`${definition.packageName}@${definition.version}`
|
|
24553
24587
|
);
|
|
24554
24588
|
const installEnvironment = {
|
|
24555
|
-
HOME:
|
|
24589
|
+
HOME: join4(staging, "home"),
|
|
24556
24590
|
NPM_CONFIG_AUDIT: "false",
|
|
24557
|
-
NPM_CONFIG_CACHE:
|
|
24591
|
+
NPM_CONFIG_CACHE: join4(staging, ".npm-cache"),
|
|
24558
24592
|
NPM_CONFIG_FUND: "false",
|
|
24559
24593
|
NPM_CONFIG_IGNORE_SCRIPTS: "true",
|
|
24560
24594
|
NPM_CONFIG_PACKAGE_LOCK: "true",
|
|
@@ -24576,8 +24610,8 @@ var ManagedNpmPackageInstaller = class {
|
|
|
24576
24610
|
timeoutMilliseconds: INSTALL_TIMEOUT_MILLISECONDS
|
|
24577
24611
|
});
|
|
24578
24612
|
await Promise.all([
|
|
24579
|
-
rm(
|
|
24580
|
-
rm(
|
|
24613
|
+
rm(join4(staging, ".npm-cache"), { force: true, recursive: true }),
|
|
24614
|
+
rm(join4(staging, "home"), { force: true, recursive: true })
|
|
24581
24615
|
]);
|
|
24582
24616
|
await validateManagedNpmPackage(staging, definition);
|
|
24583
24617
|
try {
|
|
@@ -24613,7 +24647,7 @@ var ManagedNpmPackageInstaller = class {
|
|
|
24613
24647
|
};
|
|
24614
24648
|
|
|
24615
24649
|
// src/agent-catalog/agent-specification.ts
|
|
24616
|
-
import { join as
|
|
24650
|
+
import { join as join5 } from "node:path";
|
|
24617
24651
|
var VERSION_PROBE_TIMEOUT_MILLISECONDS = 3e3;
|
|
24618
24652
|
var ACP_PROBE_TIMEOUT_MILLISECONDS = 5e3;
|
|
24619
24653
|
var DEFAULT_PROMPT_TIMEOUT_MILLISECONDS = 30 * 60 * 1e3;
|
|
@@ -24627,7 +24661,7 @@ var LocalAgentSpecification = class {
|
|
|
24627
24661
|
resolveManagedAgent = async (stateDirectory, platform, signal) => {
|
|
24628
24662
|
signal.throwIfAborted();
|
|
24629
24663
|
const executable = await resolveExecutablePath(
|
|
24630
|
-
|
|
24664
|
+
join5(stateDirectory, ...this.managedAgentExecutablePath),
|
|
24631
24665
|
platform
|
|
24632
24666
|
);
|
|
24633
24667
|
signal.throwIfAborted();
|
|
@@ -24732,9 +24766,84 @@ var CodexAgentSpecification = class extends BridgedAcpAgentDefinition {
|
|
|
24732
24766
|
managedAgentExecutablePath = ["agents", "codex", "bin", "codex"];
|
|
24733
24767
|
};
|
|
24734
24768
|
|
|
24769
|
+
// src/agent-catalog/agent-probe-error.ts
|
|
24770
|
+
var AgentProbeError = class extends Error {
|
|
24771
|
+
code;
|
|
24772
|
+
constructor(code, message, options = {}) {
|
|
24773
|
+
super(message, options);
|
|
24774
|
+
this.code = code;
|
|
24775
|
+
this.name = "AgentProbeError";
|
|
24776
|
+
}
|
|
24777
|
+
};
|
|
24778
|
+
|
|
24779
|
+
// src/agent-catalog/agents/verify-session-creation.ts
|
|
24780
|
+
import {
|
|
24781
|
+
methods as methods3
|
|
24782
|
+
} from "@agentclientprotocol/sdk";
|
|
24783
|
+
async function verifySessionCreation(connection, capabilities, defaultWorkspace, signal, label) {
|
|
24784
|
+
const session = await connection.agent.request(
|
|
24785
|
+
methods3.agent.session.new,
|
|
24786
|
+
{
|
|
24787
|
+
additionalDirectories: [],
|
|
24788
|
+
cwd: defaultWorkspace,
|
|
24789
|
+
mcpServers: []
|
|
24790
|
+
},
|
|
24791
|
+
{ cancellationSignal: signal }
|
|
24792
|
+
);
|
|
24793
|
+
if (session.sessionId.length === 0) {
|
|
24794
|
+
throw new AgentProbeError(
|
|
24795
|
+
"acp_incompatible",
|
|
24796
|
+
`${label} returned an invalid ACP session`
|
|
24797
|
+
);
|
|
24798
|
+
}
|
|
24799
|
+
if (capabilities.sessionCapabilities?.close != null) {
|
|
24800
|
+
await connection.agent.request(
|
|
24801
|
+
methods3.agent.session.close,
|
|
24802
|
+
{ sessionId: session.sessionId },
|
|
24803
|
+
{ cancellationSignal: signal }
|
|
24804
|
+
);
|
|
24805
|
+
}
|
|
24806
|
+
}
|
|
24807
|
+
|
|
24808
|
+
// src/agent-catalog/agents/cursor-cli-agent.ts
|
|
24809
|
+
var CURSOR_CLI_TESTED_VERSION = "2026.09.02-c22c1a3";
|
|
24810
|
+
var CursorCliAgentSpecification = class extends DirectAcpAgentDefinition {
|
|
24811
|
+
adapterVersion = CURSOR_CLI_TESTED_VERSION;
|
|
24812
|
+
authenticationCommand = () => "cursor-agent login";
|
|
24813
|
+
agentExecutable = "cursor-agent";
|
|
24814
|
+
id = "cursor";
|
|
24815
|
+
label = "Cursor CLI";
|
|
24816
|
+
constructor() {
|
|
24817
|
+
super(
|
|
24818
|
+
"MOBIUS_CURSOR_PATH",
|
|
24819
|
+
["--disable-auto-update", "acp"],
|
|
24820
|
+
["agents", "cursor", CURSOR_CLI_TESTED_VERSION, "bin", "cursor-agent"]
|
|
24821
|
+
);
|
|
24822
|
+
}
|
|
24823
|
+
supportsInstallation = (_platform, _architecture) => false;
|
|
24824
|
+
verifyAcp = async (connection, initialized, defaultWorkspace, signal) => {
|
|
24825
|
+
const capabilities = initialized.agentCapabilities ?? {};
|
|
24826
|
+
if (capabilities.loadSession !== true || capabilities.sessionCapabilities?.list == null || !(initialized.authMethods ?? []).some(
|
|
24827
|
+
(method) => method.id === "cursor_login"
|
|
24828
|
+
)) {
|
|
24829
|
+
throw new AgentProbeError(
|
|
24830
|
+
"acp_incompatible",
|
|
24831
|
+
"Cursor CLI reported an unsupported ACP capability set"
|
|
24832
|
+
);
|
|
24833
|
+
}
|
|
24834
|
+
await verifySessionCreation(
|
|
24835
|
+
connection,
|
|
24836
|
+
capabilities,
|
|
24837
|
+
defaultWorkspace,
|
|
24838
|
+
signal,
|
|
24839
|
+
this.label
|
|
24840
|
+
);
|
|
24841
|
+
};
|
|
24842
|
+
};
|
|
24843
|
+
|
|
24735
24844
|
// src/agent-catalog/agents/deepseek-harness-agent.ts
|
|
24736
24845
|
import { realpath as realpath3, stat as stat3 } from "node:fs/promises";
|
|
24737
|
-
import { isAbsolute as isAbsolute2, join as
|
|
24846
|
+
import { isAbsolute as isAbsolute2, join as join6, normalize } from "node:path";
|
|
24738
24847
|
|
|
24739
24848
|
// src/agent-installation/deepseek-managed-package.ts
|
|
24740
24849
|
var DeepSeekHarnessManagedPackage = class extends SriManagedNpmPackageDefinition {
|
|
@@ -24752,16 +24861,6 @@ var DEEPSEEK_HARNESS_PACKAGE = new DeepSeekHarnessManagedPackage(
|
|
|
24752
24861
|
"https://registry.npmjs.org/@deepseek-ai/dsh/-/dsh-0.1.2-rc.1.tgz"
|
|
24753
24862
|
);
|
|
24754
24863
|
|
|
24755
|
-
// src/agent-catalog/agent-probe-error.ts
|
|
24756
|
-
var AgentProbeError = class extends Error {
|
|
24757
|
-
code;
|
|
24758
|
-
constructor(code, message, options = {}) {
|
|
24759
|
-
super(message, options);
|
|
24760
|
-
this.code = code;
|
|
24761
|
-
this.name = "AgentProbeError";
|
|
24762
|
-
}
|
|
24763
|
-
};
|
|
24764
|
-
|
|
24765
24864
|
// src/agent-catalog/agents/deepseek-harness-agent.ts
|
|
24766
24865
|
async function validateAgentHome(path2) {
|
|
24767
24866
|
if (!isAbsolute2(path2) || normalize(path2) !== path2) {
|
|
@@ -24819,7 +24918,7 @@ var DeepSeekHarnessAgentSpecification = class extends DirectAcpAgentDefinition {
|
|
|
24819
24918
|
context.signal
|
|
24820
24919
|
);
|
|
24821
24920
|
if (managed.path === agent.path) {
|
|
24822
|
-
selectedHome =
|
|
24921
|
+
selectedHome = join6(
|
|
24823
24922
|
readStateDirectory(context.environment),
|
|
24824
24923
|
"agents",
|
|
24825
24924
|
this.id,
|
|
@@ -24840,7 +24939,7 @@ var DeepSeekHarnessAgentSpecification = class extends DirectAcpAgentDefinition {
|
|
|
24840
24939
|
resolveManagedAgent = async (stateDirectory, _platform, signal) => {
|
|
24841
24940
|
signal.throwIfAborted();
|
|
24842
24941
|
const executable = await validateManagedNpmPackage(
|
|
24843
|
-
|
|
24942
|
+
join6(stateDirectory, "agents", this.id, DEEPSEEK_HARNESS_PACKAGE.version),
|
|
24844
24943
|
DEEPSEEK_HARNESS_PACKAGE
|
|
24845
24944
|
);
|
|
24846
24945
|
signal.throwIfAborted();
|
|
@@ -24860,6 +24959,166 @@ var DeepSeekHarnessAgentSpecification = class extends DirectAcpAgentDefinition {
|
|
|
24860
24959
|
};
|
|
24861
24960
|
};
|
|
24862
24961
|
|
|
24962
|
+
// src/agent-catalog/agents/grok-build-agent.ts
|
|
24963
|
+
import { realpath as realpath4 } from "node:fs/promises";
|
|
24964
|
+
import { isAbsolute as isAbsolute3, join as join7, relative as relative2, sep as sep2 } from "node:path";
|
|
24965
|
+
|
|
24966
|
+
// src/agent-installation/grok-managed-package.ts
|
|
24967
|
+
var GROK_BUILD_MANAGED_VERSION = "1.0.21";
|
|
24968
|
+
var GrokBuildManagedPackage = class extends SriManagedNpmPackageDefinition {
|
|
24969
|
+
dependencyResolutionArguments = Object.freeze([
|
|
24970
|
+
"--before=2026-09-04T19:51:47.325Z"
|
|
24971
|
+
]);
|
|
24972
|
+
includeOptionalDependencies = true;
|
|
24973
|
+
requiredDependencies;
|
|
24974
|
+
verifyDependencyClosure = true;
|
|
24975
|
+
constructor(requiredDependency) {
|
|
24976
|
+
super(
|
|
24977
|
+
"@xai-official/grok",
|
|
24978
|
+
GROK_BUILD_MANAGED_VERSION,
|
|
24979
|
+
"grok",
|
|
24980
|
+
"sha512-6yQqC+h1o+ObaqCxImK23dhkrOX1DEBMOKaH6fCK+B4gX0/8XIKZp0n7iKyBdK8KZa5vhMn7pS45kjX49Tps5g==",
|
|
24981
|
+
"https://registry.npmjs.org/@xai-official/grok/-/grok-1.0.21.tgz"
|
|
24982
|
+
);
|
|
24983
|
+
this.requiredDependencies = Object.freeze([requiredDependency]);
|
|
24984
|
+
}
|
|
24985
|
+
};
|
|
24986
|
+
var GROK_DARWIN_ARM64_PACKAGE = new SriManagedNpmDependencyDefinition(
|
|
24987
|
+
"@xai-official/grok-darwin-arm64",
|
|
24988
|
+
GROK_BUILD_MANAGED_VERSION,
|
|
24989
|
+
"sha512-I4pKZGnR6Mv4MJOJsB9B/i2o0ODF4eZtp4jHN5feoTqKIeAUVg38OzBtE8aN/wZa7Xg+qhnf6Jd1tcAFvMoFtQ==",
|
|
24990
|
+
"https://registry.npmjs.org/@xai-official/grok-darwin-arm64/-/grok-darwin-arm64-1.0.21.tgz"
|
|
24991
|
+
);
|
|
24992
|
+
var GROK_DARWIN_X64_PACKAGE = new SriManagedNpmDependencyDefinition(
|
|
24993
|
+
"@xai-official/grok-darwin-x64",
|
|
24994
|
+
GROK_BUILD_MANAGED_VERSION,
|
|
24995
|
+
"sha512-h0nFj3NZ9Kz8w6fQ6UDxxeSIhC1WjwwoRE92iNbG//tZy6YGkppR3s7oRVtt4Xl0CJANKUt0EusyIYnnAvKLzw==",
|
|
24996
|
+
"https://registry.npmjs.org/@xai-official/grok-darwin-x64/-/grok-darwin-x64-1.0.21.tgz"
|
|
24997
|
+
);
|
|
24998
|
+
var GROK_LINUX_ARM64_PACKAGE = new SriManagedNpmDependencyDefinition(
|
|
24999
|
+
"@xai-official/grok-linux-arm64",
|
|
25000
|
+
GROK_BUILD_MANAGED_VERSION,
|
|
25001
|
+
"sha512-Jlwz9XtZPNKz/V/ydifC8OVu3hIZz7pmoStt8c4KCqkSWjWiZ/PBIC0iJiq8rvByhx5Z0EdSyq8ZXVwtocceGA==",
|
|
25002
|
+
"https://registry.npmjs.org/@xai-official/grok-linux-arm64/-/grok-linux-arm64-1.0.21.tgz"
|
|
25003
|
+
);
|
|
25004
|
+
var GROK_LINUX_X64_PACKAGE = new SriManagedNpmDependencyDefinition(
|
|
25005
|
+
"@xai-official/grok-linux-x64",
|
|
25006
|
+
GROK_BUILD_MANAGED_VERSION,
|
|
25007
|
+
"sha512-AjDV5ifEz5LFG2Jt5IlhAeEkJati/wOvCchVbR4eIj2ogjvmXoXlzBrYRXuAJpXBy5q0se/Yuez5FxDU9Ju81w==",
|
|
25008
|
+
"https://registry.npmjs.org/@xai-official/grok-linux-x64/-/grok-linux-x64-1.0.21.tgz"
|
|
25009
|
+
);
|
|
25010
|
+
function grokBuildManagedPackage(platform, architecture) {
|
|
25011
|
+
if (platform === "darwin" && architecture === "arm64") {
|
|
25012
|
+
return new GrokBuildManagedPackage(GROK_DARWIN_ARM64_PACKAGE);
|
|
25013
|
+
}
|
|
25014
|
+
if (platform === "darwin" && architecture === "x64") {
|
|
25015
|
+
return new GrokBuildManagedPackage(GROK_DARWIN_X64_PACKAGE);
|
|
25016
|
+
}
|
|
25017
|
+
if (platform === "linux" && architecture === "arm64") {
|
|
25018
|
+
return new GrokBuildManagedPackage(GROK_LINUX_ARM64_PACKAGE);
|
|
25019
|
+
}
|
|
25020
|
+
if (platform === "linux" && architecture === "x64") {
|
|
25021
|
+
return new GrokBuildManagedPackage(GROK_LINUX_X64_PACKAGE);
|
|
25022
|
+
}
|
|
25023
|
+
throw new Error("Grok Build does not publish a package for this platform");
|
|
25024
|
+
}
|
|
25025
|
+
|
|
25026
|
+
// src/agent-catalog/agents/grok-build-agent.ts
|
|
25027
|
+
function isContainedPath2(root, candidate) {
|
|
25028
|
+
const difference = relative2(root, candidate);
|
|
25029
|
+
return difference.length > 0 && difference !== ".." && !difference.startsWith(`..${sep2}`) && !isAbsolute3(difference);
|
|
25030
|
+
}
|
|
25031
|
+
var GrokBuildAgentSpecification = class extends DirectAcpAgentDefinition {
|
|
25032
|
+
adapterVersion = GROK_BUILD_MANAGED_VERSION;
|
|
25033
|
+
authenticationCommand = () => "grok login";
|
|
25034
|
+
agentExecutable = "grok";
|
|
25035
|
+
agentVersionArguments = ["version"];
|
|
25036
|
+
adapterVersionArguments = ["version"];
|
|
25037
|
+
id = "grok-build";
|
|
25038
|
+
label = "Grok Build";
|
|
25039
|
+
constructor() {
|
|
25040
|
+
super(
|
|
25041
|
+
"MOBIUS_GROK_BUILD_PATH",
|
|
25042
|
+
["--no-auto-update", "agent", "stdio"],
|
|
25043
|
+
[
|
|
25044
|
+
"agents",
|
|
25045
|
+
"grok-build",
|
|
25046
|
+
GROK_BUILD_MANAGED_VERSION,
|
|
25047
|
+
"home",
|
|
25048
|
+
"bin",
|
|
25049
|
+
"grok"
|
|
25050
|
+
]
|
|
25051
|
+
);
|
|
25052
|
+
}
|
|
25053
|
+
createLaunchEnvironment = async (agent, context) => {
|
|
25054
|
+
const stateDirectory = readStateDirectory(context.environment);
|
|
25055
|
+
try {
|
|
25056
|
+
const managed = await this.resolveManagedAgent(
|
|
25057
|
+
stateDirectory,
|
|
25058
|
+
context.platform ?? process.platform,
|
|
25059
|
+
context.signal
|
|
25060
|
+
);
|
|
25061
|
+
if (managed.path === agent.path) {
|
|
25062
|
+
return Object.freeze({
|
|
25063
|
+
GROK_HOME: await realpath4(
|
|
25064
|
+
join7(
|
|
25065
|
+
stateDirectory,
|
|
25066
|
+
"agents",
|
|
25067
|
+
this.id,
|
|
25068
|
+
GROK_BUILD_MANAGED_VERSION,
|
|
25069
|
+
"home"
|
|
25070
|
+
)
|
|
25071
|
+
)
|
|
25072
|
+
});
|
|
25073
|
+
}
|
|
25074
|
+
} catch {
|
|
25075
|
+
context.signal.throwIfAborted();
|
|
25076
|
+
}
|
|
25077
|
+
return Object.freeze({});
|
|
25078
|
+
};
|
|
25079
|
+
resolveManagedAgent = async (stateDirectory, platform, signal) => {
|
|
25080
|
+
signal.throwIfAborted();
|
|
25081
|
+
const versionRoot = await realpath4(
|
|
25082
|
+
join7(stateDirectory, "agents", this.id, GROK_BUILD_MANAGED_VERSION)
|
|
25083
|
+
);
|
|
25084
|
+
await validateManagedNpmPackage(
|
|
25085
|
+
join7(versionRoot, "package"),
|
|
25086
|
+
grokBuildManagedPackage(platform, process.arch)
|
|
25087
|
+
);
|
|
25088
|
+
const executable = await resolveExecutablePath(
|
|
25089
|
+
join7(versionRoot, "home", "bin", "grok"),
|
|
25090
|
+
platform
|
|
25091
|
+
);
|
|
25092
|
+
signal.throwIfAborted();
|
|
25093
|
+
if (executable === null || !isContainedPath2(versionRoot, executable.path)) {
|
|
25094
|
+
throw new AgentProbeError(
|
|
25095
|
+
"managed_agent_invalid",
|
|
25096
|
+
"The managed Grok Build executable is invalid"
|
|
25097
|
+
);
|
|
25098
|
+
}
|
|
25099
|
+
return executable;
|
|
25100
|
+
};
|
|
25101
|
+
verifyAcp = async (connection, initialized, defaultWorkspace, signal) => {
|
|
25102
|
+
const capabilities = initialized.agentCapabilities ?? {};
|
|
25103
|
+
const session = capabilities.sessionCapabilities;
|
|
25104
|
+
if (capabilities.loadSession !== true || session?.close == null || session.list == null || session.resume == null || !(initialized.authMethods ?? []).some(
|
|
25105
|
+
(method) => method.id === "xai.api_key" || method.id === "grok.com"
|
|
25106
|
+
)) {
|
|
25107
|
+
throw new AgentProbeError(
|
|
25108
|
+
"acp_incompatible",
|
|
25109
|
+
"Grok Build reported an unsupported ACP capability set"
|
|
25110
|
+
);
|
|
25111
|
+
}
|
|
25112
|
+
await verifySessionCreation(
|
|
25113
|
+
connection,
|
|
25114
|
+
capabilities,
|
|
25115
|
+
defaultWorkspace,
|
|
25116
|
+
signal,
|
|
25117
|
+
this.label
|
|
25118
|
+
);
|
|
25119
|
+
};
|
|
25120
|
+
};
|
|
25121
|
+
|
|
24863
25122
|
// src/agent-catalog/agents/opencode-agent.ts
|
|
24864
25123
|
import { join as join9 } from "node:path";
|
|
24865
25124
|
|
|
@@ -24871,18 +25130,18 @@ import {
|
|
|
24871
25130
|
copyFile,
|
|
24872
25131
|
mkdir as mkdir2,
|
|
24873
25132
|
mkdtemp as mkdtemp2,
|
|
24874
|
-
open as
|
|
24875
|
-
realpath as
|
|
25133
|
+
open as open4,
|
|
25134
|
+
realpath as realpath5,
|
|
24876
25135
|
rename as rename2,
|
|
24877
25136
|
rm as rm2,
|
|
24878
25137
|
stat as stat4,
|
|
24879
25138
|
writeFile
|
|
24880
25139
|
} from "node:fs/promises";
|
|
24881
|
-
import { dirname as dirname4, isAbsolute as
|
|
25140
|
+
import { dirname as dirname4, isAbsolute as isAbsolute4, join as join8, relative as relative3, sep as sep3 } from "node:path";
|
|
24882
25141
|
|
|
24883
25142
|
// src/agent-installation/verified-download.ts
|
|
24884
25143
|
import { createHash } from "node:crypto";
|
|
24885
|
-
import { open as
|
|
25144
|
+
import { open as open3, unlink } from "node:fs/promises";
|
|
24886
25145
|
import { fetch } from "undici";
|
|
24887
25146
|
|
|
24888
25147
|
// src/network/environment-proxy.ts
|
|
@@ -25014,7 +25273,7 @@ async function downloadVerifiedFile(options, transport = new UndiciInstallerDown
|
|
|
25014
25273
|
);
|
|
25015
25274
|
}
|
|
25016
25275
|
}
|
|
25017
|
-
handle = await
|
|
25276
|
+
handle = await open3(options.destination, "wx", 384);
|
|
25018
25277
|
const digest = createHash("sha256");
|
|
25019
25278
|
const reader = fetched.response.body.getReader();
|
|
25020
25279
|
let bytes = 0;
|
|
@@ -25124,12 +25383,12 @@ var ManagedAgentArchiveError = class extends Error {
|
|
|
25124
25383
|
var ManagedAgentArchiveDownloader = class {
|
|
25125
25384
|
download = async (options) => await downloadVerifiedFile(options);
|
|
25126
25385
|
};
|
|
25127
|
-
function
|
|
25386
|
+
function isRecord5(value) {
|
|
25128
25387
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
25129
25388
|
}
|
|
25130
|
-
function
|
|
25131
|
-
const difference =
|
|
25132
|
-
return difference.length > 0 && difference !== ".." && !difference.startsWith(`..${
|
|
25389
|
+
function isContainedPath3(root, candidate) {
|
|
25390
|
+
const difference = relative3(root, candidate);
|
|
25391
|
+
return difference.length > 0 && difference !== ".." && !difference.startsWith(`..${sep3}`) && !isAbsolute4(difference);
|
|
25133
25392
|
}
|
|
25134
25393
|
async function hashFile(path2, signal) {
|
|
25135
25394
|
signal.throwIfAborted();
|
|
@@ -25164,7 +25423,7 @@ async function hashFile(path2, signal) {
|
|
|
25164
25423
|
async function readManifest(path2) {
|
|
25165
25424
|
let handle;
|
|
25166
25425
|
try {
|
|
25167
|
-
handle = await
|
|
25426
|
+
handle = await open4(path2, "r");
|
|
25168
25427
|
} catch (error61) {
|
|
25169
25428
|
throw new ManagedAgentArchiveError(
|
|
25170
25429
|
"managed_archive_verification_failed",
|
|
@@ -25183,7 +25442,7 @@ async function readManifest(path2) {
|
|
|
25183
25442
|
const parsed = JSON.parse(
|
|
25184
25443
|
await handle.readFile({ encoding: "utf8" })
|
|
25185
25444
|
);
|
|
25186
|
-
if (!
|
|
25445
|
+
if (!isRecord5(parsed)) {
|
|
25187
25446
|
throw new ManagedAgentArchiveError(
|
|
25188
25447
|
"managed_archive_verification_failed",
|
|
25189
25448
|
"The managed Agent archive manifest is invalid"
|
|
@@ -25205,7 +25464,7 @@ async function readManifest(path2) {
|
|
|
25205
25464
|
}
|
|
25206
25465
|
async function validateManagedAgentArchive(root, definition, signal) {
|
|
25207
25466
|
try {
|
|
25208
|
-
const rootPath = await
|
|
25467
|
+
const rootPath = await realpath5(root);
|
|
25209
25468
|
const rootMetadata = await stat4(rootPath);
|
|
25210
25469
|
if (!rootMetadata.isDirectory() || typeof process.getuid === "function" && rootMetadata.uid !== process.getuid()) {
|
|
25211
25470
|
throw new Error("Managed Agent root is not user-owned");
|
|
@@ -25217,7 +25476,7 @@ async function validateManagedAgentArchive(root, definition, signal) {
|
|
|
25217
25476
|
const executable = await resolveExecutablePath(
|
|
25218
25477
|
join8(rootPath, "bin", definition.executableName)
|
|
25219
25478
|
);
|
|
25220
|
-
if (executable === null || !
|
|
25479
|
+
if (executable === null || !isContainedPath3(rootPath, executable.path) || await hashFile(executable.path, signal) !== manifest["executableSha256"]) {
|
|
25221
25480
|
throw new Error("Managed Agent executable is invalid");
|
|
25222
25481
|
}
|
|
25223
25482
|
return executable;
|
|
@@ -25273,7 +25532,7 @@ var ManagedAgentArchiveInstaller = class {
|
|
|
25273
25532
|
const archivePath = join8(working, definition.archiveName);
|
|
25274
25533
|
const extractionRoot = join8(working, "extracted");
|
|
25275
25534
|
await mkdir2(extractionRoot, { mode: 448 });
|
|
25276
|
-
const canonicalExtractionRoot = await
|
|
25535
|
+
const canonicalExtractionRoot = await realpath5(extractionRoot);
|
|
25277
25536
|
const download = await this.#downloader.download({
|
|
25278
25537
|
allowedHosts: /* @__PURE__ */ new Set([
|
|
25279
25538
|
"github.com",
|
|
@@ -25311,11 +25570,11 @@ var ManagedAgentArchiveInstaller = class {
|
|
|
25311
25570
|
signal,
|
|
25312
25571
|
timeoutMilliseconds: ARCHIVE_EXTRACTION_TIMEOUT_MILLISECONDS
|
|
25313
25572
|
});
|
|
25314
|
-
const extracted = await
|
|
25573
|
+
const extracted = await realpath5(
|
|
25315
25574
|
join8(canonicalExtractionRoot, definition.executableName)
|
|
25316
25575
|
);
|
|
25317
25576
|
const extractedMetadata = await stat4(extracted);
|
|
25318
|
-
if (!
|
|
25577
|
+
if (!isContainedPath3(canonicalExtractionRoot, extracted) || !extractedMetadata.isFile()) {
|
|
25319
25578
|
throw new ManagedAgentArchiveError(
|
|
25320
25579
|
"managed_archive_verification_failed",
|
|
25321
25580
|
"The managed Agent archive executable is invalid"
|
|
@@ -25470,7 +25729,7 @@ var OpenCodeAgentSpecification = class extends DirectAcpAgentDefinition {
|
|
|
25470
25729
|
// src/agent-catalog/agents/pi-agent.ts
|
|
25471
25730
|
import { join as join10 } from "node:path";
|
|
25472
25731
|
import {
|
|
25473
|
-
methods as
|
|
25732
|
+
methods as methods4
|
|
25474
25733
|
} from "@agentclientprotocol/sdk";
|
|
25475
25734
|
|
|
25476
25735
|
// src/agent-installation/pi-managed-packages.ts
|
|
@@ -25542,7 +25801,7 @@ var PiAgentSpecification = class extends BridgedAcpAgentDefinition {
|
|
|
25542
25801
|
);
|
|
25543
25802
|
}
|
|
25544
25803
|
const session = await connection.agent.request(
|
|
25545
|
-
|
|
25804
|
+
methods4.agent.session.new,
|
|
25546
25805
|
{
|
|
25547
25806
|
additionalDirectories: [],
|
|
25548
25807
|
cwd: defaultWorkspace,
|
|
@@ -25557,7 +25816,7 @@ var PiAgentSpecification = class extends BridgedAcpAgentDefinition {
|
|
|
25557
25816
|
);
|
|
25558
25817
|
}
|
|
25559
25818
|
const prompt = await connection.agent.request(
|
|
25560
|
-
|
|
25819
|
+
methods4.agent.session.prompt,
|
|
25561
25820
|
{
|
|
25562
25821
|
prompt: [{ text: "/session", type: "text" }],
|
|
25563
25822
|
sessionId: session.sessionId
|
|
@@ -25573,6 +25832,77 @@ var PiAgentSpecification = class extends BridgedAcpAgentDefinition {
|
|
|
25573
25832
|
};
|
|
25574
25833
|
};
|
|
25575
25834
|
|
|
25835
|
+
// src/agent-catalog/agents/workbuddy-agent.ts
|
|
25836
|
+
import { join as join11 } from "node:path";
|
|
25837
|
+
|
|
25838
|
+
// src/agent-installation/workbuddy-managed-package.ts
|
|
25839
|
+
var WORKBUDDY_MANAGED_VERSION = "2.146.0";
|
|
25840
|
+
var WorkBuddyManagedPackage = class extends SriManagedNpmPackageDefinition {
|
|
25841
|
+
dependencyResolutionArguments = Object.freeze([
|
|
25842
|
+
"--before=2026-09-05T12:39:25.295Z"
|
|
25843
|
+
]);
|
|
25844
|
+
includeOptionalDependencies = true;
|
|
25845
|
+
verifyDependencyClosure = true;
|
|
25846
|
+
};
|
|
25847
|
+
var WORKBUDDY_MANAGED_PACKAGE = new WorkBuddyManagedPackage(
|
|
25848
|
+
"@tencent-ai/codebuddy-code",
|
|
25849
|
+
WORKBUDDY_MANAGED_VERSION,
|
|
25850
|
+
"codebuddy",
|
|
25851
|
+
"sha512-81V+8rzYJY8PezHZMs4VZN2nvoijrsRWIuCERTr6hELotcxaZaAcqbQQSbHJcN8eTlFE5TRPlzMI4oEkLCat4A==",
|
|
25852
|
+
"https://registry.npmjs.org/@tencent-ai/codebuddy-code/-/codebuddy-code-2.146.0.tgz"
|
|
25853
|
+
);
|
|
25854
|
+
|
|
25855
|
+
// src/agent-catalog/agents/workbuddy-agent.ts
|
|
25856
|
+
var WorkBuddyAgentSpecification = class extends DirectAcpAgentDefinition {
|
|
25857
|
+
adapterVersion = WORKBUDDY_MANAGED_VERSION;
|
|
25858
|
+
authenticationCommand = () => "codebuddy";
|
|
25859
|
+
agentExecutable = "codebuddy";
|
|
25860
|
+
id = "workbuddy";
|
|
25861
|
+
label = "WorkBuddy";
|
|
25862
|
+
constructor() {
|
|
25863
|
+
super(
|
|
25864
|
+
"MOBIUS_WORKBUDDY_PATH",
|
|
25865
|
+
["--acp"],
|
|
25866
|
+
[
|
|
25867
|
+
"agents",
|
|
25868
|
+
"workbuddy",
|
|
25869
|
+
WORKBUDDY_MANAGED_VERSION,
|
|
25870
|
+
"node_modules",
|
|
25871
|
+
"@tencent-ai",
|
|
25872
|
+
"codebuddy-code",
|
|
25873
|
+
"bin",
|
|
25874
|
+
"codebuddy"
|
|
25875
|
+
]
|
|
25876
|
+
);
|
|
25877
|
+
}
|
|
25878
|
+
createLaunchEnvironment = () => Promise.resolve(Object.freeze({ DISABLE_AUTOUPDATER: "1" }));
|
|
25879
|
+
resolveManagedAgent = async (stateDirectory, _platform, signal) => {
|
|
25880
|
+
signal.throwIfAborted();
|
|
25881
|
+
const executable = await validateManagedNpmPackage(
|
|
25882
|
+
join11(stateDirectory, "agents", this.id, WORKBUDDY_MANAGED_VERSION),
|
|
25883
|
+
WORKBUDDY_MANAGED_PACKAGE
|
|
25884
|
+
);
|
|
25885
|
+
signal.throwIfAborted();
|
|
25886
|
+
return executable;
|
|
25887
|
+
};
|
|
25888
|
+
verifyAcp = async (connection, initialized, defaultWorkspace, signal) => {
|
|
25889
|
+
const capabilities = initialized.agentCapabilities ?? {};
|
|
25890
|
+
if (capabilities.loadSession !== true || (initialized.authMethods ?? []).length === 0) {
|
|
25891
|
+
throw new AgentProbeError(
|
|
25892
|
+
"acp_incompatible",
|
|
25893
|
+
"WorkBuddy reported an unsupported ACP capability set"
|
|
25894
|
+
);
|
|
25895
|
+
}
|
|
25896
|
+
await verifySessionCreation(
|
|
25897
|
+
connection,
|
|
25898
|
+
capabilities,
|
|
25899
|
+
defaultWorkspace,
|
|
25900
|
+
signal,
|
|
25901
|
+
this.label
|
|
25902
|
+
);
|
|
25903
|
+
};
|
|
25904
|
+
};
|
|
25905
|
+
|
|
25576
25906
|
// src/agent-catalog/agents/supported-agent-specifications.ts
|
|
25577
25907
|
function supportedLocalAgentSpecifications() {
|
|
25578
25908
|
return Object.freeze([
|
|
@@ -25580,24 +25910,27 @@ function supportedLocalAgentSpecifications() {
|
|
|
25580
25910
|
new ClaudeCodeAgentSpecification(),
|
|
25581
25911
|
new PiAgentSpecification(),
|
|
25582
25912
|
new DeepSeekHarnessAgentSpecification(),
|
|
25583
|
-
new OpenCodeAgentSpecification()
|
|
25913
|
+
new OpenCodeAgentSpecification(),
|
|
25914
|
+
new CursorCliAgentSpecification(),
|
|
25915
|
+
new GrokBuildAgentSpecification(),
|
|
25916
|
+
new WorkBuddyAgentSpecification()
|
|
25584
25917
|
]);
|
|
25585
25918
|
}
|
|
25586
25919
|
|
|
25587
25920
|
// src/agent-catalog/acp-readiness-probe.ts
|
|
25588
25921
|
import { spawn as spawn3 } from "node:child_process";
|
|
25589
25922
|
import {
|
|
25590
|
-
methods as
|
|
25923
|
+
methods as methods5,
|
|
25591
25924
|
ndJsonStream as ndJsonStream2,
|
|
25592
25925
|
PROTOCOL_VERSION as PROTOCOL_VERSION2,
|
|
25593
25926
|
RequestError as RequestError2
|
|
25594
25927
|
} from "@agentclientprotocol/sdk";
|
|
25595
25928
|
|
|
25596
25929
|
// src/agent-catalog/executable-discovery.ts
|
|
25597
|
-
import { isAbsolute as
|
|
25930
|
+
import { isAbsolute as isAbsolute5, join as join13 } from "node:path";
|
|
25598
25931
|
|
|
25599
25932
|
// src/agent-installation/managed-adapter-installer.ts
|
|
25600
|
-
import { join as
|
|
25933
|
+
import { join as join12 } from "node:path";
|
|
25601
25934
|
var ManagedAdapterInstallError = class extends Error {
|
|
25602
25935
|
code;
|
|
25603
25936
|
constructor(code, message, options = {}) {
|
|
@@ -25659,7 +25992,7 @@ var ManagedAdapterInstaller = class {
|
|
|
25659
25992
|
this.#stateDirectory = options.stateDirectory;
|
|
25660
25993
|
}
|
|
25661
25994
|
install = async (specification, signal) => {
|
|
25662
|
-
const root =
|
|
25995
|
+
const root = join12(
|
|
25663
25996
|
this.#stateDirectory,
|
|
25664
25997
|
"adapters",
|
|
25665
25998
|
specification.id,
|
|
@@ -25698,7 +26031,7 @@ async function resolveManagedAdapterExecutable(specification, context) {
|
|
|
25698
26031
|
let managed;
|
|
25699
26032
|
try {
|
|
25700
26033
|
managed = await validateManagedAdapter(
|
|
25701
|
-
|
|
26034
|
+
join13(
|
|
25702
26035
|
readStateDirectory(context.environment),
|
|
25703
26036
|
"adapters",
|
|
25704
26037
|
specification.id,
|
|
@@ -25714,7 +26047,7 @@ async function resolveManagedAdapterExecutable(specification, context) {
|
|
|
25714
26047
|
async function resolveSpecificationExecutables(executableName, overrideVariable, resolveManaged, context) {
|
|
25715
26048
|
const override = context.environment[overrideVariable];
|
|
25716
26049
|
if (override !== void 0) {
|
|
25717
|
-
if (override.length === 0 || !
|
|
26050
|
+
if (override.length === 0 || !isAbsolute5(override)) {
|
|
25718
26051
|
return [];
|
|
25719
26052
|
}
|
|
25720
26053
|
const executable = await resolveExecutablePath(override, context.platform);
|
|
@@ -25825,41 +26158,41 @@ var DiscoveryAcpHandler = class {
|
|
|
25825
26158
|
};
|
|
25826
26159
|
function readableAcpStream(input2) {
|
|
25827
26160
|
let byteLength = 0;
|
|
25828
|
-
let
|
|
26161
|
+
let open6 = true;
|
|
25829
26162
|
return new ReadableStream({
|
|
25830
26163
|
start(controller) {
|
|
25831
26164
|
input2.on("data", (chunk) => {
|
|
25832
|
-
if (!
|
|
26165
|
+
if (!open6) {
|
|
25833
26166
|
return;
|
|
25834
26167
|
}
|
|
25835
26168
|
if (!(chunk instanceof Uint8Array)) {
|
|
25836
|
-
|
|
26169
|
+
open6 = false;
|
|
25837
26170
|
controller.error(new Error("ACP adapter produced invalid output"));
|
|
25838
26171
|
return;
|
|
25839
26172
|
}
|
|
25840
26173
|
byteLength += chunk.byteLength;
|
|
25841
26174
|
if (byteLength > ACP_OUTPUT_LIMIT_BYTES) {
|
|
25842
|
-
|
|
26175
|
+
open6 = false;
|
|
25843
26176
|
controller.error(new Error("ACP adapter output limit exceeded"));
|
|
25844
26177
|
return;
|
|
25845
26178
|
}
|
|
25846
26179
|
controller.enqueue(new Uint8Array(chunk));
|
|
25847
26180
|
});
|
|
25848
26181
|
input2.once("end", () => {
|
|
25849
|
-
if (
|
|
25850
|
-
|
|
26182
|
+
if (open6) {
|
|
26183
|
+
open6 = false;
|
|
25851
26184
|
controller.close();
|
|
25852
26185
|
}
|
|
25853
26186
|
});
|
|
25854
26187
|
input2.once("error", (error61) => {
|
|
25855
|
-
if (
|
|
25856
|
-
|
|
26188
|
+
if (open6) {
|
|
26189
|
+
open6 = false;
|
|
25857
26190
|
controller.error(error61);
|
|
25858
26191
|
}
|
|
25859
26192
|
});
|
|
25860
26193
|
},
|
|
25861
26194
|
cancel() {
|
|
25862
|
-
|
|
26195
|
+
open6 = false;
|
|
25863
26196
|
}
|
|
25864
26197
|
});
|
|
25865
26198
|
}
|
|
@@ -25928,7 +26261,7 @@ async function probeAcpReadiness(specification, agent, environment, defaultWorks
|
|
|
25928
26261
|
try {
|
|
25929
26262
|
const initialized = await Promise.race([
|
|
25930
26263
|
connection.agent.request(
|
|
25931
|
-
|
|
26264
|
+
methods5.agent.initialize,
|
|
25932
26265
|
{
|
|
25933
26266
|
clientCapabilities: {},
|
|
25934
26267
|
clientInfo: { name: "mobius", version: "0.0.3" },
|
|
@@ -26139,16 +26472,8 @@ async function discoverLocalAgentInventory(options) {
|
|
|
26139
26472
|
async (specification) => await discoverAgent(specification, options)
|
|
26140
26473
|
)
|
|
26141
26474
|
);
|
|
26142
|
-
let grantedAgents = /* @__PURE__ */ new Set();
|
|
26143
|
-
try {
|
|
26144
|
-
grantedAgents = await readGrantedAgents(
|
|
26145
|
-
readStateDirectory(options.environment)
|
|
26146
|
-
);
|
|
26147
|
-
} catch {
|
|
26148
|
-
}
|
|
26149
26475
|
return new LocalAgentInventory(
|
|
26150
26476
|
discoveries,
|
|
26151
|
-
grantedAgents,
|
|
26152
26477
|
options.platform,
|
|
26153
26478
|
options.architecture
|
|
26154
26479
|
);
|
|
@@ -26179,7 +26504,7 @@ var PairingClientError = class extends Error {
|
|
|
26179
26504
|
this.name = "PairingClientError";
|
|
26180
26505
|
}
|
|
26181
26506
|
};
|
|
26182
|
-
function
|
|
26507
|
+
function isRecord6(value) {
|
|
26183
26508
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
26184
26509
|
}
|
|
26185
26510
|
function hasExactKeys(value, expectedKeys) {
|
|
@@ -26293,7 +26618,7 @@ async function resolveDefaultWorkspace(path2) {
|
|
|
26293
26618
|
const requestedWorkspace = resolve3(path2);
|
|
26294
26619
|
try {
|
|
26295
26620
|
await mkdir3(requestedWorkspace, { recursive: true, mode: 448 });
|
|
26296
|
-
const defaultWorkspace = await
|
|
26621
|
+
const defaultWorkspace = await realpath6(requestedWorkspace);
|
|
26297
26622
|
const metadata = await stat5(defaultWorkspace);
|
|
26298
26623
|
if (!metadata.isDirectory()) {
|
|
26299
26624
|
throw new PairingClientError(
|
|
@@ -26332,9 +26657,9 @@ async function readJsonResponse(response) {
|
|
|
26332
26657
|
}
|
|
26333
26658
|
}
|
|
26334
26659
|
function readRelayError(value) {
|
|
26335
|
-
if (
|
|
26660
|
+
if (isRecord6(value)) {
|
|
26336
26661
|
const error61 = value["error"];
|
|
26337
|
-
if (
|
|
26662
|
+
if (isRecord6(error61)) {
|
|
26338
26663
|
const code = error61["code"];
|
|
26339
26664
|
const message = error61["message"];
|
|
26340
26665
|
if (typeof code === "string" && typeof message === "string") {
|
|
@@ -26348,7 +26673,7 @@ function readRelayError(value) {
|
|
|
26348
26673
|
);
|
|
26349
26674
|
}
|
|
26350
26675
|
function decodeClaimResponse(value) {
|
|
26351
|
-
if (!
|
|
26676
|
+
if (!isRecord6(value) || !hasExactKeys(value, CLAIM_RESPONSE_KEYS)) {
|
|
26352
26677
|
throw new PairingClientError(
|
|
26353
26678
|
"invalid_relay_response",
|
|
26354
26679
|
"The relay returned an invalid pairing response"
|
|
@@ -26370,7 +26695,7 @@ async function claimPairing(options, defaultWorkspace, localAgents, installableA
|
|
|
26370
26695
|
id: agent.id,
|
|
26371
26696
|
label: agent.label
|
|
26372
26697
|
}));
|
|
26373
|
-
const endpoint =
|
|
26698
|
+
const endpoint = mobiusApiUrl(options.relayOrigin, "/pairings/claim");
|
|
26374
26699
|
let response;
|
|
26375
26700
|
try {
|
|
26376
26701
|
response = await fetch2(endpoint, {
|
|
@@ -26378,8 +26703,7 @@ async function claimPairing(options, defaultWorkspace, localAgents, installableA
|
|
|
26378
26703
|
agents,
|
|
26379
26704
|
installableAgents: installableAgents.map((agent) => ({
|
|
26380
26705
|
id: agent.id,
|
|
26381
|
-
label: agent.label
|
|
26382
|
-
requiresLocalApproval: agent.requiresLocalApproval
|
|
26706
|
+
label: agent.label
|
|
26383
26707
|
})),
|
|
26384
26708
|
machineName: hostname3(),
|
|
26385
26709
|
pairingCode: options.code,
|
|
@@ -26407,10 +26731,10 @@ async function claimPairing(options, defaultWorkspace, localAgents, installableA
|
|
|
26407
26731
|
return decodeClaimResponse(value);
|
|
26408
26732
|
}
|
|
26409
26733
|
async function persistConnection(channelId, relayOrigin, daemonToken, defaultWorkspace) {
|
|
26410
|
-
const connectionsDirectory =
|
|
26734
|
+
const connectionsDirectory = join14(readStateDirectory(), "connections");
|
|
26411
26735
|
await mkdir3(connectionsDirectory, { mode: 448, recursive: true });
|
|
26412
|
-
const connectionPath =
|
|
26413
|
-
const temporaryPath =
|
|
26736
|
+
const connectionPath = join14(connectionsDirectory, `${channelId}.json`);
|
|
26737
|
+
const temporaryPath = join14(
|
|
26414
26738
|
connectionsDirectory,
|
|
26415
26739
|
`.${channelId}.${randomUUID()}.tmp`
|
|
26416
26740
|
);
|
|
@@ -26433,7 +26757,7 @@ async function persistConnection(channelId, relayOrigin, daemonToken, defaultWor
|
|
|
26433
26757
|
return connectionPath;
|
|
26434
26758
|
}
|
|
26435
26759
|
function decodeSavedConnection(value, expectedChannelId) {
|
|
26436
|
-
if (!
|
|
26760
|
+
if (!isRecord6(value) || !hasExactKeys(value, SAVED_CONNECTION_KEYS)) {
|
|
26437
26761
|
throw new PairingClientError(
|
|
26438
26762
|
"invalid_connection",
|
|
26439
26763
|
"The saved connection is invalid"
|
|
@@ -26457,13 +26781,13 @@ function decodeSavedConnection(value, expectedChannelId) {
|
|
|
26457
26781
|
};
|
|
26458
26782
|
}
|
|
26459
26783
|
async function readSavedConnection(channelId) {
|
|
26460
|
-
const connectionPath =
|
|
26784
|
+
const connectionPath = join14(
|
|
26461
26785
|
readStateDirectory(),
|
|
26462
26786
|
"connections",
|
|
26463
26787
|
`${channelId}.json`
|
|
26464
26788
|
);
|
|
26465
26789
|
let encoded = "";
|
|
26466
|
-
const handle = await
|
|
26790
|
+
const handle = await open5(connectionPath, "r");
|
|
26467
26791
|
try {
|
|
26468
26792
|
const metadata = await handle.stat();
|
|
26469
26793
|
if (!metadata.isFile() || metadata.size > MAX_CONNECTION_FILE_LENGTH) {
|
|
@@ -26506,13 +26830,13 @@ function assertInventoryUsable(inventory) {
|
|
|
26506
26830
|
}
|
|
26507
26831
|
function buildPairedDaemon(connection, connectionPath, inventory) {
|
|
26508
26832
|
assertInventoryUsable(inventory);
|
|
26509
|
-
const relayUrl =
|
|
26510
|
-
|
|
26511
|
-
connection.
|
|
26833
|
+
const relayUrl = mobiusApiUrl(
|
|
26834
|
+
connection.relayOrigin,
|
|
26835
|
+
`/channels/${encodeURIComponent(connection.channelId)}/daemon`
|
|
26512
26836
|
);
|
|
26513
26837
|
relayUrl.protocol = relayUrl.protocol === "https:" ? "wss:" : "ws:";
|
|
26514
26838
|
relayUrl.searchParams.set("token", connection.daemonToken);
|
|
26515
|
-
const auditDatabasePath =
|
|
26839
|
+
const auditDatabasePath = join14(
|
|
26516
26840
|
readStateDirectory(),
|
|
26517
26841
|
"audit",
|
|
26518
26842
|
`${connection.channelId}.sqlite`
|
|
@@ -26571,7 +26895,7 @@ async function pairLocalMachine(arguments_, signal = new AbortController().signa
|
|
|
26571
26895
|
}
|
|
26572
26896
|
async function resumeLocalMachine(arguments_, signal = new AbortController().signal) {
|
|
26573
26897
|
const channelId = parseChannelArgument(arguments_);
|
|
26574
|
-
const connectionPath =
|
|
26898
|
+
const connectionPath = join14(
|
|
26575
26899
|
readStateDirectory(),
|
|
26576
26900
|
"connections",
|
|
26577
26901
|
`${channelId}.json`
|
|
@@ -26626,8 +26950,7 @@ async function publishAgentCatalog(config2, signal) {
|
|
|
26626
26950
|
})),
|
|
26627
26951
|
installableAgents: catalog.installableAgents.map((agent) => ({
|
|
26628
26952
|
id: agent.id,
|
|
26629
|
-
label: agent.label
|
|
26630
|
-
requiresLocalApproval: agent.requiresLocalApproval
|
|
26953
|
+
label: agent.label
|
|
26631
26954
|
}))
|
|
26632
26955
|
}),
|
|
26633
26956
|
dispatcher: environmentProxyDispatcher,
|
|
@@ -26668,12 +26991,6 @@ var RequestedInstallation = class extends AgentInstallation {
|
|
|
26668
26991
|
super(requestId, agentId);
|
|
26669
26992
|
}
|
|
26670
26993
|
};
|
|
26671
|
-
var AwaitingLocalApproval = class extends AgentInstallation {
|
|
26672
|
-
status = "awaiting_local_approval";
|
|
26673
|
-
constructor(requestId, agentId) {
|
|
26674
|
-
super(requestId, agentId);
|
|
26675
|
-
}
|
|
26676
|
-
};
|
|
26677
26994
|
var RunningInstallation = class extends AgentInstallation {
|
|
26678
26995
|
stage;
|
|
26679
26996
|
status = "running";
|
|
@@ -26728,9 +27045,9 @@ var InstallationJob = class {
|
|
|
26728
27045
|
this.state = new RequestedInstallation(requestId, agentId);
|
|
26729
27046
|
}
|
|
26730
27047
|
};
|
|
26731
|
-
function
|
|
27048
|
+
function authorizedSpecificationFor(specifications, agentId) {
|
|
26732
27049
|
for (const specification of specifications) {
|
|
26733
|
-
if (specification.id === agentId) {
|
|
27050
|
+
if (specification.id === agentId && specification.supportsInstallation(process.platform, process.arch)) {
|
|
26734
27051
|
return specification;
|
|
26735
27052
|
}
|
|
26736
27053
|
}
|
|
@@ -26749,14 +27066,12 @@ function executionFailure(error61) {
|
|
|
26749
27066
|
var AgentInstallationManager = class {
|
|
26750
27067
|
#activeAgents = /* @__PURE__ */ new Map();
|
|
26751
27068
|
#audit;
|
|
26752
|
-
#authorizer;
|
|
26753
27069
|
#executor;
|
|
26754
27070
|
#jobs = /* @__PURE__ */ new Map();
|
|
26755
27071
|
#observer;
|
|
26756
27072
|
#specifications;
|
|
26757
|
-
constructor(specifications,
|
|
27073
|
+
constructor(specifications, executor, observer, audit = new NullInstallationAudit()) {
|
|
26758
27074
|
this.#audit = audit;
|
|
26759
|
-
this.#authorizer = authorizer;
|
|
26760
27075
|
this.#executor = executor;
|
|
26761
27076
|
this.#observer = observer;
|
|
26762
27077
|
this.#specifications = Object.freeze([...specifications]);
|
|
@@ -26787,7 +27102,7 @@ var AgentInstallationManager = class {
|
|
|
26787
27102
|
command.requestId,
|
|
26788
27103
|
command.agentId
|
|
26789
27104
|
);
|
|
26790
|
-
const specification =
|
|
27105
|
+
const specification = authorizedSpecificationFor(
|
|
26791
27106
|
this.#specifications,
|
|
26792
27107
|
command.agentId
|
|
26793
27108
|
);
|
|
@@ -26890,45 +27205,14 @@ var AgentInstallationManager = class {
|
|
|
26890
27205
|
}, INSTALLATION_DEADLINE_MILLISECONDS);
|
|
26891
27206
|
const signal = job.controller.signal;
|
|
26892
27207
|
try {
|
|
26893
|
-
await this.#transition(
|
|
26894
|
-
job,
|
|
26895
|
-
new AwaitingLocalApproval(job.requestId, job.agentId)
|
|
26896
|
-
);
|
|
26897
|
-
this.#audit.record(
|
|
26898
|
-
"agent_installation_awaiting_approval",
|
|
26899
|
-
job.requestId,
|
|
26900
|
-
job.agentId
|
|
26901
|
-
);
|
|
26902
|
-
const approved = await this.#authorizer.authorize(
|
|
26903
|
-
specification.id,
|
|
26904
|
-
specification.label,
|
|
26905
|
-
job.requestId,
|
|
26906
|
-
signal
|
|
26907
|
-
);
|
|
26908
27208
|
signal.throwIfAborted();
|
|
26909
|
-
if (!approved) {
|
|
26910
|
-
const denied = new FailedInstallation(
|
|
26911
|
-
job.requestId,
|
|
26912
|
-
job.agentId,
|
|
26913
|
-
"installation_not_authorized",
|
|
26914
|
-
"Installation was not approved on the local machine"
|
|
26915
|
-
);
|
|
26916
|
-
await this.#transition(job, denied);
|
|
26917
|
-
this.#audit.record(
|
|
26918
|
-
"agent_installation_denied",
|
|
26919
|
-
job.requestId,
|
|
26920
|
-
job.agentId
|
|
26921
|
-
);
|
|
26922
|
-
job.completion.resolve(denied);
|
|
26923
|
-
return;
|
|
26924
|
-
}
|
|
26925
27209
|
this.#audit.record(
|
|
26926
27210
|
"agent_installation_authorized",
|
|
26927
27211
|
job.requestId,
|
|
26928
|
-
|
|
27212
|
+
specification.id
|
|
26929
27213
|
);
|
|
26930
27214
|
await this.#executor.execute(
|
|
26931
|
-
|
|
27215
|
+
specification.id,
|
|
26932
27216
|
job.requestId,
|
|
26933
27217
|
async (stage) => {
|
|
26934
27218
|
signal.throwIfAborted();
|
|
@@ -27198,12 +27482,10 @@ import { realpathSync as realpathSync2, statSync as statSync2 } from "node:fs";
|
|
|
27198
27482
|
import { resolve as resolve4 } from "node:path";
|
|
27199
27483
|
|
|
27200
27484
|
// src/agent-installation/fixed-agent-install-recipes.ts
|
|
27201
|
-
import { mkdir as
|
|
27202
|
-
import { join as
|
|
27203
|
-
|
|
27204
|
-
|
|
27205
|
-
var AGENT_INSTALL_TIMEOUT_MILLISECONDS = 5 * 60 * 1e3;
|
|
27206
|
-
var MINIMAL_PATH2 = "/usr/bin:/bin";
|
|
27485
|
+
import { mkdir as mkdir5, mkdtemp as mkdtemp3, rm as rm3 } from "node:fs/promises";
|
|
27486
|
+
import { join as join17 } from "node:path";
|
|
27487
|
+
|
|
27488
|
+
// src/agent-installation/fixed-agent-install-recipe.ts
|
|
27207
27489
|
var FixedAgentInstallRecipe = class {
|
|
27208
27490
|
assertSupportedPlatform = () => {
|
|
27209
27491
|
if (process.platform !== "darwin" && process.platform !== "linux" || process.arch !== "arm64" && process.arch !== "x64") {
|
|
@@ -27224,28 +27506,243 @@ var FixedAgentInstallRecipe = class {
|
|
|
27224
27506
|
return executable;
|
|
27225
27507
|
};
|
|
27226
27508
|
};
|
|
27509
|
+
|
|
27510
|
+
// src/agent-installation/grok-build-install-recipe.ts
|
|
27511
|
+
import { mkdir as mkdir4, realpath as realpath7, stat as stat6 } from "node:fs/promises";
|
|
27512
|
+
import { delimiter as delimiter2, dirname as dirname5, isAbsolute as isAbsolute6, join as join15, relative as relative4, sep as sep4 } from "node:path";
|
|
27513
|
+
var INSTALL_TIMEOUT_MILLISECONDS2 = 5 * 60 * 1e3;
|
|
27514
|
+
function isContainedPath4(root, candidate) {
|
|
27515
|
+
const difference = relative4(root, candidate);
|
|
27516
|
+
return difference.length > 0 && difference !== ".." && !difference.startsWith(`..${sep4}`) && !isAbsolute6(difference);
|
|
27517
|
+
}
|
|
27518
|
+
async function resolveLifecycleScript(packageRoot) {
|
|
27519
|
+
try {
|
|
27520
|
+
const canonicalPackageRoot = await realpath7(packageRoot);
|
|
27521
|
+
const script = await realpath7(
|
|
27522
|
+
join15(canonicalPackageRoot, "bin", "postinstall.js")
|
|
27523
|
+
);
|
|
27524
|
+
const metadata = await stat6(script);
|
|
27525
|
+
if (!metadata.isFile() || !isContainedPath4(canonicalPackageRoot, script)) {
|
|
27526
|
+
throw new Error("Invalid Grok Build lifecycle script");
|
|
27527
|
+
}
|
|
27528
|
+
return script;
|
|
27529
|
+
} catch (error61) {
|
|
27530
|
+
throw new InstallationManagerError(
|
|
27531
|
+
"agent_verification_failed",
|
|
27532
|
+
"The managed Grok Build lifecycle script is invalid",
|
|
27533
|
+
{ cause: error61 }
|
|
27534
|
+
);
|
|
27535
|
+
}
|
|
27536
|
+
}
|
|
27537
|
+
var GrokBuildInstallRecipe = class extends FixedAgentInstallRecipe {
|
|
27538
|
+
#npmInstaller;
|
|
27539
|
+
id = "grok-build";
|
|
27540
|
+
label = "Grok Build";
|
|
27541
|
+
releaseChannel = GROK_BUILD_MANAGED_VERSION;
|
|
27542
|
+
constructor(npmInstaller = new ManagedNpmPackageInstaller()) {
|
|
27543
|
+
super();
|
|
27544
|
+
this.#npmInstaller = npmInstaller;
|
|
27545
|
+
}
|
|
27546
|
+
install = async (options) => {
|
|
27547
|
+
this.assertSupportedPlatform();
|
|
27548
|
+
const definition = grokBuildManagedPackage(process.platform, process.arch);
|
|
27549
|
+
const versionRoot = join15(
|
|
27550
|
+
options.stateDirectory,
|
|
27551
|
+
"agents",
|
|
27552
|
+
this.id,
|
|
27553
|
+
GROK_BUILD_MANAGED_VERSION
|
|
27554
|
+
);
|
|
27555
|
+
const packageRoot = join15(versionRoot, "package");
|
|
27556
|
+
const managedHome = join15(versionRoot, "home");
|
|
27557
|
+
try {
|
|
27558
|
+
await mkdir4(managedHome, { mode: 448, recursive: true });
|
|
27559
|
+
const canonicalHome = await realpath7(managedHome);
|
|
27560
|
+
await options.report("downloading");
|
|
27561
|
+
await options.report("verifying");
|
|
27562
|
+
await options.report("installing_agent");
|
|
27563
|
+
await this.#npmInstaller.install(
|
|
27564
|
+
packageRoot,
|
|
27565
|
+
definition,
|
|
27566
|
+
options.environment,
|
|
27567
|
+
options.signal
|
|
27568
|
+
);
|
|
27569
|
+
options.audit.record(
|
|
27570
|
+
"agent_npm_package_verified",
|
|
27571
|
+
options.requestId,
|
|
27572
|
+
this.id,
|
|
27573
|
+
{
|
|
27574
|
+
integrity: definition.integrity,
|
|
27575
|
+
package: definition.packageName,
|
|
27576
|
+
version: definition.version
|
|
27577
|
+
}
|
|
27578
|
+
);
|
|
27579
|
+
const script = await resolveLifecycleScript(
|
|
27580
|
+
join15(packageRoot, "node_modules", "@xai-official", "grok")
|
|
27581
|
+
);
|
|
27582
|
+
await runBoundedProcess({
|
|
27583
|
+
arguments: [script],
|
|
27584
|
+
command: process.execPath,
|
|
27585
|
+
cwd: dirname5(script),
|
|
27586
|
+
environment: {
|
|
27587
|
+
GROK_HOME: canonicalHome,
|
|
27588
|
+
GROK_INSTALL_COMPLETIONS: "0",
|
|
27589
|
+
GROK_NPM_REGISTRY: "https://registry.npmjs.org/",
|
|
27590
|
+
HOME: canonicalHome,
|
|
27591
|
+
PATH: `${dirname5(process.execPath)}${delimiter2}/usr/bin${delimiter2}/bin`
|
|
27592
|
+
},
|
|
27593
|
+
outputLimitBytes: 64 * 1024,
|
|
27594
|
+
signal: options.signal,
|
|
27595
|
+
timeoutMilliseconds: INSTALL_TIMEOUT_MILLISECONDS2
|
|
27596
|
+
});
|
|
27597
|
+
options.audit.record(
|
|
27598
|
+
"agent_lifecycle_step_completed",
|
|
27599
|
+
options.requestId,
|
|
27600
|
+
this.id,
|
|
27601
|
+
{
|
|
27602
|
+
lifecycle: "postinstall",
|
|
27603
|
+
package: definition.packageName,
|
|
27604
|
+
version: definition.version
|
|
27605
|
+
}
|
|
27606
|
+
);
|
|
27607
|
+
return await this.requireInstalledExecutable(
|
|
27608
|
+
join15(canonicalHome, "bin", "grok")
|
|
27609
|
+
);
|
|
27610
|
+
} catch (error61) {
|
|
27611
|
+
if (options.signal.aborted) {
|
|
27612
|
+
options.signal.throwIfAborted();
|
|
27613
|
+
}
|
|
27614
|
+
if (error61 instanceof ManagedNpmPackageError) {
|
|
27615
|
+
if (error61.code === "managed_package_verification_failed") {
|
|
27616
|
+
throw new InstallationManagerError(
|
|
27617
|
+
"agent_verification_failed",
|
|
27618
|
+
"The managed Grok Build packages did not match their pinned artifacts",
|
|
27619
|
+
{ cause: error61 }
|
|
27620
|
+
);
|
|
27621
|
+
}
|
|
27622
|
+
if (error61.code === "managed_package_publish_failed") {
|
|
27623
|
+
throw new InstallationManagerError(
|
|
27624
|
+
"agent_publish_failed",
|
|
27625
|
+
"The managed Grok Build package could not be published",
|
|
27626
|
+
{ cause: error61 }
|
|
27627
|
+
);
|
|
27628
|
+
}
|
|
27629
|
+
throw new InstallationManagerError(error61.code, error61.message, {
|
|
27630
|
+
cause: error61
|
|
27631
|
+
});
|
|
27632
|
+
}
|
|
27633
|
+
if (error61 instanceof InstallationManagerError) {
|
|
27634
|
+
throw error61;
|
|
27635
|
+
}
|
|
27636
|
+
throw new InstallationManagerError(
|
|
27637
|
+
"agent_install_failed",
|
|
27638
|
+
"The fixed Grok Build installation recipe failed",
|
|
27639
|
+
{ cause: error61 }
|
|
27640
|
+
);
|
|
27641
|
+
}
|
|
27642
|
+
};
|
|
27643
|
+
};
|
|
27644
|
+
|
|
27645
|
+
// src/agent-installation/workbuddy-install-recipe.ts
|
|
27646
|
+
import { join as join16 } from "node:path";
|
|
27647
|
+
var WorkBuddyInstallRecipe = class extends FixedAgentInstallRecipe {
|
|
27648
|
+
#npmInstaller;
|
|
27649
|
+
id = "workbuddy";
|
|
27650
|
+
label = "WorkBuddy";
|
|
27651
|
+
releaseChannel = WORKBUDDY_MANAGED_VERSION;
|
|
27652
|
+
constructor(npmInstaller = new ManagedNpmPackageInstaller()) {
|
|
27653
|
+
super();
|
|
27654
|
+
this.#npmInstaller = npmInstaller;
|
|
27655
|
+
}
|
|
27656
|
+
install = async (options) => {
|
|
27657
|
+
this.assertSupportedPlatform();
|
|
27658
|
+
try {
|
|
27659
|
+
await options.report("downloading");
|
|
27660
|
+
await options.report("verifying");
|
|
27661
|
+
await options.report("installing_agent");
|
|
27662
|
+
const executable = await this.#npmInstaller.install(
|
|
27663
|
+
join16(
|
|
27664
|
+
options.stateDirectory,
|
|
27665
|
+
"agents",
|
|
27666
|
+
this.id,
|
|
27667
|
+
WORKBUDDY_MANAGED_VERSION
|
|
27668
|
+
),
|
|
27669
|
+
WORKBUDDY_MANAGED_PACKAGE,
|
|
27670
|
+
options.environment,
|
|
27671
|
+
options.signal
|
|
27672
|
+
);
|
|
27673
|
+
options.audit.record(
|
|
27674
|
+
"agent_npm_package_verified",
|
|
27675
|
+
options.requestId,
|
|
27676
|
+
this.id,
|
|
27677
|
+
{
|
|
27678
|
+
integrity: WORKBUDDY_MANAGED_PACKAGE.integrity,
|
|
27679
|
+
package: WORKBUDDY_MANAGED_PACKAGE.packageName,
|
|
27680
|
+
version: WORKBUDDY_MANAGED_PACKAGE.version
|
|
27681
|
+
}
|
|
27682
|
+
);
|
|
27683
|
+
return executable;
|
|
27684
|
+
} catch (error61) {
|
|
27685
|
+
if (options.signal.aborted) {
|
|
27686
|
+
options.signal.throwIfAborted();
|
|
27687
|
+
}
|
|
27688
|
+
if (error61 instanceof ManagedNpmPackageError) {
|
|
27689
|
+
if (error61.code === "managed_package_verification_failed") {
|
|
27690
|
+
throw new InstallationManagerError(
|
|
27691
|
+
"agent_verification_failed",
|
|
27692
|
+
"The managed WorkBuddy package did not match its pinned artifact",
|
|
27693
|
+
{ cause: error61 }
|
|
27694
|
+
);
|
|
27695
|
+
}
|
|
27696
|
+
if (error61.code === "managed_package_publish_failed") {
|
|
27697
|
+
throw new InstallationManagerError(
|
|
27698
|
+
"agent_publish_failed",
|
|
27699
|
+
"The managed WorkBuddy package could not be published",
|
|
27700
|
+
{ cause: error61 }
|
|
27701
|
+
);
|
|
27702
|
+
}
|
|
27703
|
+
throw new InstallationManagerError(error61.code, error61.message, {
|
|
27704
|
+
cause: error61
|
|
27705
|
+
});
|
|
27706
|
+
}
|
|
27707
|
+
if (error61 instanceof InstallationManagerError) {
|
|
27708
|
+
throw error61;
|
|
27709
|
+
}
|
|
27710
|
+
throw new InstallationManagerError(
|
|
27711
|
+
"agent_install_failed",
|
|
27712
|
+
"The fixed WorkBuddy installation recipe failed",
|
|
27713
|
+
{ cause: error61 }
|
|
27714
|
+
);
|
|
27715
|
+
}
|
|
27716
|
+
};
|
|
27717
|
+
};
|
|
27718
|
+
|
|
27719
|
+
// src/agent-installation/fixed-agent-install-recipes.ts
|
|
27720
|
+
var INSTALLER_DOWNLOAD_LIMIT_BYTES = 1024 * 1024;
|
|
27721
|
+
var INSTALLER_DOWNLOAD_TIMEOUT_MILLISECONDS = 6e4;
|
|
27722
|
+
var AGENT_INSTALL_TIMEOUT_MILLISECONDS = 5 * 60 * 1e3;
|
|
27723
|
+
var MINIMAL_PATH2 = "/usr/bin:/bin";
|
|
27227
27724
|
var CodexInstallRecipe = class extends FixedAgentInstallRecipe {
|
|
27228
27725
|
id = "codex";
|
|
27229
27726
|
label = "Codex";
|
|
27230
27727
|
releaseChannel = "latest";
|
|
27231
27728
|
install = async (options) => {
|
|
27232
27729
|
this.assertSupportedPlatform();
|
|
27233
|
-
const root =
|
|
27234
|
-
const temporaryRoot =
|
|
27730
|
+
const root = join17(options.stateDirectory, "agents", this.id);
|
|
27731
|
+
const temporaryRoot = join17(options.stateDirectory, "temporary");
|
|
27235
27732
|
await Promise.all([
|
|
27236
|
-
|
|
27237
|
-
|
|
27733
|
+
mkdir5(root, { mode: 448, recursive: true }),
|
|
27734
|
+
mkdir5(temporaryRoot, { mode: 448, recursive: true })
|
|
27238
27735
|
]);
|
|
27239
27736
|
const temporaryDirectory = await mkdtemp3(
|
|
27240
|
-
|
|
27737
|
+
join17(temporaryRoot, ".codex-install-")
|
|
27241
27738
|
);
|
|
27242
|
-
const installerPath =
|
|
27243
|
-
const installDirectory =
|
|
27244
|
-
const codexHome =
|
|
27739
|
+
const installerPath = join17(temporaryDirectory, "install.sh");
|
|
27740
|
+
const installDirectory = join17(root, "bin");
|
|
27741
|
+
const codexHome = join17(root, "home");
|
|
27245
27742
|
try {
|
|
27246
27743
|
await Promise.all([
|
|
27247
|
-
|
|
27248
|
-
|
|
27744
|
+
mkdir5(installDirectory, { mode: 448, recursive: true }),
|
|
27745
|
+
mkdir5(codexHome, { mode: 448, recursive: true })
|
|
27249
27746
|
]);
|
|
27250
27747
|
await options.report("downloading");
|
|
27251
27748
|
const download = await downloadVerifiedFile({
|
|
@@ -27285,7 +27782,7 @@ var CodexInstallRecipe = class extends FixedAgentInstallRecipe {
|
|
|
27285
27782
|
timeoutMilliseconds: AGENT_INSTALL_TIMEOUT_MILLISECONDS
|
|
27286
27783
|
});
|
|
27287
27784
|
return await this.requireInstalledExecutable(
|
|
27288
|
-
|
|
27785
|
+
join17(installDirectory, "codex")
|
|
27289
27786
|
);
|
|
27290
27787
|
} catch (error61) {
|
|
27291
27788
|
if (options.signal.aborted) {
|
|
@@ -27309,17 +27806,17 @@ var ClaudeCodeInstallRecipe = class extends FixedAgentInstallRecipe {
|
|
|
27309
27806
|
releaseChannel = "stable";
|
|
27310
27807
|
install = async (options) => {
|
|
27311
27808
|
this.assertSupportedPlatform();
|
|
27312
|
-
const root =
|
|
27313
|
-
const managedHome =
|
|
27314
|
-
const temporaryRoot =
|
|
27809
|
+
const root = join17(options.stateDirectory, "agents", this.id);
|
|
27810
|
+
const managedHome = join17(root, "home");
|
|
27811
|
+
const temporaryRoot = join17(options.stateDirectory, "temporary");
|
|
27315
27812
|
await Promise.all([
|
|
27316
|
-
|
|
27317
|
-
|
|
27813
|
+
mkdir5(managedHome, { mode: 448, recursive: true }),
|
|
27814
|
+
mkdir5(temporaryRoot, { mode: 448, recursive: true })
|
|
27318
27815
|
]);
|
|
27319
27816
|
const temporaryDirectory = await mkdtemp3(
|
|
27320
|
-
|
|
27817
|
+
join17(temporaryRoot, ".claude-install-")
|
|
27321
27818
|
);
|
|
27322
|
-
const installerPath =
|
|
27819
|
+
const installerPath = join17(temporaryDirectory, "install.sh");
|
|
27323
27820
|
try {
|
|
27324
27821
|
await options.report("downloading");
|
|
27325
27822
|
const download = await downloadVerifiedFile({
|
|
@@ -27356,7 +27853,7 @@ var ClaudeCodeInstallRecipe = class extends FixedAgentInstallRecipe {
|
|
|
27356
27853
|
timeoutMilliseconds: AGENT_INSTALL_TIMEOUT_MILLISECONDS
|
|
27357
27854
|
});
|
|
27358
27855
|
return await this.requireInstalledExecutable(
|
|
27359
|
-
|
|
27856
|
+
join17(managedHome, ".local", "bin", "claude")
|
|
27360
27857
|
);
|
|
27361
27858
|
} catch (error61) {
|
|
27362
27859
|
if (options.signal.aborted) {
|
|
@@ -27390,7 +27887,7 @@ var PiInstallRecipe = class extends FixedAgentInstallRecipe {
|
|
|
27390
27887
|
await options.report("verifying");
|
|
27391
27888
|
await options.report("installing_agent");
|
|
27392
27889
|
const executable = await this.#npmInstaller.install(
|
|
27393
|
-
|
|
27890
|
+
join17(
|
|
27394
27891
|
options.stateDirectory,
|
|
27395
27892
|
"agents",
|
|
27396
27893
|
this.id,
|
|
@@ -27457,18 +27954,18 @@ var DeepSeekHarnessInstallRecipe = class extends FixedAgentInstallRecipe {
|
|
|
27457
27954
|
install = async (options) => {
|
|
27458
27955
|
this.assertSupportedPlatform();
|
|
27459
27956
|
try {
|
|
27460
|
-
const managedHome =
|
|
27957
|
+
const managedHome = join17(
|
|
27461
27958
|
options.stateDirectory,
|
|
27462
27959
|
"agents",
|
|
27463
27960
|
this.id,
|
|
27464
27961
|
"home"
|
|
27465
27962
|
);
|
|
27466
|
-
await
|
|
27963
|
+
await mkdir5(managedHome, { mode: 448, recursive: true });
|
|
27467
27964
|
await options.report("downloading");
|
|
27468
27965
|
await options.report("verifying");
|
|
27469
27966
|
await options.report("installing_agent");
|
|
27470
27967
|
const executable = await this.#npmInstaller.install(
|
|
27471
|
-
|
|
27968
|
+
join17(
|
|
27472
27969
|
options.stateDirectory,
|
|
27473
27970
|
"agents",
|
|
27474
27971
|
this.id,
|
|
@@ -27540,7 +28037,7 @@ var OpenCodeInstallRecipe = class extends FixedAgentInstallRecipe {
|
|
|
27540
28037
|
await options.report("verifying");
|
|
27541
28038
|
await options.report("installing_agent");
|
|
27542
28039
|
const executable = await this.#archiveInstaller.install(
|
|
27543
|
-
|
|
28040
|
+
join17(
|
|
27544
28041
|
options.stateDirectory,
|
|
27545
28042
|
"agents",
|
|
27546
28043
|
this.id,
|
|
@@ -27599,7 +28096,9 @@ function fixedAgentInstallRecipes() {
|
|
|
27599
28096
|
new ClaudeCodeInstallRecipe(),
|
|
27600
28097
|
new PiInstallRecipe(),
|
|
27601
28098
|
new DeepSeekHarnessInstallRecipe(),
|
|
27602
|
-
new OpenCodeInstallRecipe()
|
|
28099
|
+
new OpenCodeInstallRecipe(),
|
|
28100
|
+
new GrokBuildInstallRecipe(),
|
|
28101
|
+
new WorkBuddyInstallRecipe()
|
|
27603
28102
|
]);
|
|
27604
28103
|
}
|
|
27605
28104
|
|
|
@@ -27840,51 +28339,16 @@ var FixedInstallationExecutor = class {
|
|
|
27840
28339
|
};
|
|
27841
28340
|
};
|
|
27842
28341
|
|
|
27843
|
-
// src/agent-installation/local-installation-authorizer.ts
|
|
27844
|
-
import { createInterface } from "node:readline/promises";
|
|
27845
|
-
var ConsoleInstallationAuthorizer = class {
|
|
27846
|
-
#stateDirectory;
|
|
27847
|
-
constructor(stateDirectory) {
|
|
27848
|
-
this.#stateDirectory = stateDirectory;
|
|
27849
|
-
}
|
|
27850
|
-
authorize = async (agentId, label, requestId, signal) => {
|
|
27851
|
-
signal.throwIfAborted();
|
|
27852
|
-
const grants = await readGrantedAgents(this.#stateDirectory);
|
|
27853
|
-
signal.throwIfAborted();
|
|
27854
|
-
if (grants.has(agentId)) {
|
|
27855
|
-
return true;
|
|
27856
|
-
}
|
|
27857
|
-
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
27858
|
-
return false;
|
|
27859
|
-
}
|
|
27860
|
-
const prompt = createInterface({
|
|
27861
|
-
input: process.stdin,
|
|
27862
|
-
output: process.stdout
|
|
27863
|
-
});
|
|
27864
|
-
try {
|
|
27865
|
-
const answer = await prompt.question(
|
|
27866
|
-
`
|
|
27867
|
-
Mobius Web requested installation of ${label} (${requestId}). Allow this fixed user-level recipe? [y/N] `,
|
|
27868
|
-
{ signal }
|
|
27869
|
-
);
|
|
27870
|
-
const normalized = answer.trim().toLowerCase();
|
|
27871
|
-
return normalized === "y" || normalized === "yes";
|
|
27872
|
-
} finally {
|
|
27873
|
-
prompt.close();
|
|
27874
|
-
}
|
|
27875
|
-
};
|
|
27876
|
-
};
|
|
27877
|
-
|
|
27878
28342
|
// src/authorization/workspace-directory.ts
|
|
27879
|
-
import { readdir, realpath as
|
|
28343
|
+
import { readdir, realpath as realpath8, stat as stat7 } from "node:fs/promises";
|
|
27880
28344
|
import { homedir as homedir2 } from "node:os";
|
|
27881
28345
|
import {
|
|
27882
28346
|
basename as basename2,
|
|
27883
|
-
dirname as
|
|
27884
|
-
isAbsolute as
|
|
27885
|
-
join as
|
|
28347
|
+
dirname as dirname6,
|
|
28348
|
+
isAbsolute as isAbsolute7,
|
|
28349
|
+
join as join18,
|
|
27886
28350
|
normalize as normalize2,
|
|
27887
|
-
relative as
|
|
28351
|
+
relative as relative5
|
|
27888
28352
|
} from "node:path";
|
|
27889
28353
|
var WorkspaceDirectoryListing = class {
|
|
27890
28354
|
directoryId;
|
|
@@ -27934,20 +28398,20 @@ var WorkspaceDirectoryService = class {
|
|
|
27934
28398
|
if (id === "home") return homedir2();
|
|
27935
28399
|
if (id.startsWith("path-")) {
|
|
27936
28400
|
const path2 = decodePath(id, "path-");
|
|
27937
|
-
if (
|
|
28401
|
+
if (isAbsolute7(path2)) return path2;
|
|
27938
28402
|
}
|
|
27939
28403
|
throw new LocalAuthorizationError("The directory identifier is invalid");
|
|
27940
28404
|
};
|
|
27941
28405
|
resolvePath = async (requested, signal) => {
|
|
27942
28406
|
signal.throwIfAborted();
|
|
27943
|
-
if (!
|
|
28407
|
+
if (!isAbsolute7(requested) || requested.includes("\0") || normalize2(requested) !== requested)
|
|
27944
28408
|
throw new LocalAuthorizationError("The local directory path is invalid");
|
|
27945
28409
|
try {
|
|
27946
|
-
const target = await
|
|
28410
|
+
const target = await realpath8(requested);
|
|
27947
28411
|
signal.throwIfAborted();
|
|
27948
|
-
const metadata = await
|
|
28412
|
+
const metadata = await stat7(target);
|
|
27949
28413
|
signal.throwIfAborted();
|
|
27950
|
-
if (!
|
|
28414
|
+
if (!isAbsolute7(target) || normalize2(target) !== target || !metadata.isDirectory())
|
|
27951
28415
|
throw new LocalAuthorizationError(
|
|
27952
28416
|
"The selected location is not a directory"
|
|
27953
28417
|
);
|
|
@@ -27962,8 +28426,8 @@ var WorkspaceDirectoryService = class {
|
|
|
27962
28426
|
}
|
|
27963
28427
|
};
|
|
27964
28428
|
label = (path2) => {
|
|
27965
|
-
const suffix =
|
|
27966
|
-
return suffix === "" ? "~" : !
|
|
28429
|
+
const suffix = relative5(homedir2(), path2);
|
|
28430
|
+
return suffix === "" ? "~" : !isAbsolute7(suffix) && suffix !== ".." && !suffix.startsWith(`..${process.platform === "win32" ? "\\" : "/"}`) ? `~/${suffix.replaceAll("\\", "/")}` : path2;
|
|
27967
28431
|
};
|
|
27968
28432
|
identify = async (bindingId, requestedPath, signal) => {
|
|
27969
28433
|
this.authorizeMachine(bindingId);
|
|
@@ -27991,7 +28455,7 @@ var WorkspaceDirectoryService = class {
|
|
|
27991
28455
|
continue;
|
|
27992
28456
|
}
|
|
27993
28457
|
try {
|
|
27994
|
-
const path2 = await this.resolvePath(
|
|
28458
|
+
const path2 = await this.resolvePath(join18(target, child.name), signal);
|
|
27995
28459
|
entries.push({ directoryId: encodePath(path2), name: child.name });
|
|
27996
28460
|
} catch (cause) {
|
|
27997
28461
|
signal.throwIfAborted();
|
|
@@ -27999,7 +28463,7 @@ var WorkspaceDirectoryService = class {
|
|
|
27999
28463
|
}
|
|
28000
28464
|
}
|
|
28001
28465
|
entries.sort((a, b) => a.name.localeCompare(b.name));
|
|
28002
|
-
const parent =
|
|
28466
|
+
const parent = dirname6(target);
|
|
28003
28467
|
return new WorkspaceDirectoryListing(
|
|
28004
28468
|
id,
|
|
28005
28469
|
this.label(target),
|
|
@@ -28792,7 +29256,7 @@ var RelayConnectionLiveness = class {
|
|
|
28792
29256
|
|
|
28793
29257
|
// src/relay-connection/session-event-outbox.ts
|
|
28794
29258
|
import { mkdirSync as mkdirSync3 } from "node:fs";
|
|
28795
|
-
import { dirname as
|
|
29259
|
+
import { dirname as dirname7 } from "node:path";
|
|
28796
29260
|
import { DatabaseSync as DatabaseSync3 } from "node:sqlite";
|
|
28797
29261
|
function readPendingEnvelope(row) {
|
|
28798
29262
|
if (typeof row !== "object" || row === null || Array.isArray(row)) {
|
|
@@ -28807,7 +29271,7 @@ function readPendingEnvelope(row) {
|
|
|
28807
29271
|
var SessionEventOutbox = class {
|
|
28808
29272
|
#database;
|
|
28809
29273
|
constructor(path2) {
|
|
28810
|
-
mkdirSync3(
|
|
29274
|
+
mkdirSync3(dirname7(path2), { recursive: true });
|
|
28811
29275
|
this.#database = new DatabaseSync3(path2);
|
|
28812
29276
|
this.#database.exec(`
|
|
28813
29277
|
CREATE TABLE IF NOT EXISTS relay_session_event_outbox (
|
|
@@ -29099,17 +29563,6 @@ var DaemonInstallationObserver = class {
|
|
|
29099
29563
|
if (state instanceof RequestedInstallation) {
|
|
29100
29564
|
return Promise.resolve();
|
|
29101
29565
|
}
|
|
29102
|
-
if (state instanceof AwaitingLocalApproval) {
|
|
29103
|
-
this.#send(
|
|
29104
|
-
socket,
|
|
29105
|
-
encodeAgentInstallAwaitingApprovalEvent({
|
|
29106
|
-
agentId: state.agentId,
|
|
29107
|
-
kind: AGENT_INSTALL_AWAITING_APPROVAL_KIND,
|
|
29108
|
-
requestId: state.requestId
|
|
29109
|
-
})
|
|
29110
|
-
);
|
|
29111
|
-
return Promise.resolve();
|
|
29112
|
-
}
|
|
29113
29566
|
if (state instanceof RunningInstallation) {
|
|
29114
29567
|
if (!this.#started.has(state.requestId)) {
|
|
29115
29568
|
this.#started.add(state.requestId);
|
|
@@ -30006,7 +30459,6 @@ async function runDaemon(config2, audit, signal, timer = systemDaemonTimer) {
|
|
|
30006
30459
|
);
|
|
30007
30460
|
const installations = new AgentInstallationManager(
|
|
30008
30461
|
specifications,
|
|
30009
|
-
new ConsoleInstallationAuthorizer(stateDirectory),
|
|
30010
30462
|
installationExecutor,
|
|
30011
30463
|
installationObserver,
|
|
30012
30464
|
installationAudit
|