openfox 2.0.74 → 2.0.76
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/README.md +5 -2
- package/dist/{chat-handler-ETKFIHUO.js → chat-handler-3BZ4PDL2.js} +17 -16
- package/dist/chunk-46RORSKU.js +495 -0
- package/dist/{chunk-S7O77CVO.js → chunk-4QHDQP2N.js} +2 -2
- package/dist/{chunk-YD6NDTKF.js → chunk-5GOOSZX7.js} +1 -1
- package/dist/{chunk-XWBNYU2L.js → chunk-7772ENZN.js} +4 -3
- package/dist/{chunk-I4RWK2L2.js → chunk-7QXRQ5ZL.js} +3 -3
- package/dist/{chunk-2VBETAU2.js → chunk-D6CI2B7B.js} +111 -539
- package/dist/{chunk-E5LLEO3C.js → chunk-DH3SSBZN.js} +2 -2
- package/dist/{chunk-CHPRGEY5.js → chunk-HAQV6AJP.js} +3 -3
- package/dist/{chunk-R6L2QXQ5.js → chunk-HHUIXHHX.js} +16 -6
- package/dist/{chunk-ZRQDCQ7R.js → chunk-HLHGNHMV.js} +10 -8
- package/dist/{chunk-QFR6JF32.js → chunk-J7VCI5EX.js} +205 -82
- package/dist/chunk-KQEVAO2Q.js +7 -0
- package/dist/{chunk-UN26GIQG.js → chunk-KVRSAC4Z.js} +1 -1
- package/dist/{chunk-UV3EMWL4.js → chunk-LXFLRM7M.js} +2 -2
- package/dist/{chunk-6XKM25OT.js → chunk-NGJ5XJ7D.js} +4 -4
- package/dist/{chunk-NOU2QIL5.js → chunk-O3NUNU4H.js} +5 -2
- package/dist/{chunk-PYB2UEC3.js → chunk-OBQPXUXI.js} +4 -4
- package/dist/{chunk-OHGQILRF.js → chunk-OCVRIPQP.js} +2 -2
- package/dist/{chunk-TMRFTWXP.js → chunk-OMWVB2XC.js} +38 -23
- package/dist/{chunk-6XOA2WPU.js → chunk-W4ZEG3LX.js} +5 -2
- package/dist/{chunk-2DCJERYX.js → chunk-XTK6E2QR.js} +4 -4
- package/dist/{chunk-QNKXZH3Z.js → chunk-YMFCFMMB.js} +2 -2
- package/dist/cli/dev.js +1 -1
- package/dist/cli/index.js +1 -1
- package/dist/{client-SC6X65GY.js → client-TDPQVBQ7.js} +2 -2
- package/dist/{compactor-4UKYWC5F.js → compactor-BB3YYVRP.js} +7 -7
- package/dist/{events-AEQ6GQXI.js → events-FLWRLM6V.js} +3 -3
- package/dist/{inspect-proxy-PHVZBZUO.js → inspect-proxy-JHZV34QR.js} +4 -4
- package/dist/install-CPOPMCSE.js +120 -0
- package/dist/{manager-24C2AXVF.js → manager-OPMCSYN2.js} +5 -5
- package/dist/{orchestrator-O2YAAZ3U.js → orchestrator-5IMCWX5P.js} +16 -15
- package/dist/package.json +1 -1
- package/dist/path-security-ZROWNL22.js +50 -0
- package/dist/{platform-XQ7BS3KQ.js → platform-QGXO3CNR.js} +4 -4
- package/dist/plugins-registry.json +6 -0
- package/dist/{processor-FKAS3K4L.js → processor-3R4GS6VB.js} +17 -16
- package/dist/{project-creator-FQRBN3RG.js → project-creator-C22J43BC.js} +3 -3
- package/dist/{projects-LHRNCUGW.js → projects-WSVINK2C.js} +3 -3
- package/dist/{protocol-4QFU7WAI.js → protocol-EWEVW65B.js} +3 -3
- package/dist/{protocol-DGQWVFcP.d.ts → protocol-Sr6Jr4ZS.d.ts} +5 -2
- package/dist/{provider-OJUCZ5RN.js → provider-G2YC2IC4.js} +3 -3
- package/dist/{provider-manager-MAKXSL6L.js → provider-manager-SQIELYLK.js} +3 -3
- package/dist/{serve-T5U6SLB7.js → serve-MXKMKZYY.js} +22 -21
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.js +21 -20
- package/dist/{server-T2YP3VT2.js → server-SPYFMFQE.js} +18 -17
- package/dist/{settings-PFXRYXZU.js → settings-7XDMSPIC.js} +3 -3
- package/dist/shared/index.d.ts +1 -1
- package/dist/shared/index.js +1 -1
- package/dist/{tools-APW7MY4E.js → tools-JRCUWPJO.js} +20 -18
- package/dist/{update-FWO365SV.js → update-OXDQ75M7.js} +12 -3
- package/dist/{update-server-MYYQUNZX.js → update-server-4MTM7M5P.js} +2 -2
- package/dist/web/assets/{index-DZRcUhoE.css → index-BNVBxKnB.css} +1 -1
- package/dist/web/assets/{index-Xh2VHbZe.js → index-ghDkIdlf.js} +74 -74
- package/dist/web/index.html +2 -2
- package/dist/web/sw.js +1 -1
- package/package.json +1 -1
- package/plugins-registry.json +6 -0
- package/dist/chunk-3OZBPWHP.js +0 -7
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createMcpTools
|
|
3
|
+
} from "./chunk-NWO6GRYE.js";
|
|
4
|
+
import {
|
|
5
|
+
applyMcpServerUpdate
|
|
6
|
+
} from "./chunk-KVRSAC4Z.js";
|
|
1
7
|
import {
|
|
2
8
|
getGitBranch,
|
|
3
9
|
listWorkspaces
|
|
@@ -18,13 +24,13 @@ import {
|
|
|
18
24
|
createToolCallEvent,
|
|
19
25
|
createToolResultEvent,
|
|
20
26
|
streamLLMPure
|
|
21
|
-
} from "./chunk-
|
|
27
|
+
} from "./chunk-7772ENZN.js";
|
|
22
28
|
import {
|
|
23
29
|
startInspectProxy
|
|
24
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-DH3SSBZN.js";
|
|
25
31
|
import {
|
|
26
32
|
getProject
|
|
27
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-LXFLRM7M.js";
|
|
28
34
|
import {
|
|
29
35
|
checkAborted,
|
|
30
36
|
createProcess,
|
|
@@ -35,24 +41,30 @@ import {
|
|
|
35
41
|
spawnShellProcess,
|
|
36
42
|
startProcessCommand,
|
|
37
43
|
stopProcess
|
|
38
|
-
} from "./chunk-
|
|
44
|
+
} from "./chunk-OBQPXUXI.js";
|
|
45
|
+
import {
|
|
46
|
+
SETTINGS_KEYS,
|
|
47
|
+
deleteSetting,
|
|
48
|
+
getSetting,
|
|
49
|
+
setSetting
|
|
50
|
+
} from "./chunk-YMFCFMMB.js";
|
|
39
51
|
import {
|
|
40
52
|
getMaxPerSession,
|
|
41
53
|
getSessionProcessCount,
|
|
42
54
|
terminateProcessTree
|
|
43
55
|
} from "./chunk-I72ACQ6R.js";
|
|
44
56
|
import {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
} from "./chunk-
|
|
57
|
+
PathAccessDeniedError,
|
|
58
|
+
extractAbsolutePathsFromCommand,
|
|
59
|
+
extractSensitivePathsFromCommand,
|
|
60
|
+
requestPathAccess
|
|
61
|
+
} from "./chunk-46RORSKU.js";
|
|
50
62
|
import {
|
|
51
63
|
getCurrentContextWindowId,
|
|
52
64
|
getCurrentWindowMessageOptions,
|
|
53
65
|
getEventStore,
|
|
54
66
|
getRuntimeConfig
|
|
55
|
-
} from "./chunk-
|
|
67
|
+
} from "./chunk-NGJ5XJ7D.js";
|
|
56
68
|
import {
|
|
57
69
|
buildContextMessagesFromEventHistory,
|
|
58
70
|
foldContextState,
|
|
@@ -67,15 +79,8 @@ import {
|
|
|
67
79
|
createChatDoneMessage,
|
|
68
80
|
createChatMessageMessage,
|
|
69
81
|
createChatMessageUpdatedMessage,
|
|
70
|
-
createChatPathConfirmationMessage,
|
|
71
82
|
createQueueStateMessage
|
|
72
|
-
} from "./chunk-
|
|
73
|
-
import {
|
|
74
|
-
SETTINGS_KEYS,
|
|
75
|
-
deleteSetting,
|
|
76
|
-
getSetting,
|
|
77
|
-
setSetting
|
|
78
|
-
} from "./chunk-QNKXZH3Z.js";
|
|
83
|
+
} from "./chunk-O3NUNU4H.js";
|
|
79
84
|
import {
|
|
80
85
|
modelSupportsVision
|
|
81
86
|
} from "./chunk-V4IE7HJY.js";
|
|
@@ -99,430 +104,10 @@ import {
|
|
|
99
104
|
|
|
100
105
|
// src/server/tools/read.ts
|
|
101
106
|
import { readFile as readFile2, stat, readdir } from "fs/promises";
|
|
102
|
-
import { extname, join
|
|
103
|
-
|
|
104
|
-
// src/server/tools/tool-helpers.ts
|
|
105
|
-
import { resolve as resolve2, isAbsolute } from "path";
|
|
106
|
-
|
|
107
|
-
// src/server/tools/path-security.ts
|
|
108
|
-
import { realpath } from "fs/promises";
|
|
109
|
-
import { resolve, normalize, join, basename, sep, posix, win32 } from "path";
|
|
110
|
-
import { homedir, tmpdir } from "os";
|
|
111
|
-
var SAFE_PATHS = /* @__PURE__ */ new Set([
|
|
112
|
-
"/dev/null",
|
|
113
|
-
"/dev/zero",
|
|
114
|
-
"/dev/random",
|
|
115
|
-
"/dev/urandom",
|
|
116
|
-
"/dev/stdin",
|
|
117
|
-
"/dev/stdout",
|
|
118
|
-
"/dev/stderr",
|
|
119
|
-
"/dev/fd/0",
|
|
120
|
-
"/dev/fd/1",
|
|
121
|
-
"/dev/fd/2"
|
|
122
|
-
]);
|
|
123
|
-
var ALLOWED_ROOTS = ["/tmp", "/var/tmp", tmpdir()];
|
|
124
|
-
var SENSITIVE_FILE_PATTERNS = [
|
|
125
|
-
// Dotenv files (but not .envrc, .env-example, .env.example)
|
|
126
|
-
/^\.env$/,
|
|
127
|
-
// .env
|
|
128
|
-
/^\.env\.(?!example)[a-zA-Z0-9_.-]+$/,
|
|
129
|
-
// .env.local, .env.production (not .env.example)
|
|
130
|
-
// Credential files
|
|
131
|
-
/^credentials\.json$/i,
|
|
132
|
-
/^secrets?\.(?:json|ya?ml|toml)$/i,
|
|
133
|
-
// Private keys
|
|
134
|
-
/\.pem$/i,
|
|
135
|
-
/\.key$/i,
|
|
136
|
-
/^id_rsa/,
|
|
137
|
-
/^id_ed25519/,
|
|
138
|
-
/^id_ecdsa/,
|
|
139
|
-
/^id_dsa/,
|
|
140
|
-
// Auth configs
|
|
141
|
-
/^\.netrc$/
|
|
142
|
-
];
|
|
143
|
-
function isSensitivePath(path) {
|
|
144
|
-
const fileName = basename(path);
|
|
145
|
-
if (!fileName) return false;
|
|
146
|
-
return SENSITIVE_FILE_PATTERNS.some((pattern) => pattern.test(fileName));
|
|
147
|
-
}
|
|
148
|
-
var sessionAllowedPaths = /* @__PURE__ */ new Map();
|
|
149
|
-
function addAllowedPath(sessionId, path) {
|
|
150
|
-
if (!sessionAllowedPaths.has(sessionId)) {
|
|
151
|
-
sessionAllowedPaths.set(sessionId, /* @__PURE__ */ new Set());
|
|
152
|
-
}
|
|
153
|
-
sessionAllowedPaths.get(sessionId).add(normalize(path));
|
|
154
|
-
}
|
|
155
|
-
function addAllowedPaths(sessionId, paths) {
|
|
156
|
-
for (const path of paths) {
|
|
157
|
-
addAllowedPath(sessionId, path);
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
function isPathAllowed(sessionId, path) {
|
|
161
|
-
const allowed = sessionAllowedPaths.get(sessionId);
|
|
162
|
-
if (!allowed) return false;
|
|
163
|
-
return allowed.has(normalize(path));
|
|
164
|
-
}
|
|
165
|
-
async function safeRealpath(path) {
|
|
166
|
-
const absolutePath = normalize(resolve(path));
|
|
167
|
-
try {
|
|
168
|
-
return await realpath(absolutePath);
|
|
169
|
-
} catch {
|
|
170
|
-
const missingSegments = [];
|
|
171
|
-
let current = absolutePath;
|
|
172
|
-
while (true) {
|
|
173
|
-
try {
|
|
174
|
-
const canonicalParent = await realpath(current);
|
|
175
|
-
return normalize(join(canonicalParent, ...missingSegments.reverse()));
|
|
176
|
-
} catch {
|
|
177
|
-
const parent = resolve(current, "..");
|
|
178
|
-
if (parent === current) return absolutePath;
|
|
179
|
-
missingSegments.push(basename(current));
|
|
180
|
-
current = parent;
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
async function isPathWithinSandbox(path, workdir, sessionId) {
|
|
186
|
-
const normalizedWorkdir = normalize((await safeRealpath(workdir)).replace(/\/+$/, ""));
|
|
187
|
-
let resolvedPath;
|
|
188
|
-
try {
|
|
189
|
-
resolvedPath = normalize(await realpath(path));
|
|
190
|
-
} catch {
|
|
191
|
-
try {
|
|
192
|
-
const { readlink } = await import("fs/promises");
|
|
193
|
-
const linkTarget = await readlink(path);
|
|
194
|
-
const linkDir = resolve(path, "..");
|
|
195
|
-
resolvedPath = await safeRealpath(resolve(linkDir, linkTarget));
|
|
196
|
-
} catch {
|
|
197
|
-
resolvedPath = await safeRealpath(path);
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
resolvedPath = resolvedPath.replace(/\/+$/, "");
|
|
201
|
-
if (resolvedPath === normalizedWorkdir || resolvedPath.startsWith(normalizedWorkdir + sep)) {
|
|
202
|
-
return { allowed: true, resolvedPath };
|
|
203
|
-
}
|
|
204
|
-
for (const root of ALLOWED_ROOTS) {
|
|
205
|
-
const normalizedRoot = normalize((await safeRealpath(root)).replace(/\/+$/, ""));
|
|
206
|
-
if (resolvedPath === normalizedRoot || resolvedPath.startsWith(normalizedRoot + sep)) {
|
|
207
|
-
return { allowed: true, resolvedPath };
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
if (sessionId && (isPathAllowed(sessionId, path) || isPathAllowed(sessionId, resolvedPath))) {
|
|
211
|
-
return { allowed: true, resolvedPath };
|
|
212
|
-
}
|
|
213
|
-
return { allowed: false, resolvedPath };
|
|
214
|
-
}
|
|
215
|
-
function looksLikeRegex(str) {
|
|
216
|
-
return /[*?+[\]\\]/.test(str);
|
|
217
|
-
}
|
|
218
|
-
var isWindows = () => process.platform === "win32";
|
|
219
|
-
function isWindowsAbsolutePath(str) {
|
|
220
|
-
return /^[A-Za-z]:[\\/]/.test(str);
|
|
221
|
-
}
|
|
222
|
-
function normalizeExtracted(path) {
|
|
223
|
-
return isWindowsAbsolutePath(path) ? win32.normalize(path) : posix.normalize(path);
|
|
224
|
-
}
|
|
225
|
-
function isPlaceholderToken(str) {
|
|
226
|
-
return str.includes("__URL__") || str.includes("__FILEURL__") || str.includes("__SED__") || str.includes("__COMMIT_MSG__");
|
|
227
|
-
}
|
|
228
|
-
function extractAbsolutePathsFromCommand(command) {
|
|
229
|
-
if (!command.trim()) {
|
|
230
|
-
return [];
|
|
231
|
-
}
|
|
232
|
-
const paths = [];
|
|
233
|
-
const home = homedir();
|
|
234
|
-
let sanitized = command.replace(/https?:\/\/[^\s'"]+/g, " __URL__ ").replace(/ftp:\/\/[^\s'"]+/g, " __URL__ ");
|
|
235
|
-
sanitized = sanitized.replace(/(?<!\w)s\/[^/]*\/[^/]*\/[gip]*/g, " __SED__ ");
|
|
236
|
-
sanitized = sanitized.replace(/(?<!\w)s\|[^|]*\|[^|]*\|[gip]*/g, " __SED__ ");
|
|
237
|
-
sanitized = sanitized.replace(/(?<!\w)s:[^:]*:[^:]*:[gip]*/g, " __SED__ ");
|
|
238
|
-
sanitized = sanitized.replace(
|
|
239
|
-
/git\s+commit\b.*?(?:-(?:[a-zA-Z]*m)(?=\s)|--message)\s+(["'])(?:(?!\1).)*\1/g,
|
|
240
|
-
(match2) => match2.replace(/\/[^\s"'|&;<>`()]+/g, " __COMMIT_MSG__ ")
|
|
241
|
-
);
|
|
242
|
-
const fileUrlMatches = command.matchAll(/file:\/\/([^\s'"]+)/g);
|
|
243
|
-
for (const match2 of fileUrlMatches) {
|
|
244
|
-
const filePath = match2[1];
|
|
245
|
-
if (filePath && !isSafePath(filePath)) {
|
|
246
|
-
paths.push(normalizeExtracted(filePath));
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
sanitized = sanitized.replace(/file:\/\/[^\s'"]+/g, " __FILEURL__ ");
|
|
250
|
-
const tildePattern = /(?:^|[\s='"(])~(\/[^\s'"()]*)?(?=[\s'"()]|$)/g;
|
|
251
|
-
let match;
|
|
252
|
-
while ((match = tildePattern.exec(sanitized)) !== null) {
|
|
253
|
-
const pathPart = match[1] ?? "";
|
|
254
|
-
const fullPath = home + pathPart;
|
|
255
|
-
const resolved = normalize(resolve(fullPath));
|
|
256
|
-
if (!isSafePath(resolved)) {
|
|
257
|
-
paths.push(resolved);
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
const quotedPattern = /["']([^"']+)["']/g;
|
|
261
|
-
while ((match = quotedPattern.exec(sanitized)) !== null) {
|
|
262
|
-
const content = match[1];
|
|
263
|
-
if (content.startsWith("/") && content.endsWith("/")) {
|
|
264
|
-
continue;
|
|
265
|
-
}
|
|
266
|
-
if (content.startsWith("/") && looksLikeRegex(content)) {
|
|
267
|
-
continue;
|
|
268
|
-
}
|
|
269
|
-
if (isWindowsAbsolutePath(content)) {
|
|
270
|
-
const resolved = normalizeExtracted(content);
|
|
271
|
-
if (!isSafePath(resolved)) {
|
|
272
|
-
paths.push(resolved);
|
|
273
|
-
}
|
|
274
|
-
} else if (!isWindows() && content.startsWith("/")) {
|
|
275
|
-
const resolved = normalizeExtracted(content);
|
|
276
|
-
if (!isSafePath(resolved)) {
|
|
277
|
-
paths.push(resolved);
|
|
278
|
-
}
|
|
279
|
-
} else if (content.startsWith("~")) {
|
|
280
|
-
const pathPart = content.slice(1);
|
|
281
|
-
const fullPath = join(home, pathPart);
|
|
282
|
-
const resolved = normalize(resolve(fullPath));
|
|
283
|
-
if (!isSafePath(resolved)) {
|
|
284
|
-
paths.push(resolved);
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
if (isWindows()) {
|
|
289
|
-
const winAbsolutePattern = /(?:^|[\s=(])([A-Za-z]:[\\/][^\s"'|&;<>`()]+)/g;
|
|
290
|
-
while ((match = winAbsolutePattern.exec(sanitized)) !== null) {
|
|
291
|
-
const candidate = match[1];
|
|
292
|
-
if (isPlaceholderToken(candidate)) continue;
|
|
293
|
-
const resolved = normalizeExtracted(candidate);
|
|
294
|
-
if (!isSafePath(resolved)) {
|
|
295
|
-
paths.push(resolved);
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
} else {
|
|
299
|
-
const absolutePattern = /(?:^|[\s=(])(\/[^\s"'|&;<>`()]+)/g;
|
|
300
|
-
while ((match = absolutePattern.exec(sanitized)) !== null) {
|
|
301
|
-
const candidate = match[1];
|
|
302
|
-
if (isPlaceholderToken(candidate)) continue;
|
|
303
|
-
if (looksLikeRegex(candidate)) continue;
|
|
304
|
-
const resolved = normalizeExtracted(candidate);
|
|
305
|
-
if (resolved === "/" || resolved === "") continue;
|
|
306
|
-
if (!isSafePath(resolved)) {
|
|
307
|
-
paths.push(resolved);
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
return [...new Set(paths)];
|
|
312
|
-
}
|
|
313
|
-
function extractSensitivePathsFromCommand(command) {
|
|
314
|
-
if (!command.trim()) {
|
|
315
|
-
return [];
|
|
316
|
-
}
|
|
317
|
-
const paths = [];
|
|
318
|
-
const quotedPattern = /["']([^"']+)["']/g;
|
|
319
|
-
let match;
|
|
320
|
-
while ((match = quotedPattern.exec(command)) !== null) {
|
|
321
|
-
const content = match[1];
|
|
322
|
-
if (isSensitivePath(content)) {
|
|
323
|
-
paths.push(content);
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
const unquoted = command.replace(/["'][^"']*["']/g, " ").replace(/[|&;><]/g, " ");
|
|
327
|
-
const tokens = unquoted.split(/\s+/).filter(Boolean);
|
|
328
|
-
for (const token of tokens) {
|
|
329
|
-
if (token.startsWith("-")) continue;
|
|
330
|
-
if (token.includes("://")) continue;
|
|
331
|
-
if (isSensitivePath(token)) {
|
|
332
|
-
paths.push(token);
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
return [...new Set(paths)];
|
|
336
|
-
}
|
|
337
|
-
function isSafePath(path) {
|
|
338
|
-
const normalized = posix.normalize(path);
|
|
339
|
-
return SAFE_PATHS.has(normalized);
|
|
340
|
-
}
|
|
341
|
-
async function checkPathsAccess(paths, workdir, sessionId) {
|
|
342
|
-
if (paths.length === 0) {
|
|
343
|
-
return { needsConfirmation: false, deniedPaths: [], sensitivePaths: [] };
|
|
344
|
-
}
|
|
345
|
-
const deniedPaths = [];
|
|
346
|
-
const sensitivePaths = [];
|
|
347
|
-
for (const path of paths) {
|
|
348
|
-
const result = await isPathWithinSandbox(path, workdir, sessionId);
|
|
349
|
-
if (!result.allowed) {
|
|
350
|
-
deniedPaths.push(result.resolvedPath);
|
|
351
|
-
}
|
|
352
|
-
if (isSensitivePath(path) && !isPathAllowed(sessionId ?? "", path)) {
|
|
353
|
-
sensitivePaths.push(result.resolvedPath);
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
const uniqueDenied = [...new Set(deniedPaths)];
|
|
357
|
-
const uniqueSensitive = [...new Set(sensitivePaths)];
|
|
358
|
-
return {
|
|
359
|
-
needsConfirmation: uniqueDenied.length > 0 || uniqueSensitive.length > 0,
|
|
360
|
-
deniedPaths: uniqueDenied,
|
|
361
|
-
sensitivePaths: uniqueSensitive
|
|
362
|
-
};
|
|
363
|
-
}
|
|
364
|
-
var DANGEROUS_PATTERNS = [
|
|
365
|
-
/sudo\s/,
|
|
366
|
-
/rm\s+(-rf?|--recursive)\s+[~]/,
|
|
367
|
-
/chmod\s+777/,
|
|
368
|
-
/>\s*\/dev\/sd/,
|
|
369
|
-
/mkfs\s/,
|
|
370
|
-
/dd\s+if=/,
|
|
371
|
-
/:\(\)\s*\{\s*:\s*\|\s*:\s*&\s*\}\s*;/
|
|
372
|
-
];
|
|
373
|
-
function extractDangerousPatterns(command) {
|
|
374
|
-
const dangerous = [];
|
|
375
|
-
for (const pattern of DANGEROUS_PATTERNS) {
|
|
376
|
-
if (pattern.test(command)) {
|
|
377
|
-
dangerous.push(pattern.source);
|
|
378
|
-
}
|
|
379
|
-
}
|
|
380
|
-
return dangerous;
|
|
381
|
-
}
|
|
382
|
-
function extractGitNoVerify(command) {
|
|
383
|
-
const subCommands = command.split(/\s*(?:&&|\|\||\||;)\s*/);
|
|
384
|
-
for (const sub of subCommands) {
|
|
385
|
-
const parts = sub.trim().split(/\s+/);
|
|
386
|
-
const gitIndex = parts.indexOf("git");
|
|
387
|
-
const subCmd = parts[gitIndex + 1];
|
|
388
|
-
if (gitIndex >= 0 && subCmd && !subCmd.startsWith("-")) {
|
|
389
|
-
const gitArgs = parts.slice(gitIndex + 2);
|
|
390
|
-
if (gitArgs.some((a) => a === "--no-verify" || a === "-n")) {
|
|
391
|
-
return true;
|
|
392
|
-
}
|
|
393
|
-
}
|
|
394
|
-
}
|
|
395
|
-
return false;
|
|
396
|
-
}
|
|
397
|
-
async function requestPathAccess(paths, workdir, sessionId, callId, tool, onEvent, dangerLevel, command, isSubAgent) {
|
|
398
|
-
if (isSubAgent) {
|
|
399
|
-
const result2 = await checkPathsAccess(paths, workdir, sessionId);
|
|
400
|
-
if (!result2.needsConfirmation) return;
|
|
401
|
-
if (dangerLevel === "dangerous") {
|
|
402
|
-
const allPaths2 = [.../* @__PURE__ */ new Set([...result2.deniedPaths, ...result2.sensitivePaths])];
|
|
403
|
-
addAllowedPaths(sessionId, allPaths2);
|
|
404
|
-
return;
|
|
405
|
-
}
|
|
406
|
-
const allPaths = [.../* @__PURE__ */ new Set([...result2.deniedPaths, ...result2.sensitivePaths])];
|
|
407
|
-
const hasDenied2 = result2.deniedPaths.length > 0;
|
|
408
|
-
const hasSensitive2 = result2.sensitivePaths.length > 0;
|
|
409
|
-
const reason2 = hasDenied2 && hasSensitive2 ? "both" : hasDenied2 ? "outside_workdir" : "sensitive_file";
|
|
410
|
-
throw new PathAccessDeniedError(allPaths, tool, reason2);
|
|
411
|
-
}
|
|
412
|
-
const emitPendingEvent = (confirmationPaths, confirmationReason) => {
|
|
413
|
-
try {
|
|
414
|
-
const eventStore = getEventStore();
|
|
415
|
-
eventStore.append(sessionId, {
|
|
416
|
-
type: "path.confirmation_pending",
|
|
417
|
-
data: { callId, tool, paths: confirmationPaths, workdir, reason: confirmationReason }
|
|
418
|
-
});
|
|
419
|
-
} catch {
|
|
420
|
-
}
|
|
421
|
-
};
|
|
422
|
-
if (command && extractGitNoVerify(command)) {
|
|
423
|
-
emitPendingEvent([workdir], "git_no_verify");
|
|
424
|
-
const confirmationPromise2 = registerPathConfirmation(callId, [workdir], sessionId);
|
|
425
|
-
onEvent(createChatPathConfirmationMessage(callId, tool, ["git --no-verify detected"], workdir, "git_no_verify"));
|
|
426
|
-
const approved2 = await confirmationPromise2;
|
|
427
|
-
if (!approved2) {
|
|
428
|
-
throw new PathAccessDeniedError(
|
|
429
|
-
["git --no-verify"],
|
|
430
|
-
tool,
|
|
431
|
-
"git_no_verify",
|
|
432
|
-
"User denied git command with --no-verify. The agent must not use --no-verify and must resolve the issue (e.g., fix lint errors, resolve conflicts) that prevents the commit."
|
|
433
|
-
);
|
|
434
|
-
}
|
|
435
|
-
}
|
|
436
|
-
if (dangerLevel !== "dangerous" && command) {
|
|
437
|
-
const dangerousPatterns = extractDangerousPatterns(command);
|
|
438
|
-
if (dangerousPatterns.length > 0) {
|
|
439
|
-
emitPendingEvent([workdir], "dangerous_command");
|
|
440
|
-
const confirmationPromise2 = registerPathConfirmation(callId, [workdir], sessionId);
|
|
441
|
-
onEvent(
|
|
442
|
-
createChatPathConfirmationMessage(callId, tool, [dangerousPatterns.join(", ")], workdir, "dangerous_command")
|
|
443
|
-
);
|
|
444
|
-
const approved2 = await confirmationPromise2;
|
|
445
|
-
if (!approved2) {
|
|
446
|
-
throw new PathAccessDeniedError(dangerousPatterns, tool, "dangerous_command");
|
|
447
|
-
}
|
|
448
|
-
}
|
|
449
|
-
}
|
|
450
|
-
const result = await checkPathsAccess(paths, workdir, sessionId);
|
|
451
|
-
if (!result.needsConfirmation) {
|
|
452
|
-
return;
|
|
453
|
-
}
|
|
454
|
-
if (dangerLevel === "dangerous") {
|
|
455
|
-
const allPaths = [.../* @__PURE__ */ new Set([...result.deniedPaths, ...result.sensitivePaths])];
|
|
456
|
-
addAllowedPaths(sessionId, allPaths);
|
|
457
|
-
return;
|
|
458
|
-
}
|
|
459
|
-
const allPathsNeedingConfirmation = [.../* @__PURE__ */ new Set([...result.deniedPaths, ...result.sensitivePaths])];
|
|
460
|
-
const hasDenied = result.deniedPaths.length > 0;
|
|
461
|
-
const hasSensitive = result.sensitivePaths.length > 0;
|
|
462
|
-
const reason = hasDenied && hasSensitive ? "both" : hasDenied ? "outside_workdir" : "sensitive_file";
|
|
463
|
-
emitPendingEvent(allPathsNeedingConfirmation, reason);
|
|
464
|
-
const confirmationPromise = registerPathConfirmation(callId, allPathsNeedingConfirmation, sessionId);
|
|
465
|
-
onEvent(createChatPathConfirmationMessage(callId, tool, allPathsNeedingConfirmation, workdir, reason));
|
|
466
|
-
const approved = await confirmationPromise;
|
|
467
|
-
if (!approved) {
|
|
468
|
-
throw new PathAccessDeniedError(allPathsNeedingConfirmation, tool, reason);
|
|
469
|
-
}
|
|
470
|
-
}
|
|
471
|
-
var PathAccessDeniedError = class extends Error {
|
|
472
|
-
constructor(paths, tool, reason = "outside_workdir", customMessage) {
|
|
473
|
-
const reasonText = reason === "sensitive_file" ? "sensitive files (may contain secrets)" : reason === "both" ? "paths outside workdir and sensitive files" : reason === "git_no_verify" ? "git commands with --no-verify" : "paths outside workdir";
|
|
474
|
-
super(customMessage ?? `User denied access to ${reasonText}: ${paths.join(", ")}`);
|
|
475
|
-
this.paths = paths;
|
|
476
|
-
this.tool = tool;
|
|
477
|
-
this.reason = reason;
|
|
478
|
-
this.customMessage = customMessage;
|
|
479
|
-
this.name = "PathAccessDeniedError";
|
|
480
|
-
}
|
|
481
|
-
};
|
|
482
|
-
var pendingConfirmations = /* @__PURE__ */ new Map();
|
|
483
|
-
function registerPathConfirmation(callId, paths, sessionId) {
|
|
484
|
-
return new Promise((resolve6, reject) => {
|
|
485
|
-
pendingConfirmations.set(callId, { resolve: resolve6, reject, paths, sessionId });
|
|
486
|
-
});
|
|
487
|
-
}
|
|
488
|
-
function providePathConfirmation(callId, approved, alwaysAllow) {
|
|
489
|
-
const pending = pendingConfirmations.get(callId);
|
|
490
|
-
if (!pending) {
|
|
491
|
-
return { found: false };
|
|
492
|
-
}
|
|
493
|
-
try {
|
|
494
|
-
const eventStore = getEventStore();
|
|
495
|
-
eventStore.append(pending.sessionId, {
|
|
496
|
-
type: "path.confirmation_responded",
|
|
497
|
-
data: { callId, approved, alwaysAllow: alwaysAllow ?? false }
|
|
498
|
-
});
|
|
499
|
-
} catch {
|
|
500
|
-
}
|
|
501
|
-
if (approved) {
|
|
502
|
-
if (alwaysAllow) {
|
|
503
|
-
addAllowedPaths(pending.sessionId, pending.paths);
|
|
504
|
-
} else {
|
|
505
|
-
addAllowedPaths(pending.sessionId, pending.paths);
|
|
506
|
-
}
|
|
507
|
-
}
|
|
508
|
-
pending.resolve(approved);
|
|
509
|
-
pendingConfirmations.delete(callId);
|
|
510
|
-
return { found: true, sessionId: pending.sessionId, approved };
|
|
511
|
-
}
|
|
512
|
-
function cancelPathConfirmationsForSession(sessionId, reason) {
|
|
513
|
-
let cancelledCount = 0;
|
|
514
|
-
for (const [callId, pending] of pendingConfirmations.entries()) {
|
|
515
|
-
if (pending.sessionId !== sessionId) {
|
|
516
|
-
continue;
|
|
517
|
-
}
|
|
518
|
-
pending.reject(new Error(reason));
|
|
519
|
-
pendingConfirmations.delete(callId);
|
|
520
|
-
cancelledCount += 1;
|
|
521
|
-
}
|
|
522
|
-
return cancelledCount;
|
|
523
|
-
}
|
|
107
|
+
import { extname, join } from "path";
|
|
524
108
|
|
|
525
109
|
// src/server/tools/tool-helpers.ts
|
|
110
|
+
import { resolve, isAbsolute } from "path";
|
|
526
111
|
function buildSignal(timeoutMs, contextSignal) {
|
|
527
112
|
const timeoutSignal = AbortSignal.timeout(timeoutMs);
|
|
528
113
|
if (contextSignal) {
|
|
@@ -570,7 +155,7 @@ function createTool(name, definition, handler2) {
|
|
|
570
155
|
async execute(args, context) {
|
|
571
156
|
const startTime = Date.now();
|
|
572
157
|
const helpers = {
|
|
573
|
-
resolvePath: (path) => isAbsolute(path) ? path :
|
|
158
|
+
resolvePath: (path) => isAbsolute(path) ? path : resolve(context.workdir, path),
|
|
574
159
|
checkPathAccess: async (paths, command) => {
|
|
575
160
|
if (context.onEvent) {
|
|
576
161
|
await requestPathAccess(
|
|
@@ -620,7 +205,7 @@ function createTool(name, definition, handler2) {
|
|
|
620
205
|
// src/server/tools/file-tracker.ts
|
|
621
206
|
import { createHash } from "crypto";
|
|
622
207
|
import { readFile } from "fs/promises";
|
|
623
|
-
import { resolve as
|
|
208
|
+
import { resolve as resolve2 } from "path";
|
|
624
209
|
var FileNotReadError = class extends Error {
|
|
625
210
|
constructor(path) {
|
|
626
211
|
super(`File "${path}" must be read before writing. Use read_file first.`);
|
|
@@ -649,7 +234,7 @@ async function computeFileHash(filePath) {
|
|
|
649
234
|
}
|
|
650
235
|
}
|
|
651
236
|
async function validateFileForWrite(filePath, readFiles) {
|
|
652
|
-
const normalizedPath =
|
|
237
|
+
const normalizedPath = resolve2(filePath);
|
|
653
238
|
const currentHash = await computeFileHash(normalizedPath);
|
|
654
239
|
if (currentHash === null) {
|
|
655
240
|
return { valid: true };
|
|
@@ -889,7 +474,7 @@ async function listDirectory(dirPath, relativePath) {
|
|
|
889
474
|
let sizeStr = "";
|
|
890
475
|
if (!entry.isDirectory()) {
|
|
891
476
|
try {
|
|
892
|
-
const entryStat = await stat(
|
|
477
|
+
const entryStat = await stat(join(dirPath, entry.name));
|
|
893
478
|
sizeStr = ` ${formatSize(entryStat.size).padStart(7)}`;
|
|
894
479
|
} catch {
|
|
895
480
|
}
|
|
@@ -1402,7 +987,7 @@ Make sure whitespace and indentation match exactly.`
|
|
|
1402
987
|
|
|
1403
988
|
// src/server/tools/shell.ts
|
|
1404
989
|
import { spawn } from "child_process";
|
|
1405
|
-
import { resolve as
|
|
990
|
+
import { resolve as resolve3, isAbsolute as isAbsolute2 } from "path";
|
|
1406
991
|
import { access } from "fs/promises";
|
|
1407
992
|
import stripAnsi from "strip-ansi";
|
|
1408
993
|
|
|
@@ -1428,7 +1013,7 @@ async function checkRtkAvailability() {
|
|
|
1428
1013
|
rtkAvailable = true;
|
|
1429
1014
|
} catch {
|
|
1430
1015
|
try {
|
|
1431
|
-
const out = await new Promise((
|
|
1016
|
+
const out = await new Promise((resolve5, reject) => {
|
|
1432
1017
|
const proc = spawn("rtk", ["--version"], { stdio: ["ignore", "pipe", "pipe"] });
|
|
1433
1018
|
let output = "";
|
|
1434
1019
|
proc.stdout?.on("data", (d) => {
|
|
@@ -1436,7 +1021,7 @@ async function checkRtkAvailability() {
|
|
|
1436
1021
|
});
|
|
1437
1022
|
proc.on("error", reject);
|
|
1438
1023
|
proc.on("close", (code) => {
|
|
1439
|
-
if (code === 0)
|
|
1024
|
+
if (code === 0) resolve5(output.trim());
|
|
1440
1025
|
else reject(new Error(`exit ${code}`));
|
|
1441
1026
|
});
|
|
1442
1027
|
});
|
|
@@ -1495,12 +1080,12 @@ var runCommandTool = createTool(
|
|
|
1495
1080
|
const pathsToCheck = [workingDir];
|
|
1496
1081
|
const commandPaths = extractAbsolutePathsFromCommand(args.command);
|
|
1497
1082
|
for (const cmdPath of commandPaths) {
|
|
1498
|
-
const resolved = isAbsolute2(cmdPath) ? cmdPath :
|
|
1083
|
+
const resolved = isAbsolute2(cmdPath) ? cmdPath : resolve3(workingDir, cmdPath);
|
|
1499
1084
|
pathsToCheck.push(resolved);
|
|
1500
1085
|
}
|
|
1501
1086
|
const sensitivePaths = extractSensitivePathsFromCommand(args.command);
|
|
1502
1087
|
for (const sensitivePath of sensitivePaths) {
|
|
1503
|
-
const resolved = isAbsolute2(sensitivePath) ? sensitivePath :
|
|
1088
|
+
const resolved = isAbsolute2(sensitivePath) ? sensitivePath : resolve3(workingDir, sensitivePath);
|
|
1504
1089
|
pathsToCheck.push(resolved);
|
|
1505
1090
|
}
|
|
1506
1091
|
await helpers.checkPathAccess(pathsToCheck, args.command);
|
|
@@ -1550,7 +1135,7 @@ ${result.stderr}`;
|
|
|
1550
1135
|
async function tryRtkRewrite(command) {
|
|
1551
1136
|
if (!await checkRtkAvailability()) return command;
|
|
1552
1137
|
try {
|
|
1553
|
-
const result = await new Promise((
|
|
1138
|
+
const result = await new Promise((resolve5, reject) => {
|
|
1554
1139
|
const proc = spawn("rtk", ["rewrite", command], {
|
|
1555
1140
|
stdio: ["ignore", "pipe", "pipe"],
|
|
1556
1141
|
timeout: 2e3
|
|
@@ -1561,7 +1146,7 @@ async function tryRtkRewrite(command) {
|
|
|
1561
1146
|
});
|
|
1562
1147
|
proc.on("error", reject);
|
|
1563
1148
|
proc.on("close", (code) => {
|
|
1564
|
-
if (code === 0 || code === 3)
|
|
1149
|
+
if (code === 0 || code === 3) resolve5(stdout.trim());
|
|
1565
1150
|
else reject(new Error(`exit ${code}`));
|
|
1566
1151
|
});
|
|
1567
1152
|
});
|
|
@@ -1571,7 +1156,7 @@ async function tryRtkRewrite(command) {
|
|
|
1571
1156
|
return command;
|
|
1572
1157
|
}
|
|
1573
1158
|
function executeCommand(command, cwd, timeout, signal, onProgress) {
|
|
1574
|
-
return new Promise((
|
|
1159
|
+
return new Promise((resolve5, reject) => {
|
|
1575
1160
|
if (checkAborted(signal)) {
|
|
1576
1161
|
reject(new Error("Command aborted before execution"));
|
|
1577
1162
|
return;
|
|
@@ -1610,7 +1195,7 @@ function executeCommand(command, cwd, timeout, signal, onProgress) {
|
|
|
1610
1195
|
let output = stdout.trim();
|
|
1611
1196
|
if (output) output += "\n\n";
|
|
1612
1197
|
output += "[interrupted by user]";
|
|
1613
|
-
|
|
1198
|
+
resolve5({
|
|
1614
1199
|
stdout: output,
|
|
1615
1200
|
stderr: stderr.trim(),
|
|
1616
1201
|
exitCode: 130
|
|
@@ -1622,7 +1207,7 @@ function executeCommand(command, cwd, timeout, signal, onProgress) {
|
|
|
1622
1207
|
if (output) output += "\n\n";
|
|
1623
1208
|
output += `[Exit code: 124]
|
|
1624
1209
|
[Process timed out after ${timeout}ms]`;
|
|
1625
|
-
|
|
1210
|
+
resolve5({
|
|
1626
1211
|
stdout: output,
|
|
1627
1212
|
stderr: stderr.trim(),
|
|
1628
1213
|
exitCode: 124
|
|
@@ -1638,7 +1223,7 @@ function executeCommand(command, cwd, timeout, signal, onProgress) {
|
|
|
1638
1223
|
if (output) output += "\n\n";
|
|
1639
1224
|
output += `[Exit code: 124]
|
|
1640
1225
|
[Process timed out after ${timeout}ms]`;
|
|
1641
|
-
|
|
1226
|
+
resolve5({
|
|
1642
1227
|
stdout: output,
|
|
1643
1228
|
stderr: stderr.trim(),
|
|
1644
1229
|
exitCode: 124
|
|
@@ -1649,14 +1234,14 @@ function executeCommand(command, cwd, timeout, signal, onProgress) {
|
|
|
1649
1234
|
let output = stdout.trim();
|
|
1650
1235
|
if (output) output += "\n\n";
|
|
1651
1236
|
output += "[interrupted by user]";
|
|
1652
|
-
|
|
1237
|
+
resolve5({
|
|
1653
1238
|
stdout: output,
|
|
1654
1239
|
stderr: stderr.trim(),
|
|
1655
1240
|
exitCode: 130
|
|
1656
1241
|
});
|
|
1657
1242
|
return;
|
|
1658
1243
|
}
|
|
1659
|
-
|
|
1244
|
+
resolve5({
|
|
1660
1245
|
stdout: stdout.trim(),
|
|
1661
1246
|
stderr: stderr.trim(),
|
|
1662
1247
|
exitCode: code ?? 1
|
|
@@ -1821,18 +1406,18 @@ ${Object.entries(schema.fields).map(([f, t]) => ` ${f}: ${t}`).join("\n")}`
|
|
|
1821
1406
|
|
|
1822
1407
|
// src/server/sub-agents/manager.ts
|
|
1823
1408
|
import { readFile as readFile8, access as access5 } from "fs/promises";
|
|
1824
|
-
import { join as
|
|
1409
|
+
import { join as join6, dirname as dirname5, isAbsolute as isAbsolute3 } from "path";
|
|
1825
1410
|
|
|
1826
1411
|
// src/server/agents/registry.ts
|
|
1827
1412
|
import { readdir as readdir3, readFile as readFile5, writeFile as writeFile4, mkdir as mkdir3, access as access3, unlink as unlink2 } from "fs/promises";
|
|
1828
|
-
import { join as
|
|
1413
|
+
import { join as join3, dirname as dirname2 } from "path";
|
|
1829
1414
|
import { constants as constants2 } from "fs";
|
|
1830
1415
|
import { fileURLToPath } from "url";
|
|
1831
1416
|
import matter2 from "gray-matter";
|
|
1832
1417
|
|
|
1833
1418
|
// src/server/shared/item-loader.ts
|
|
1834
1419
|
import { readdir as readdir2, readFile as readFile4, access as access2, writeFile as writeFile3, mkdir as mkdir2, unlink } from "fs/promises";
|
|
1835
|
-
import { join as
|
|
1420
|
+
import { join as join2 } from "path";
|
|
1836
1421
|
import { constants } from "fs";
|
|
1837
1422
|
import matter from "gray-matter";
|
|
1838
1423
|
async function pathExists(path) {
|
|
@@ -1864,7 +1449,7 @@ async function loadItemsFromDir(dir, options) {
|
|
|
1864
1449
|
const items = [];
|
|
1865
1450
|
for (const file of files) {
|
|
1866
1451
|
try {
|
|
1867
|
-
const raw = await readFile4(
|
|
1452
|
+
const raw = await readFile4(join2(dir, file), "utf-8");
|
|
1868
1453
|
const { data, content } = matter(raw);
|
|
1869
1454
|
if (data.id && content.trim()) {
|
|
1870
1455
|
items.push({
|
|
@@ -1888,12 +1473,12 @@ async function saveItemToDir(dir, item, ext, serialize) {
|
|
|
1888
1473
|
await mkdir2(dir, { recursive: true });
|
|
1889
1474
|
}
|
|
1890
1475
|
const meta = item.metadata;
|
|
1891
|
-
const filePath =
|
|
1476
|
+
const filePath = join2(dir, `${meta.id}${ext}`);
|
|
1892
1477
|
await writeFile3(filePath, serialize(item), "utf-8");
|
|
1893
1478
|
}
|
|
1894
1479
|
var jsonSerializer = (item) => JSON.stringify(item, null, 2) + "\n";
|
|
1895
1480
|
async function deleteItemFromDir(dir, id, ext) {
|
|
1896
|
-
const filePath =
|
|
1481
|
+
const filePath = join2(dir, `${id}${ext}`);
|
|
1897
1482
|
try {
|
|
1898
1483
|
await unlink(filePath);
|
|
1899
1484
|
return { success: true };
|
|
@@ -1904,14 +1489,14 @@ async function deleteItemFromDir(dir, id, ext) {
|
|
|
1904
1489
|
|
|
1905
1490
|
// src/server/agents/registry.ts
|
|
1906
1491
|
var __bundleDir = dirname2(fileURLToPath(import.meta.url));
|
|
1907
|
-
var DEFAULTS_DIR =
|
|
1908
|
-
var DEFAULTS_DIR_ALT =
|
|
1492
|
+
var DEFAULTS_DIR = join3(__bundleDir, "defaults");
|
|
1493
|
+
var DEFAULTS_DIR_ALT = join3(__bundleDir, "agent-defaults");
|
|
1909
1494
|
var AGENT_EXTENSION = ".agent.md";
|
|
1910
1495
|
function getAgentsDir(configDir) {
|
|
1911
|
-
return
|
|
1496
|
+
return join3(configDir, "agents");
|
|
1912
1497
|
}
|
|
1913
1498
|
function getProjectAgentsDir(projectDir) {
|
|
1914
|
-
return
|
|
1499
|
+
return join3(projectDir, ".openfox", "agents");
|
|
1915
1500
|
}
|
|
1916
1501
|
async function pathExists2(path) {
|
|
1917
1502
|
try {
|
|
@@ -1952,7 +1537,7 @@ async function loadAgentsFromDir(dir) {
|
|
|
1952
1537
|
const agents = [];
|
|
1953
1538
|
for (const file of files) {
|
|
1954
1539
|
try {
|
|
1955
|
-
const raw = await readFile5(
|
|
1540
|
+
const raw = await readFile5(join3(dir, file), "utf-8");
|
|
1956
1541
|
const agent = parseAgentFile(raw, file);
|
|
1957
1542
|
if (agent) {
|
|
1958
1543
|
agents.push(agent);
|
|
@@ -2037,7 +1622,7 @@ async function isDefaultAgent(agentId) {
|
|
|
2037
1622
|
}
|
|
2038
1623
|
function getAgentFilePaths(agentsDir, agentId) {
|
|
2039
1624
|
const hyphenated = agentId.replace(/_/g, "-");
|
|
2040
|
-
return [
|
|
1625
|
+
return [join3(agentsDir, `${agentId}${AGENT_EXTENSION}`), join3(agentsDir, `${hyphenated}${AGENT_EXTENSION}`)];
|
|
2041
1626
|
}
|
|
2042
1627
|
function findAgentById(agentId, agents) {
|
|
2043
1628
|
return agents.find((a) => a.metadata.id === agentId);
|
|
@@ -2071,7 +1656,7 @@ async function saveAgent(configDir, agent) {
|
|
|
2071
1656
|
if (!await pathExists2(agentsDir)) {
|
|
2072
1657
|
await mkdir3(agentsDir, { recursive: true });
|
|
2073
1658
|
}
|
|
2074
|
-
const filePath =
|
|
1659
|
+
const filePath = join3(agentsDir, `${agent.metadata.id}${AGENT_EXTENSION}`);
|
|
2075
1660
|
const content = matter2.stringify(agent.prompt, agent.metadata);
|
|
2076
1661
|
await writeFile4(filePath, content, "utf-8");
|
|
2077
1662
|
}
|
|
@@ -2095,7 +1680,7 @@ async function deleteAgent(configDir, agentId) {
|
|
|
2095
1680
|
|
|
2096
1681
|
// src/server/context/instructions.ts
|
|
2097
1682
|
import { readFile as readFile6, access as access4 } from "fs/promises";
|
|
2098
|
-
import { join as
|
|
1683
|
+
import { join as join4, dirname as dirname3 } from "path";
|
|
2099
1684
|
import { constants as constants3 } from "fs";
|
|
2100
1685
|
var INSTRUCTION_FILENAMES = ["AGENTS.md", "CLAUDE.md"];
|
|
2101
1686
|
async function findInstructionFiles(workdir) {
|
|
@@ -2112,7 +1697,7 @@ async function findInstructionFiles(workdir) {
|
|
|
2112
1697
|
}
|
|
2113
1698
|
for (const dir of pathsToCheck) {
|
|
2114
1699
|
for (const filename of INSTRUCTION_FILENAMES) {
|
|
2115
|
-
const filePath =
|
|
1700
|
+
const filePath = join4(dir, filename);
|
|
2116
1701
|
if (await fileExists(filePath)) {
|
|
2117
1702
|
foundFiles.push({
|
|
2118
1703
|
path: filePath,
|
|
@@ -2185,22 +1770,22 @@ async function fileExists(path) {
|
|
|
2185
1770
|
}
|
|
2186
1771
|
|
|
2187
1772
|
// src/server/skills/registry.ts
|
|
2188
|
-
import { writeFile as writeFile5, mkdir as mkdir4, unlink as unlink3, readdir as readdir4, readFile as readFile7, realpath
|
|
2189
|
-
import { join as
|
|
1773
|
+
import { writeFile as writeFile5, mkdir as mkdir4, unlink as unlink3, readdir as readdir4, readFile as readFile7, realpath, rm } from "fs/promises";
|
|
1774
|
+
import { join as join5, dirname as dirname4 } from "path";
|
|
2190
1775
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
2191
|
-
import { homedir
|
|
1776
|
+
import { homedir } from "os";
|
|
2192
1777
|
import matter3 from "gray-matter";
|
|
2193
1778
|
var __bundleDir2 = dirname4(fileURLToPath2(import.meta.url));
|
|
2194
|
-
var DEFAULTS_DIR2 =
|
|
2195
|
-
var DEFAULTS_DIR_ALT2 =
|
|
1779
|
+
var DEFAULTS_DIR2 = join5(__bundleDir2, "defaults");
|
|
1780
|
+
var DEFAULTS_DIR_ALT2 = join5(__bundleDir2, "skill-defaults");
|
|
2196
1781
|
var SKILL_EXTENSION = ".skill.md";
|
|
2197
1782
|
var SKILL_SETTING_PREFIX = "skill.enabled.";
|
|
2198
1783
|
var PORTABLE_NAME_REGEX = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
2199
1784
|
function getSkillsDir(configDir) {
|
|
2200
|
-
return
|
|
1785
|
+
return join5(configDir, "skills");
|
|
2201
1786
|
}
|
|
2202
1787
|
function getProjectSkillsDir(projectDir) {
|
|
2203
|
-
return
|
|
1788
|
+
return join5(projectDir, ".openfox", "skills");
|
|
2204
1789
|
}
|
|
2205
1790
|
function portableDisplayName(data, id) {
|
|
2206
1791
|
const metadata = data["metadata"];
|
|
@@ -2228,8 +1813,8 @@ async function loadPortableSkills(dir, source) {
|
|
|
2228
1813
|
const skills = [];
|
|
2229
1814
|
for (const entry of entries) {
|
|
2230
1815
|
if (!entry.isDirectory() && !entry.isSymbolicLink()) continue;
|
|
2231
|
-
const packageDir =
|
|
2232
|
-
const entrypoint =
|
|
1816
|
+
const packageDir = join5(dir, entry.name);
|
|
1817
|
+
const entrypoint = join5(packageDir, "SKILL.md");
|
|
2233
1818
|
try {
|
|
2234
1819
|
const content = await readFile7(entrypoint, "utf-8");
|
|
2235
1820
|
const parsed = matter3(content);
|
|
@@ -2238,7 +1823,7 @@ async function loadPortableSkills(dir, source) {
|
|
|
2238
1823
|
const description = typeof data["description"] === "string" ? data["description"].trim() : "";
|
|
2239
1824
|
const prompt = parsed.content.trim();
|
|
2240
1825
|
if (!id || !description || !prompt) continue;
|
|
2241
|
-
const resolvedDirectory = await
|
|
1826
|
+
const resolvedDirectory = await realpath(packageDir);
|
|
2242
1827
|
const warnings = [];
|
|
2243
1828
|
if (id.length > 64 || !PORTABLE_NAME_REGEX.test(id)) {
|
|
2244
1829
|
warnings.push("Skill name must use 1-64 lowercase letters, numbers, and single hyphens");
|
|
@@ -2269,10 +1854,10 @@ async function loadPortableSkills(dir, source) {
|
|
|
2269
1854
|
async function annotateLegacySkills(skills, dir, source) {
|
|
2270
1855
|
return Promise.all(
|
|
2271
1856
|
skills.map(async (skill) => {
|
|
2272
|
-
const entrypoint =
|
|
1857
|
+
const entrypoint = join5(dir, `${skill.metadata.id}${SKILL_EXTENSION}`);
|
|
2273
1858
|
let resolvedEntrypoint = entrypoint;
|
|
2274
1859
|
try {
|
|
2275
|
-
resolvedEntrypoint = await
|
|
1860
|
+
resolvedEntrypoint = await realpath(entrypoint);
|
|
2276
1861
|
} catch {
|
|
2277
1862
|
}
|
|
2278
1863
|
return {
|
|
@@ -2322,16 +1907,16 @@ async function loadAllSkills(configDir, projectDir, options = {}) {
|
|
|
2322
1907
|
return (await loadAllSkillsWithDiagnostics(configDir, projectDir, options)).skills;
|
|
2323
1908
|
}
|
|
2324
1909
|
async function loadAllSkillsWithDiagnostics(configDir, projectDir, options = {}) {
|
|
2325
|
-
const home = options.homeDir ??
|
|
1910
|
+
const home = options.homeDir ?? homedir();
|
|
2326
1911
|
const selected = (options.selectedDirectories ?? getSelectedSkillDirectories()).map(
|
|
2327
|
-
(dir) => dir === "~" ? home : dir.startsWith("~/") ?
|
|
1912
|
+
(dir) => dir === "~" ? home : dir.startsWith("~/") ? join5(home, dir.slice(2)) : dir
|
|
2328
1913
|
);
|
|
2329
1914
|
const locations = [
|
|
2330
1915
|
loadDefaultSkills(),
|
|
2331
|
-
loadSkillsDirectory(
|
|
1916
|
+
loadSkillsDirectory(join5(home, ".agents", "skills"), "global-shared"),
|
|
2332
1917
|
loadUserSkills(configDir),
|
|
2333
1918
|
...selected.map((dir) => loadSkillsDirectory(dir, "selected")),
|
|
2334
|
-
...projectDir ? [loadSkillsDirectory(
|
|
1919
|
+
...projectDir ? [loadSkillsDirectory(join5(projectDir, ".agents", "skills"), "project-shared"), loadProjectSkills(projectDir)] : []
|
|
2335
1920
|
];
|
|
2336
1921
|
const groups = await Promise.all(locations);
|
|
2337
1922
|
const skillMap = /* @__PURE__ */ new Map();
|
|
@@ -2381,11 +1966,11 @@ function findSkillById(skillId, skills) {
|
|
|
2381
1966
|
return skills.find((s) => s.metadata.id === skillId);
|
|
2382
1967
|
}
|
|
2383
1968
|
async function skillExists(configDir, skillId, projectDir) {
|
|
2384
|
-
if (await pathExists(
|
|
2385
|
-
if (await pathExists(
|
|
2386
|
-
if (projectDir && await pathExists(
|
|
1969
|
+
if (await pathExists(join5(getSkillsDir(configDir), `${skillId}${SKILL_EXTENSION}`))) return true;
|
|
1970
|
+
if (await pathExists(join5(getSkillsDir(configDir), skillId, "SKILL.md"))) return true;
|
|
1971
|
+
if (projectDir && await pathExists(join5(getProjectSkillsDir(projectDir), `${skillId}${SKILL_EXTENSION}`)))
|
|
2387
1972
|
return true;
|
|
2388
|
-
if (projectDir && await pathExists(
|
|
1973
|
+
if (projectDir && await pathExists(join5(getProjectSkillsDir(projectDir), skillId, "SKILL.md"))) return true;
|
|
2389
1974
|
return false;
|
|
2390
1975
|
}
|
|
2391
1976
|
function portableFrontmatter(skill) {
|
|
@@ -2401,9 +1986,9 @@ function portableFrontmatter(skill) {
|
|
|
2401
1986
|
};
|
|
2402
1987
|
}
|
|
2403
1988
|
async function savePortableSkill(dir, skill) {
|
|
2404
|
-
const packageDir =
|
|
1989
|
+
const packageDir = join5(dir, skill.metadata.id);
|
|
2405
1990
|
await mkdir4(packageDir, { recursive: true });
|
|
2406
|
-
await writeFile5(
|
|
1991
|
+
await writeFile5(join5(packageDir, "SKILL.md"), matter3.stringify(skill.prompt, portableFrontmatter(skill)), "utf-8");
|
|
2407
1992
|
}
|
|
2408
1993
|
async function saveSkill(configDir, skill) {
|
|
2409
1994
|
await savePortableSkill(getSkillsDir(configDir), skill);
|
|
@@ -2486,7 +2071,7 @@ async function deleteSkill(configDir, skillId) {
|
|
|
2486
2071
|
if (isDefault) {
|
|
2487
2072
|
return { success: false, reason: "Cannot delete built-in defaults" };
|
|
2488
2073
|
}
|
|
2489
|
-
const filePath =
|
|
2074
|
+
const filePath = join5(getSkillsDir(configDir), `${skillId}${SKILL_EXTENSION}`);
|
|
2490
2075
|
try {
|
|
2491
2076
|
await unlink3(filePath);
|
|
2492
2077
|
deleteSetting(`${SKILL_SETTING_PREFIX}${skillId}`);
|
|
@@ -2522,6 +2107,21 @@ function createToolProgressHandler(append, messageId, callId, _sessionId) {
|
|
|
2522
2107
|
// src/server/chat/execute-tools.ts
|
|
2523
2108
|
import stripAnsi2 from "strip-ansi";
|
|
2524
2109
|
var INTERRUPTED_ERROR = "Tool execution was interrupted by user";
|
|
2110
|
+
function extractSubAgentPrompt(args) {
|
|
2111
|
+
return args["prompt"] || args["query"] || args["task"] || "";
|
|
2112
|
+
}
|
|
2113
|
+
async function transformSubAgentAliases(toolCalls, toolRegistry) {
|
|
2114
|
+
const hasCallSubAgent = toolRegistry.tools.some((t) => t.name === "call_sub_agent");
|
|
2115
|
+
if (!hasCallSubAgent) return;
|
|
2116
|
+
const agents = await loadAllAgentsDefault();
|
|
2117
|
+
for (const tc of toolCalls) {
|
|
2118
|
+
const agentDef = findAgentById(tc.name, agents);
|
|
2119
|
+
if (!agentDef?.metadata.subagent) continue;
|
|
2120
|
+
const prompt = extractSubAgentPrompt(tc.arguments);
|
|
2121
|
+
tc.name = "call_sub_agent";
|
|
2122
|
+
tc.arguments = { subAgentType: agentDef.metadata.id, prompt };
|
|
2123
|
+
}
|
|
2124
|
+
}
|
|
2525
2125
|
function createInterruptedResult(startTime) {
|
|
2526
2126
|
return {
|
|
2527
2127
|
success: false,
|
|
@@ -2538,6 +2138,7 @@ async function executeTools(assistantMsgId, toolCalls, ctx, append) {
|
|
|
2538
2138
|
if (ctx.signal?.aborted) {
|
|
2539
2139
|
throw new Error("Aborted");
|
|
2540
2140
|
}
|
|
2141
|
+
await transformSubAgentAliases(toolCalls, ctx.toolRegistry);
|
|
2541
2142
|
for (const toolCall of toolCalls) {
|
|
2542
2143
|
append(createToolCallEvent(assistantMsgId, toolCall));
|
|
2543
2144
|
}
|
|
@@ -2843,6 +2444,8 @@ ${CONTINUE_PROMPT}` : CONTINUE_PROMPT;
|
|
|
2843
2444
|
const requestedMaxTokens = modelSettings.maxTokens ?? 16384;
|
|
2844
2445
|
modelSettings = { ...modelSettings, maxTokens: Math.min(requestedMaxTokens, availableForOutput) };
|
|
2845
2446
|
}
|
|
2447
|
+
const allAgents = await loadAllAgentsDefault();
|
|
2448
|
+
const subAgentAliases = new Set(getSubAgents(allAgents).map((a) => a.metadata.id));
|
|
2846
2449
|
const streamGen = streamLLMPure({
|
|
2847
2450
|
messageId: assistantMsgId,
|
|
2848
2451
|
systemPrompt: assembledRequest.systemPrompt,
|
|
@@ -2851,6 +2454,7 @@ ${CONTINUE_PROMPT}` : CONTINUE_PROMPT;
|
|
|
2851
2454
|
tools: assembledRequest.tools,
|
|
2852
2455
|
toolChoice: "auto",
|
|
2853
2456
|
signal,
|
|
2457
|
+
subAgentAliases,
|
|
2854
2458
|
...config.retryPatterns ? { retryPatterns: config.retryPatterns } : {},
|
|
2855
2459
|
...modelSettings && { modelSettings }
|
|
2856
2460
|
});
|
|
@@ -2909,7 +2513,7 @@ ${CONTINUE_PROMPT}` : CONTINUE_PROMPT;
|
|
|
2909
2513
|
sessionManager.setCurrentContextSize(sessionId, result.usage.promptTokens, config.subAgentMetadata?.subAgentId);
|
|
2910
2514
|
if (!compacting) {
|
|
2911
2515
|
const contextState2 = sessionManager.getContextState(sessionId);
|
|
2912
|
-
const { shouldCompact, appendCompactionPrompt } = await import("./compactor-
|
|
2516
|
+
const { shouldCompact, appendCompactionPrompt } = await import("./compactor-BB3YYVRP.js");
|
|
2913
2517
|
if (shouldCompact(contextState2.currentTokens, contextState2.maxTokens, runtimeConfig.context.compactionThreshold)) {
|
|
2914
2518
|
appendCompactionPrompt(sessionId, append);
|
|
2915
2519
|
compacting = true;
|
|
@@ -3609,7 +3213,7 @@ async function loadGitIgnoreRules(workdir) {
|
|
|
3609
3213
|
if (!isAbsolute3(workdir)) return "";
|
|
3610
3214
|
let currentDir = workdir;
|
|
3611
3215
|
while (true) {
|
|
3612
|
-
const gitignorePath =
|
|
3216
|
+
const gitignorePath = join6(currentDir, ".gitignore");
|
|
3613
3217
|
try {
|
|
3614
3218
|
await access5(gitignorePath);
|
|
3615
3219
|
const content = await readFile8(gitignorePath, "utf-8");
|
|
@@ -3814,7 +3418,7 @@ var callSubAgentTool = {
|
|
|
3814
3418
|
};
|
|
3815
3419
|
}
|
|
3816
3420
|
try {
|
|
3817
|
-
const { getToolRegistryForAgent: getToolRegistryForAgent2 } = await import("./tools-
|
|
3421
|
+
const { getToolRegistryForAgent: getToolRegistryForAgent2 } = await import("./tools-JRCUWPJO.js");
|
|
3818
3422
|
const toolRegistry = getToolRegistryForAgent2(agentDef);
|
|
3819
3423
|
const turnMetrics = new TurnMetrics();
|
|
3820
3424
|
const result = await executeSubAgent({
|
|
@@ -4100,7 +3704,7 @@ var webFetchTool = createTool(
|
|
|
4100
3704
|
// src/server/dev-server/manager.ts
|
|
4101
3705
|
import "child_process";
|
|
4102
3706
|
import { readFile as readFile9, writeFile as writeFile6, mkdir as mkdir5 } from "fs/promises";
|
|
4103
|
-
import { resolve as
|
|
3707
|
+
import { resolve as resolve4, join as join7 } from "path";
|
|
4104
3708
|
import net from "net";
|
|
4105
3709
|
var MAX_LOG_LINES = 2e3;
|
|
4106
3710
|
var MAX_LOG_BYTES = 1e5;
|
|
@@ -4108,7 +3712,7 @@ var DEFAULT_PROBE_PORT = 10469;
|
|
|
4108
3712
|
var MAX_PORT_SCAN = 200;
|
|
4109
3713
|
var PROBE_TIMEOUT_MS = 300;
|
|
4110
3714
|
var getDevServerConfigPath = (workdir) => {
|
|
4111
|
-
return
|
|
3715
|
+
return join7(resolve4(workdir), ".openfox", "dev.json");
|
|
4112
3716
|
};
|
|
4113
3717
|
var ERROR_PATTERNS = [
|
|
4114
3718
|
/EADDRINUSE/,
|
|
@@ -4157,7 +3761,7 @@ var DevServerManager = class {
|
|
|
4157
3761
|
this._sessionManager = sm;
|
|
4158
3762
|
}
|
|
4159
3763
|
resolveWorkdir(workdir) {
|
|
4160
|
-
return
|
|
3764
|
+
return resolve4(workdir);
|
|
4161
3765
|
}
|
|
4162
3766
|
getInstance(workdir) {
|
|
4163
3767
|
const key = this.resolveWorkdir(workdir);
|
|
@@ -4255,7 +3859,7 @@ var DevServerManager = class {
|
|
|
4255
3859
|
}
|
|
4256
3860
|
async saveConfig(workdir, config) {
|
|
4257
3861
|
const resolved = this.resolveWorkdir(workdir);
|
|
4258
|
-
const dirPath =
|
|
3862
|
+
const dirPath = join7(resolved, ".openfox");
|
|
4259
3863
|
await mkdir5(dirPath, { recursive: true });
|
|
4260
3864
|
const configPath = getDevServerConfigPath(workdir);
|
|
4261
3865
|
await writeFile6(configPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
@@ -4813,7 +4417,7 @@ var mcpConfigTool = createTool(
|
|
|
4813
4417
|
mcpNotifyChanged?.(sessionId);
|
|
4814
4418
|
}
|
|
4815
4419
|
async function rebuildTools() {
|
|
4816
|
-
const { setMcpTools: setMcpTools2 } = await import("./tools-
|
|
4420
|
+
const { setMcpTools: setMcpTools2 } = await import("./tools-JRCUWPJO.js");
|
|
4817
4421
|
const mcpTools = createMcpTools(mcpManagerForTools);
|
|
4818
4422
|
setMcpTools2(mcpTools);
|
|
4819
4423
|
}
|
|
@@ -4899,7 +4503,9 @@ var mcpConfigTool = createTool(
|
|
|
4899
4503
|
notifyContextChanged(context.sessionId);
|
|
4900
4504
|
const server = mcpManagerForTools.getServer(args.name);
|
|
4901
4505
|
const toolCount = server?.tools.length ?? 0;
|
|
4902
|
-
return helpers.success(
|
|
4506
|
+
return helpers.success(
|
|
4507
|
+
`Updated MCP server "${args.name}" (${toolCount} tools discovered). ${APPLY_PROMPT_MESSAGE}`
|
|
4508
|
+
);
|
|
4903
4509
|
}
|
|
4904
4510
|
if (args.action === "remove") {
|
|
4905
4511
|
if (!args.name) return helpers.error("Missing required field: name");
|
|
@@ -5243,39 +4849,11 @@ function validateToolAction(toolName, action, permissions) {
|
|
|
5243
4849
|
}
|
|
5244
4850
|
return void 0;
|
|
5245
4851
|
}
|
|
5246
|
-
function extractSubAgentPrompt(args) {
|
|
5247
|
-
return args["prompt"] || args["query"] || args["task"] || "";
|
|
5248
|
-
}
|
|
5249
4852
|
function createRegistryFromTools(tools, allowedTools, toolPermissions, agentId, isSubAgent) {
|
|
5250
4853
|
const toolMap = /* @__PURE__ */ new Map();
|
|
5251
4854
|
for (const tool of tools) {
|
|
5252
4855
|
toolMap.set(tool.name, tool);
|
|
5253
4856
|
}
|
|
5254
|
-
async function trySubAgentAlias(name, args, context) {
|
|
5255
|
-
if (!toolMap.has("call_sub_agent")) {
|
|
5256
|
-
return null;
|
|
5257
|
-
}
|
|
5258
|
-
try {
|
|
5259
|
-
const agents = await loadAllAgentsDefault();
|
|
5260
|
-
const agentDef = findAgentById(name, agents);
|
|
5261
|
-
if (!agentDef?.metadata.subagent) {
|
|
5262
|
-
return null;
|
|
5263
|
-
}
|
|
5264
|
-
const prompt = extractSubAgentPrompt(args);
|
|
5265
|
-
logger.info("Sub-agent alias transformation", {
|
|
5266
|
-
from: name,
|
|
5267
|
-
to: "call_sub_agent",
|
|
5268
|
-
subAgentType: name
|
|
5269
|
-
});
|
|
5270
|
-
return callSubAgentTool.execute({ subAgentType: name, prompt }, context);
|
|
5271
|
-
} catch (err) {
|
|
5272
|
-
logger.warn("Sub-agent alias resolution failed", {
|
|
5273
|
-
tool: name,
|
|
5274
|
-
error: err instanceof Error ? err.message : String(err)
|
|
5275
|
-
});
|
|
5276
|
-
return null;
|
|
5277
|
-
}
|
|
5278
|
-
}
|
|
5279
4857
|
return {
|
|
5280
4858
|
tools,
|
|
5281
4859
|
definitions: tools.map((t) => t.definition),
|
|
@@ -5351,8 +4929,6 @@ function createRegistryFromTools(tools, allowedTools, toolPermissions, agentId,
|
|
|
5351
4929
|
};
|
|
5352
4930
|
}
|
|
5353
4931
|
}
|
|
5354
|
-
const aliasResult = await trySubAgentAlias(name, args, context);
|
|
5355
|
-
if (aliasResult) return aliasResult;
|
|
5356
4932
|
return {
|
|
5357
4933
|
success: false,
|
|
5358
4934
|
error: `Unknown tool: ${name}. Available tools: ${tools.map((t) => t.name).join(", ")}`,
|
|
@@ -5429,10 +5005,6 @@ function createToolRegistry() {
|
|
|
5429
5005
|
}
|
|
5430
5006
|
|
|
5431
5007
|
export {
|
|
5432
|
-
requestPathAccess,
|
|
5433
|
-
PathAccessDeniedError,
|
|
5434
|
-
providePathConfirmation,
|
|
5435
|
-
cancelPathConfirmationsForSession,
|
|
5436
5008
|
pathExists,
|
|
5437
5009
|
getDefaultIds,
|
|
5438
5010
|
loadItemsFromDir,
|
|
@@ -5493,4 +5065,4 @@ export {
|
|
|
5493
5065
|
getToolRegistryForAgent,
|
|
5494
5066
|
createToolRegistry
|
|
5495
5067
|
};
|
|
5496
|
-
//# sourceMappingURL=chunk-
|
|
5068
|
+
//# sourceMappingURL=chunk-D6CI2B7B.js.map
|