@ai-setting/roy-agent-core 1.5.29 → 1.5.31
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/env/tool/built-in/index.js +1 -1
- package/dist/env/tool/index.js +2 -2
- package/dist/index.js +2 -2
- package/dist/shared/@ai-setting/{roy-agent-core-satmq6sh.js → roy-agent-core-p46v1kr2.js} +398 -83
- package/package.json +1 -1
- /package/dist/shared/@ai-setting/{roy-agent-core-qqceba6k.js → roy-agent-core-q27e6dhw.js} +0 -0
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
grepTool,
|
|
9
9
|
readFileTool,
|
|
10
10
|
writeFileTool
|
|
11
|
-
} from "../../../shared/@ai-setting/roy-agent-core-
|
|
11
|
+
} from "../../../shared/@ai-setting/roy-agent-core-p46v1kr2.js";
|
|
12
12
|
import"../../../shared/@ai-setting/roy-agent-core-xs5rsgat.js";
|
|
13
13
|
import"../../../shared/@ai-setting/roy-agent-core-psv4v63c.js";
|
|
14
14
|
import"../../../shared/@ai-setting/roy-agent-core-fs0mn2jk.js";
|
package/dist/env/tool/index.js
CHANGED
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
ToolComponent,
|
|
3
3
|
ToolRegistry,
|
|
4
4
|
ToolValidator
|
|
5
|
-
} from "../../shared/@ai-setting/roy-agent-core-
|
|
5
|
+
} from "../../shared/@ai-setting/roy-agent-core-q27e6dhw.js";
|
|
6
6
|
import {
|
|
7
7
|
bashTool,
|
|
8
8
|
echoTool,
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
grepTool,
|
|
14
14
|
readFileTool,
|
|
15
15
|
writeFileTool
|
|
16
|
-
} from "../../shared/@ai-setting/roy-agent-core-
|
|
16
|
+
} from "../../shared/@ai-setting/roy-agent-core-p46v1kr2.js";
|
|
17
17
|
import"../../shared/@ai-setting/roy-agent-core-e25xkv53.js";
|
|
18
18
|
import"../../shared/@ai-setting/roy-agent-core-qxhq8ven.js";
|
|
19
19
|
import"../../shared/@ai-setting/roy-agent-core-kkbwepqb.js";
|
package/dist/index.js
CHANGED
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
ToolComponent,
|
|
10
10
|
ToolRegistry,
|
|
11
11
|
ToolValidator
|
|
12
|
-
} from "./shared/@ai-setting/roy-agent-core-
|
|
12
|
+
} from "./shared/@ai-setting/roy-agent-core-q27e6dhw.js";
|
|
13
13
|
import {
|
|
14
14
|
bashTool,
|
|
15
15
|
editFileTool,
|
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
grepTool,
|
|
20
20
|
readFileTool,
|
|
21
21
|
writeFileTool
|
|
22
|
-
} from "./shared/@ai-setting/roy-agent-core-
|
|
22
|
+
} from "./shared/@ai-setting/roy-agent-core-p46v1kr2.js";
|
|
23
23
|
import {
|
|
24
24
|
PromptComponent,
|
|
25
25
|
getBuiltInPrompt,
|
|
@@ -11,9 +11,100 @@ import {
|
|
|
11
11
|
// src/env/tool/built-in/bash.ts
|
|
12
12
|
init_propagation();
|
|
13
13
|
import { z } from "zod";
|
|
14
|
-
import {
|
|
15
|
-
import
|
|
16
|
-
|
|
14
|
+
import { spawn } from "child_process";
|
|
15
|
+
import path from "path";
|
|
16
|
+
function getPlatform() {
|
|
17
|
+
return process.platform;
|
|
18
|
+
}
|
|
19
|
+
function isWindows() {
|
|
20
|
+
return getPlatform() === "win32";
|
|
21
|
+
}
|
|
22
|
+
function getShellCommand(command) {
|
|
23
|
+
if (isWindows()) {
|
|
24
|
+
return {
|
|
25
|
+
shell: "cmd.exe",
|
|
26
|
+
args: ["/c", command]
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
return {
|
|
30
|
+
shell: "/bin/sh",
|
|
31
|
+
args: ["-c", command]
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
function normalizeCwd(cwd) {
|
|
35
|
+
if (!cwd)
|
|
36
|
+
return;
|
|
37
|
+
return path.normalize(cwd);
|
|
38
|
+
}
|
|
39
|
+
function executeCommand(command, options) {
|
|
40
|
+
return new Promise((resolve) => {
|
|
41
|
+
const { shell, args } = getShellCommand(command);
|
|
42
|
+
let stdout = "";
|
|
43
|
+
let stderr = "";
|
|
44
|
+
let timedOut = false;
|
|
45
|
+
let resolved = false;
|
|
46
|
+
let timer = null;
|
|
47
|
+
let forceKillTimer = null;
|
|
48
|
+
const child = spawn(shell, args, {
|
|
49
|
+
cwd: normalizeCwd(options.cwd),
|
|
50
|
+
env: options.env,
|
|
51
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
52
|
+
windowsHide: true
|
|
53
|
+
});
|
|
54
|
+
const cleanup = () => {
|
|
55
|
+
if (timer)
|
|
56
|
+
clearTimeout(timer);
|
|
57
|
+
if (forceKillTimer)
|
|
58
|
+
clearTimeout(forceKillTimer);
|
|
59
|
+
};
|
|
60
|
+
const doResolve = (result) => {
|
|
61
|
+
if (!resolved) {
|
|
62
|
+
resolved = true;
|
|
63
|
+
cleanup();
|
|
64
|
+
resolve(result);
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
if (options.timeout) {
|
|
68
|
+
timer = setTimeout(() => {
|
|
69
|
+
timedOut = true;
|
|
70
|
+
if (isWindows()) {
|
|
71
|
+
child.kill("SIGTERM");
|
|
72
|
+
forceKillTimer = setTimeout(() => {
|
|
73
|
+
if (!child.killed) {
|
|
74
|
+
try {
|
|
75
|
+
process.kill(child.pid, "SIGKILL");
|
|
76
|
+
} catch {}
|
|
77
|
+
}
|
|
78
|
+
}, 500);
|
|
79
|
+
} else {
|
|
80
|
+
child.kill("SIGKILL");
|
|
81
|
+
}
|
|
82
|
+
}, options.timeout);
|
|
83
|
+
}
|
|
84
|
+
child.stdout?.on("data", (data) => {
|
|
85
|
+
stdout += data.toString();
|
|
86
|
+
});
|
|
87
|
+
child.stderr?.on("data", (data) => {
|
|
88
|
+
stderr += data.toString();
|
|
89
|
+
});
|
|
90
|
+
child.on("close", (code) => {
|
|
91
|
+
doResolve({
|
|
92
|
+
stdout: stdout.trim(),
|
|
93
|
+
stderr: stderr.trim(),
|
|
94
|
+
exitCode: timedOut ? -1 : code ?? 0,
|
|
95
|
+
timedOut
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
child.on("error", (err) => {
|
|
99
|
+
doResolve({
|
|
100
|
+
stdout: stdout.trim(),
|
|
101
|
+
stderr: err.message,
|
|
102
|
+
exitCode: 1,
|
|
103
|
+
timedOut: false
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
}
|
|
17
108
|
function getCurrentSpanContext() {
|
|
18
109
|
try {
|
|
19
110
|
const { getTracerProvider } = (init_tracer_provider(), __toCommonJS(exports_tracer_provider));
|
|
@@ -61,19 +152,14 @@ var bashTool = {
|
|
|
61
152
|
metadata: {
|
|
62
153
|
category: "system",
|
|
63
154
|
tags: ["shell", "command", "terminal", "exec"],
|
|
64
|
-
version: "1.
|
|
155
|
+
version: "1.3.0"
|
|
65
156
|
},
|
|
66
157
|
execute: async (args, ctx) => {
|
|
67
158
|
const startTime = Date.now();
|
|
68
159
|
const { command, workdir, timeout = 60000, env } = args;
|
|
69
160
|
const currentSpanCtx = getCurrentSpanContext();
|
|
70
161
|
const traceId = currentSpanCtx?.traceId || getCurrentTraceId();
|
|
71
|
-
const
|
|
72
|
-
timeout
|
|
73
|
-
};
|
|
74
|
-
if (workdir || ctx.workdir) {
|
|
75
|
-
options.cwd = workdir || ctx.workdir;
|
|
76
|
-
}
|
|
162
|
+
const cwd = workdir || ctx.workdir;
|
|
77
163
|
const childEnv = {};
|
|
78
164
|
for (const [key, value] of Object.entries(process.env)) {
|
|
79
165
|
if (value !== undefined) {
|
|
@@ -96,7 +182,6 @@ var bashTool = {
|
|
|
96
182
|
if (env) {
|
|
97
183
|
Object.assign(childEnv, env);
|
|
98
184
|
}
|
|
99
|
-
options.env = childEnv;
|
|
100
185
|
let otelSpan = undefined;
|
|
101
186
|
try {
|
|
102
187
|
const { getTracerProvider } = (init_tracer_provider(), __toCommonJS(exports_tracer_provider));
|
|
@@ -105,51 +190,67 @@ var bashTool = {
|
|
|
105
190
|
otelSpan = tracer.startSpan(`bash: ${command.slice(0, 50)}${command.length > 50 ? "..." : ""}`, {
|
|
106
191
|
attributes: {
|
|
107
192
|
"bash.command": command.slice(0, 200),
|
|
108
|
-
"bash.workdir":
|
|
109
|
-
"bash.timeout": timeout
|
|
193
|
+
"bash.workdir": cwd || "",
|
|
194
|
+
"bash.timeout": timeout,
|
|
195
|
+
"bash.platform": process.platform
|
|
110
196
|
}
|
|
111
197
|
});
|
|
112
198
|
} catch {}
|
|
113
199
|
const spanId = otelSpan?.spanContext?.spanId;
|
|
114
200
|
try {
|
|
115
|
-
const
|
|
201
|
+
const result = await executeCommand(command, {
|
|
202
|
+
cwd,
|
|
203
|
+
timeout,
|
|
204
|
+
env: childEnv
|
|
205
|
+
});
|
|
116
206
|
if (otelSpan) {
|
|
117
|
-
|
|
207
|
+
if (result.timedOut) {
|
|
208
|
+
const execError = new Error(`Command timed out after ${timeout}ms`);
|
|
209
|
+
execError.name = "BashExecutionError";
|
|
210
|
+
otelSpan.end(undefined, execError);
|
|
211
|
+
} else if (result.exitCode !== 0) {
|
|
212
|
+
const execError = new Error(result.stderr || "Command failed");
|
|
213
|
+
execError.name = "BashExecutionError";
|
|
214
|
+
otelSpan.end(undefined, execError);
|
|
215
|
+
} else {
|
|
216
|
+
otelSpan.end({ stdout: result.stdout, stderr: result.stderr });
|
|
217
|
+
}
|
|
118
218
|
}
|
|
119
219
|
return {
|
|
120
|
-
success:
|
|
121
|
-
output: stdout || "(no output)",
|
|
220
|
+
success: !result.timedOut && result.exitCode === 0,
|
|
221
|
+
output: result.stdout || "(no output)",
|
|
222
|
+
error: result.timedOut ? `Command timed out after ${timeout}ms` : result.exitCode !== 0 ? result.stderr : undefined,
|
|
122
223
|
metadata: {
|
|
123
224
|
execution_time_ms: Date.now() - startTime,
|
|
124
|
-
stdout,
|
|
125
|
-
stderr,
|
|
126
|
-
exit_code:
|
|
225
|
+
stdout: result.stdout,
|
|
226
|
+
stderr: result.stderr,
|
|
227
|
+
exit_code: result.exitCode,
|
|
228
|
+
timed_out: result.timedOut,
|
|
127
229
|
trace_id: traceId,
|
|
128
230
|
parent_span_id: currentSpanCtx?.spanId,
|
|
129
|
-
span_id: spanId
|
|
231
|
+
span_id: spanId,
|
|
232
|
+
platform: process.platform
|
|
130
233
|
}
|
|
131
234
|
};
|
|
132
235
|
} catch (error) {
|
|
133
|
-
const
|
|
134
|
-
const
|
|
135
|
-
const stderr = error.stderr || error.message;
|
|
136
|
-
const execError = new Error(stderr);
|
|
236
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
237
|
+
const execError = new Error(errorMessage);
|
|
137
238
|
execError.name = "BashExecutionError";
|
|
138
239
|
if (otelSpan) {
|
|
139
240
|
otelSpan.end(undefined, execError);
|
|
140
241
|
}
|
|
141
242
|
return {
|
|
142
|
-
success:
|
|
143
|
-
output:
|
|
144
|
-
error:
|
|
243
|
+
success: false,
|
|
244
|
+
output: "",
|
|
245
|
+
error: errorMessage,
|
|
145
246
|
metadata: {
|
|
146
247
|
execution_time_ms: Date.now() - startTime,
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
exit_code: exitCode,
|
|
248
|
+
exit_code: 1,
|
|
249
|
+
timed_out: false,
|
|
150
250
|
trace_id: traceId,
|
|
151
251
|
parent_span_id: currentSpanCtx?.spanId,
|
|
152
|
-
span_id: spanId
|
|
252
|
+
span_id: spanId,
|
|
253
|
+
platform: process.platform
|
|
153
254
|
}
|
|
154
255
|
};
|
|
155
256
|
}
|
|
@@ -182,13 +283,15 @@ var echoTool = {
|
|
|
182
283
|
// src/env/tool/built-in/glob.ts
|
|
183
284
|
import { z as z2 } from "zod";
|
|
184
285
|
import { glob as globAsync } from "glob";
|
|
286
|
+
import { stat } from "fs/promises";
|
|
287
|
+
import path2 from "path";
|
|
185
288
|
var globTool = {
|
|
186
289
|
name: "glob",
|
|
187
290
|
description: "Search for files matching a glob pattern. Use this to find files by name patterns like **/*.ts or **/*.md.",
|
|
188
291
|
parameters: z2.object({
|
|
189
|
-
pattern: z2.string().describe("Glob pattern to match (e.g., **/*.ts, **/*.md)"),
|
|
292
|
+
pattern: z2.string().min(1).describe("Glob pattern to match (e.g., **/*.ts, **/*.md)"),
|
|
190
293
|
cwd: z2.string().optional().describe("Working directory to search in"),
|
|
191
|
-
maxResults: z2.number().int().positive().optional().describe("Maximum number of results to return"),
|
|
294
|
+
maxResults: z2.number().int().positive().default(100).optional().describe("Maximum number of results to return"),
|
|
192
295
|
ignore: z2.array(z2.string()).optional().describe("Patterns to ignore")
|
|
193
296
|
}),
|
|
194
297
|
sandbox: {
|
|
@@ -197,20 +300,66 @@ var globTool = {
|
|
|
197
300
|
metadata: {
|
|
198
301
|
category: "file",
|
|
199
302
|
tags: ["search", "file", "glob", "pattern"],
|
|
200
|
-
version: "1.
|
|
303
|
+
version: "1.1.0"
|
|
201
304
|
},
|
|
202
305
|
execute: async (args, ctx) => {
|
|
203
306
|
const startTime = Date.now();
|
|
204
307
|
const { pattern, cwd, maxResults = 100, ignore } = args;
|
|
205
308
|
const searchDir = cwd || ctx.workdir || process.cwd();
|
|
206
309
|
try {
|
|
207
|
-
const
|
|
310
|
+
const dirStats = await stat(searchDir);
|
|
311
|
+
if (!dirStats.isDirectory()) {
|
|
312
|
+
return {
|
|
313
|
+
success: false,
|
|
314
|
+
output: "",
|
|
315
|
+
error: `Path is not a directory: ${searchDir}`,
|
|
316
|
+
metadata: { execution_time_ms: Date.now() - startTime }
|
|
317
|
+
};
|
|
318
|
+
}
|
|
319
|
+
} catch (error) {
|
|
320
|
+
return {
|
|
321
|
+
success: false,
|
|
322
|
+
output: "",
|
|
323
|
+
error: error instanceof Error ? error.message : String(error),
|
|
324
|
+
metadata: { execution_time_ms: Date.now() - startTime }
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
try {
|
|
328
|
+
const absolutePattern = path2.isAbsolute(pattern) ? pattern : pattern;
|
|
329
|
+
const files = await globAsync(absolutePattern, {
|
|
208
330
|
cwd: searchDir,
|
|
209
331
|
ignore: ignore || ["**/node_modules/**", "**/.git/**"],
|
|
210
|
-
maxDepth: 20
|
|
332
|
+
maxDepth: 20,
|
|
333
|
+
absolute: false,
|
|
334
|
+
nodir: true
|
|
211
335
|
});
|
|
212
|
-
const
|
|
213
|
-
const
|
|
336
|
+
const filesWithMtime = [];
|
|
337
|
+
for (const file of files) {
|
|
338
|
+
try {
|
|
339
|
+
const fullPath = path2.join(searchDir, file);
|
|
340
|
+
const stats = await stat(fullPath);
|
|
341
|
+
if (stats.isFile()) {
|
|
342
|
+
filesWithMtime.push({
|
|
343
|
+
path: file,
|
|
344
|
+
mtime: stats.mtimeMs
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
} catch {}
|
|
348
|
+
}
|
|
349
|
+
filesWithMtime.sort((a, b) => b.mtime - a.mtime);
|
|
350
|
+
const truncated = filesWithMtime.length > maxResults;
|
|
351
|
+
const limitedFiles = filesWithMtime.slice(0, maxResults);
|
|
352
|
+
const outputLines = [];
|
|
353
|
+
if (limitedFiles.length === 0) {
|
|
354
|
+
outputLines.push("No files found");
|
|
355
|
+
} else {
|
|
356
|
+
outputLines.push(...limitedFiles.map((f) => f.path));
|
|
357
|
+
if (truncated) {
|
|
358
|
+
outputLines.push("");
|
|
359
|
+
outputLines.push(`(Results are truncated: showing first ${maxResults} results. Consider using a more specific path or pattern.)`);
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
const output = outputLines.join(`
|
|
214
363
|
`);
|
|
215
364
|
return {
|
|
216
365
|
success: true,
|
|
@@ -218,8 +367,9 @@ var globTool = {
|
|
|
218
367
|
metadata: {
|
|
219
368
|
execution_time_ms: Date.now() - startTime,
|
|
220
369
|
output_size: output.length,
|
|
221
|
-
total_matches:
|
|
222
|
-
returned_matches: limitedFiles.length
|
|
370
|
+
total_matches: filesWithMtime.length,
|
|
371
|
+
returned_matches: limitedFiles.length,
|
|
372
|
+
truncated
|
|
223
373
|
}
|
|
224
374
|
};
|
|
225
375
|
} catch (error) {
|
|
@@ -237,7 +387,8 @@ var globTool = {
|
|
|
237
387
|
|
|
238
388
|
// src/env/tool/built-in/read-file.ts
|
|
239
389
|
import { z as z3 } from "zod";
|
|
240
|
-
import { readFile } from "fs/promises";
|
|
390
|
+
import { readFile, stat as stat2 } from "fs/promises";
|
|
391
|
+
import path3 from "path";
|
|
241
392
|
var readFileTool = {
|
|
242
393
|
name: "read_file",
|
|
243
394
|
description: "Read the contents of a file. Use this to read source code, configuration files, or any text files.",
|
|
@@ -261,21 +412,67 @@ var readFileTool = {
|
|
|
261
412
|
metadata: {
|
|
262
413
|
category: "file",
|
|
263
414
|
tags: ["read", "file", "io"],
|
|
264
|
-
version: "1.
|
|
415
|
+
version: "1.1.0"
|
|
265
416
|
},
|
|
266
417
|
execute: async (args, ctx) => {
|
|
267
418
|
const startTime = Date.now();
|
|
268
419
|
const { path: filePath, offset, limit, encoding = "utf-8" } = args;
|
|
420
|
+
if (!filePath || typeof filePath !== "string") {
|
|
421
|
+
return {
|
|
422
|
+
success: false,
|
|
423
|
+
output: "",
|
|
424
|
+
error: "Invalid file path provided",
|
|
425
|
+
metadata: { execution_time_ms: Date.now() - startTime }
|
|
426
|
+
};
|
|
427
|
+
}
|
|
428
|
+
const normalizedPath = path3.normalize(filePath);
|
|
429
|
+
try {
|
|
430
|
+
const stats = await stat2(normalizedPath);
|
|
431
|
+
if (stats.isDirectory()) {
|
|
432
|
+
return {
|
|
433
|
+
success: false,
|
|
434
|
+
output: "",
|
|
435
|
+
error: `Path is a directory, not a file: ${normalizedPath}`,
|
|
436
|
+
metadata: { execution_time_ms: Date.now() - startTime }
|
|
437
|
+
};
|
|
438
|
+
}
|
|
439
|
+
} catch (error) {
|
|
440
|
+
if (error.code === "ENOENT") {
|
|
441
|
+
return {
|
|
442
|
+
success: false,
|
|
443
|
+
output: "",
|
|
444
|
+
error: `File not found: ${normalizedPath}`,
|
|
445
|
+
metadata: { execution_time_ms: Date.now() - startTime }
|
|
446
|
+
};
|
|
447
|
+
}
|
|
448
|
+
return {
|
|
449
|
+
success: false,
|
|
450
|
+
output: "",
|
|
451
|
+
error: error instanceof Error ? error.message : String(error),
|
|
452
|
+
metadata: { execution_time_ms: Date.now() - startTime }
|
|
453
|
+
};
|
|
454
|
+
}
|
|
269
455
|
try {
|
|
270
|
-
const
|
|
456
|
+
const contentBuffer = await readFile(normalizedPath);
|
|
457
|
+
let contentStr;
|
|
458
|
+
if (encoding === "base64") {
|
|
459
|
+
contentStr = contentBuffer.toString("base64");
|
|
460
|
+
} else {
|
|
461
|
+
contentStr = contentBuffer.toString("utf-8");
|
|
462
|
+
}
|
|
271
463
|
let output;
|
|
272
|
-
const contentBuffer = content;
|
|
273
|
-
const contentStr = typeof contentBuffer === "string" ? contentBuffer : contentBuffer.toString(encoding);
|
|
274
464
|
if (offset !== undefined || limit !== undefined) {
|
|
275
|
-
const lines = contentStr.split(
|
|
276
|
-
`);
|
|
465
|
+
const lines = contentStr.split(/\r?\n/);
|
|
277
466
|
const startLine = offset || 0;
|
|
278
|
-
const endLine = limit ? startLine + limit : lines.length;
|
|
467
|
+
const endLine = limit !== undefined ? Math.min(startLine + limit, lines.length) : lines.length;
|
|
468
|
+
if (startLine >= lines.length) {
|
|
469
|
+
return {
|
|
470
|
+
success: false,
|
|
471
|
+
output: "",
|
|
472
|
+
error: `Offset ${offset} is beyond file length (${lines.length} lines)`,
|
|
473
|
+
metadata: { execution_time_ms: Date.now() - startTime }
|
|
474
|
+
};
|
|
475
|
+
}
|
|
279
476
|
output = lines.slice(startLine, endLine).join(`
|
|
280
477
|
`);
|
|
281
478
|
} else {
|
|
@@ -287,7 +484,7 @@ var readFileTool = {
|
|
|
287
484
|
metadata: {
|
|
288
485
|
execution_time_ms: Date.now() - startTime,
|
|
289
486
|
output_size: output.length,
|
|
290
|
-
file_path:
|
|
487
|
+
file_path: normalizedPath
|
|
291
488
|
}
|
|
292
489
|
};
|
|
293
490
|
} catch (error) {
|
|
@@ -305,8 +502,8 @@ var readFileTool = {
|
|
|
305
502
|
|
|
306
503
|
// src/env/tool/built-in/write-file.ts
|
|
307
504
|
import { z as z4 } from "zod";
|
|
308
|
-
import { writeFile, mkdir } from "fs/promises";
|
|
309
|
-
import
|
|
505
|
+
import { writeFile, mkdir, stat as stat3 } from "fs/promises";
|
|
506
|
+
import path4 from "path";
|
|
310
507
|
var writeFileTool = {
|
|
311
508
|
name: "write_file",
|
|
312
509
|
description: "Write content to a file. Use this to create new files or overwrite existing ones.",
|
|
@@ -331,24 +528,53 @@ var writeFileTool = {
|
|
|
331
528
|
metadata: {
|
|
332
529
|
category: "file",
|
|
333
530
|
tags: ["write", "file", "io", "create"],
|
|
334
|
-
version: "1.
|
|
531
|
+
version: "1.1.0"
|
|
335
532
|
},
|
|
336
533
|
execute: async (args, ctx) => {
|
|
337
534
|
const startTime = Date.now();
|
|
338
535
|
const { path: filePath, content, createDirs = false, append = false } = args;
|
|
536
|
+
if (!filePath || typeof filePath !== "string") {
|
|
537
|
+
return {
|
|
538
|
+
success: false,
|
|
539
|
+
output: "",
|
|
540
|
+
error: "Invalid file path provided",
|
|
541
|
+
metadata: { execution_time_ms: Date.now() - startTime }
|
|
542
|
+
};
|
|
543
|
+
}
|
|
544
|
+
const normalizedPath = path4.normalize(filePath);
|
|
545
|
+
try {
|
|
546
|
+
const stats = await stat3(normalizedPath);
|
|
547
|
+
if (stats.isDirectory()) {
|
|
548
|
+
return {
|
|
549
|
+
success: false,
|
|
550
|
+
output: "",
|
|
551
|
+
error: `Path is a directory, not a file: ${normalizedPath}`,
|
|
552
|
+
metadata: { execution_time_ms: Date.now() - startTime }
|
|
553
|
+
};
|
|
554
|
+
}
|
|
555
|
+
} catch (error) {
|
|
556
|
+
if (error.code !== "ENOENT") {
|
|
557
|
+
return {
|
|
558
|
+
success: false,
|
|
559
|
+
output: "",
|
|
560
|
+
error: error instanceof Error ? error.message : String(error),
|
|
561
|
+
metadata: { execution_time_ms: Date.now() - startTime }
|
|
562
|
+
};
|
|
563
|
+
}
|
|
564
|
+
}
|
|
339
565
|
try {
|
|
340
566
|
if (createDirs) {
|
|
341
|
-
await mkdir(dirname(
|
|
567
|
+
await mkdir(path4.dirname(normalizedPath), { recursive: true });
|
|
342
568
|
}
|
|
343
569
|
const flags = append ? "a" : "w";
|
|
344
|
-
await writeFile(
|
|
570
|
+
await writeFile(normalizedPath, content, { flag: flags });
|
|
345
571
|
return {
|
|
346
572
|
success: true,
|
|
347
|
-
output: append ? `Content appended to: ${
|
|
573
|
+
output: append ? `Content appended to: ${normalizedPath}` : `File written: ${normalizedPath}`,
|
|
348
574
|
metadata: {
|
|
349
575
|
execution_time_ms: Date.now() - startTime,
|
|
350
576
|
output_size: content.length,
|
|
351
|
-
file_path:
|
|
577
|
+
file_path: normalizedPath
|
|
352
578
|
}
|
|
353
579
|
};
|
|
354
580
|
} catch (error) {
|
|
@@ -366,7 +592,9 @@ var writeFileTool = {
|
|
|
366
592
|
|
|
367
593
|
// src/env/tool/built-in/edit-file.ts
|
|
368
594
|
import { z as z5 } from "zod";
|
|
369
|
-
import { readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
|
|
595
|
+
import { readFile as readFile2, writeFile as writeFile2, stat as stat4, unlink } from "fs/promises";
|
|
596
|
+
import path5 from "path";
|
|
597
|
+
import { randomUUID } from "crypto";
|
|
370
598
|
var editFileTool = {
|
|
371
599
|
name: "edit_file",
|
|
372
600
|
description: "Edit a file by replacing specific text. Use this to make targeted changes to files by specifying what to find and what to replace.",
|
|
@@ -391,32 +619,75 @@ var editFileTool = {
|
|
|
391
619
|
metadata: {
|
|
392
620
|
category: "file",
|
|
393
621
|
tags: ["edit", "file", "replace", "modify"],
|
|
394
|
-
version: "1.
|
|
622
|
+
version: "1.1.0"
|
|
395
623
|
},
|
|
396
624
|
execute: async (args, ctx) => {
|
|
397
625
|
const startTime = Date.now();
|
|
398
626
|
const { path: filePath, oldString, newString, replaceAll = false } = args;
|
|
627
|
+
if (!filePath || typeof filePath !== "string") {
|
|
628
|
+
return {
|
|
629
|
+
success: false,
|
|
630
|
+
output: "",
|
|
631
|
+
error: "Invalid file path provided",
|
|
632
|
+
metadata: { execution_time_ms: Date.now() - startTime }
|
|
633
|
+
};
|
|
634
|
+
}
|
|
635
|
+
const normalizedPath = path5.normalize(filePath);
|
|
636
|
+
try {
|
|
637
|
+
const stats = await stat4(normalizedPath);
|
|
638
|
+
if (stats.isDirectory()) {
|
|
639
|
+
return {
|
|
640
|
+
success: false,
|
|
641
|
+
output: "",
|
|
642
|
+
error: `Path is a directory, not a file: ${normalizedPath}`,
|
|
643
|
+
metadata: { execution_time_ms: Date.now() - startTime }
|
|
644
|
+
};
|
|
645
|
+
}
|
|
646
|
+
} catch (error) {
|
|
647
|
+
if (error.code === "ENOENT") {
|
|
648
|
+
return {
|
|
649
|
+
success: false,
|
|
650
|
+
output: "",
|
|
651
|
+
error: `File not found: ${normalizedPath}`,
|
|
652
|
+
metadata: { execution_time_ms: Date.now() - startTime }
|
|
653
|
+
};
|
|
654
|
+
}
|
|
655
|
+
return {
|
|
656
|
+
success: false,
|
|
657
|
+
output: "",
|
|
658
|
+
error: error instanceof Error ? error.message : String(error),
|
|
659
|
+
metadata: { execution_time_ms: Date.now() - startTime }
|
|
660
|
+
};
|
|
661
|
+
}
|
|
399
662
|
try {
|
|
400
|
-
const content = await readFile2(
|
|
401
|
-
const
|
|
663
|
+
const content = await readFile2(normalizedPath, "utf-8");
|
|
664
|
+
const escapedPattern = escapeRegExp(oldString);
|
|
665
|
+
const searchPattern = replaceAll ? new RegExp(escapedPattern, "g") : new RegExp(escapedPattern);
|
|
402
666
|
if (!searchPattern.test(content)) {
|
|
403
667
|
return {
|
|
404
668
|
success: false,
|
|
405
669
|
output: "",
|
|
406
|
-
error: `Could not find "${oldString}" in file ${
|
|
670
|
+
error: `Could not find "${oldString}" in file ${normalizedPath}`,
|
|
407
671
|
metadata: {
|
|
408
672
|
execution_time_ms: Date.now() - startTime
|
|
409
673
|
}
|
|
410
674
|
};
|
|
411
675
|
}
|
|
412
|
-
const newContent = replaceAll ? content.replace(new RegExp(
|
|
413
|
-
|
|
676
|
+
const newContent = replaceAll ? content.replace(new RegExp(escapedPattern, "g"), newString) : content.replace(oldString, newString);
|
|
677
|
+
const tempPath = `${normalizedPath}.${randomUUID()}.tmp`;
|
|
678
|
+
await writeFile2(tempPath, newContent, "utf-8");
|
|
679
|
+
await Bun.write(normalizedPath, newContent);
|
|
680
|
+
try {
|
|
681
|
+
await unlink(tempPath);
|
|
682
|
+
} catch {}
|
|
683
|
+
const count = replaceAll ? (content.match(new RegExp(escapedPattern, "g")) || []).length : content.includes(oldString) ? 1 : 0;
|
|
414
684
|
return {
|
|
415
685
|
success: true,
|
|
416
|
-
output: replaceAll ? `Replaced
|
|
686
|
+
output: replaceAll ? `Replaced ${count} occurrences in: ${normalizedPath}` : `Replaced text in: ${normalizedPath}`,
|
|
417
687
|
metadata: {
|
|
418
688
|
execution_time_ms: Date.now() - startTime,
|
|
419
|
-
file_path:
|
|
689
|
+
file_path: normalizedPath,
|
|
690
|
+
replacements: count
|
|
420
691
|
}
|
|
421
692
|
};
|
|
422
693
|
} catch (error) {
|
|
@@ -437,13 +708,22 @@ function escapeRegExp(string) {
|
|
|
437
708
|
|
|
438
709
|
// src/env/tool/built-in/grep.ts
|
|
439
710
|
import { z as z6 } from "zod";
|
|
440
|
-
import { readFile as readFile3 } from "fs/promises";
|
|
711
|
+
import { readFile as readFile3, stat as stat5 } from "fs/promises";
|
|
441
712
|
import { glob as globAsync2 } from "glob";
|
|
713
|
+
import path6 from "path";
|
|
714
|
+
function isBinaryContent(content) {
|
|
715
|
+
for (let i = 0;i < Math.min(content.length, 8192); i++) {
|
|
716
|
+
if (content[i] === 0) {
|
|
717
|
+
return true;
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
return false;
|
|
721
|
+
}
|
|
442
722
|
var grepTool = {
|
|
443
723
|
name: "grep",
|
|
444
724
|
description: "Search for text patterns in files. Use this to find specific strings, code patterns, or content across multiple files.",
|
|
445
725
|
parameters: z6.object({
|
|
446
|
-
pattern: z6.string().describe("The pattern to search for"),
|
|
726
|
+
pattern: z6.string().min(1).describe("The pattern to search for"),
|
|
447
727
|
path: z6.string().optional().describe("File or directory path to search in"),
|
|
448
728
|
include: z6.string().optional().describe("Glob pattern for files to include (e.g., *.ts, *.js)"),
|
|
449
729
|
caseSensitive: z6.boolean().default(true).optional().describe("Whether the search should be case sensitive"),
|
|
@@ -456,7 +736,7 @@ var grepTool = {
|
|
|
456
736
|
metadata: {
|
|
457
737
|
category: "file",
|
|
458
738
|
tags: ["search", "grep", "find", "pattern"],
|
|
459
|
-
version: "1.
|
|
739
|
+
version: "1.1.0"
|
|
460
740
|
},
|
|
461
741
|
execute: async (args, ctx) => {
|
|
462
742
|
const startTime = Date.now();
|
|
@@ -470,34 +750,69 @@ var grepTool = {
|
|
|
470
750
|
} = args;
|
|
471
751
|
const basePath = searchPath || ctx.workdir || process.cwd();
|
|
472
752
|
try {
|
|
753
|
+
const stats = await stat5(basePath);
|
|
754
|
+
if (!stats.isDirectory() && !stats.isFile()) {
|
|
755
|
+
return {
|
|
756
|
+
success: false,
|
|
757
|
+
output: "",
|
|
758
|
+
error: `Path is neither a file nor a directory: ${basePath}`,
|
|
759
|
+
metadata: { execution_time_ms: Date.now() - startTime }
|
|
760
|
+
};
|
|
761
|
+
}
|
|
762
|
+
} catch (error) {
|
|
763
|
+
return {
|
|
764
|
+
success: false,
|
|
765
|
+
output: "",
|
|
766
|
+
error: error instanceof Error ? error.message : String(error),
|
|
767
|
+
metadata: { execution_time_ms: Date.now() - startTime }
|
|
768
|
+
};
|
|
769
|
+
}
|
|
770
|
+
try {
|
|
771
|
+
const isFile = (await stat5(basePath)).isFile();
|
|
473
772
|
let files = [];
|
|
474
|
-
if (
|
|
475
|
-
files =
|
|
476
|
-
cwd: basePath,
|
|
477
|
-
ignore: ["**/node_modules/**", "**/.git/**"],
|
|
478
|
-
maxDepth: 10
|
|
479
|
-
});
|
|
773
|
+
if (isFile) {
|
|
774
|
+
files = [basePath];
|
|
480
775
|
} else {
|
|
481
|
-
|
|
776
|
+
const globPattern = include || "**/*";
|
|
777
|
+
files = await globAsync2(globPattern, {
|
|
482
778
|
cwd: basePath,
|
|
483
|
-
ignore: ["**/node_modules/**", "**/.git/**"],
|
|
484
|
-
maxDepth: 10
|
|
779
|
+
ignore: ["**/node_modules/**", "**/.git/**", "**/*.min.js", "**/*.map"],
|
|
780
|
+
maxDepth: 10,
|
|
781
|
+
nodir: true
|
|
485
782
|
});
|
|
783
|
+
files = files.map((f) => path6.join(basePath, f));
|
|
486
784
|
}
|
|
487
785
|
const results = [];
|
|
488
786
|
const regexFlags = caseSensitive ? "" : "i";
|
|
489
|
-
|
|
787
|
+
let regex;
|
|
788
|
+
try {
|
|
789
|
+
regex = new RegExp(pattern, regexFlags);
|
|
790
|
+
} catch {
|
|
791
|
+
return {
|
|
792
|
+
success: false,
|
|
793
|
+
output: "",
|
|
794
|
+
error: `Invalid regex pattern: ${pattern}`,
|
|
795
|
+
metadata: { execution_time_ms: Date.now() - startTime }
|
|
796
|
+
};
|
|
797
|
+
}
|
|
490
798
|
for (const file of files) {
|
|
491
799
|
if (results.length >= maxResults)
|
|
492
800
|
break;
|
|
493
801
|
try {
|
|
494
|
-
const
|
|
495
|
-
|
|
496
|
-
|
|
802
|
+
const fileStats = await stat5(file);
|
|
803
|
+
if (fileStats.isDirectory())
|
|
804
|
+
continue;
|
|
805
|
+
const content = await readFile3(file);
|
|
806
|
+
if (isBinaryContent(content))
|
|
807
|
+
continue;
|
|
808
|
+
const textContent = content.toString("utf-8");
|
|
809
|
+
const lines = textContent.split(/\r?\n/);
|
|
497
810
|
for (let i = 0;i < lines.length; i++) {
|
|
811
|
+
regex.lastIndex = 0;
|
|
498
812
|
if (regex.test(lines[i])) {
|
|
499
813
|
const lineNum = showLineNumbers ? `${i + 1}:` : "";
|
|
500
|
-
|
|
814
|
+
const relativePath = path6.relative(basePath, file);
|
|
815
|
+
results.push(`${relativePath}:${lineNum}${lines[i]}`);
|
|
501
816
|
if (results.length >= maxResults)
|
|
502
817
|
break;
|
|
503
818
|
}
|
package/package.json
CHANGED
|
File without changes
|