@arts1234567/arc-code 0.1.0
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/LICENSE +21 -0
- package/README.md +109 -0
- package/bin/arc.js +5 -0
- package/dist/agent/executor.js +78 -0
- package/dist/agent/executor.js.map +1 -0
- package/dist/agent/memory.js +57 -0
- package/dist/agent/memory.js.map +1 -0
- package/dist/agent/orchestrator.js +153 -0
- package/dist/agent/orchestrator.js.map +1 -0
- package/dist/agent/planner.js +26 -0
- package/dist/agent/planner.js.map +1 -0
- package/dist/agent/retriever.js +151 -0
- package/dist/agent/retriever.js.map +1 -0
- package/dist/agent/verifier.js +24 -0
- package/dist/agent/verifier.js.map +1 -0
- package/dist/cli.js +33 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.js +47 -0
- package/dist/config.js.map +1 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/dist/llm/compaction.js +108 -0
- package/dist/llm/compaction.js.map +1 -0
- package/dist/llm/provider.js +201 -0
- package/dist/llm/provider.js.map +1 -0
- package/dist/llm/system.js +40 -0
- package/dist/llm/system.js.map +1 -0
- package/dist/llm/types.js +4 -0
- package/dist/llm/types.js.map +1 -0
- package/dist/run-interactive.js +22 -0
- package/dist/run-interactive.js.map +1 -0
- package/dist/run-single.js +72 -0
- package/dist/run-single.js.map +1 -0
- package/dist/state.js +75 -0
- package/dist/state.js.map +1 -0
- package/dist/tools/delete.js +63 -0
- package/dist/tools/delete.js.map +1 -0
- package/dist/tools/edit.js +67 -0
- package/dist/tools/edit.js.map +1 -0
- package/dist/tools/execute.js +85 -0
- package/dist/tools/execute.js.map +1 -0
- package/dist/tools/index.js +36 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/list.js +66 -0
- package/dist/tools/list.js.map +1 -0
- package/dist/tools/move.js +56 -0
- package/dist/tools/move.js.map +1 -0
- package/dist/tools/read.js +84 -0
- package/dist/tools/read.js.map +1 -0
- package/dist/tools/read_image.js +67 -0
- package/dist/tools/read_image.js.map +1 -0
- package/dist/tools/search.js +177 -0
- package/dist/tools/search.js.map +1 -0
- package/dist/tools/websearch.js +106 -0
- package/dist/tools/websearch.js.map +1 -0
- package/dist/tools/write.js +47 -0
- package/dist/tools/write.js.map +1 -0
- package/dist/ui/ChatWindow.js +143 -0
- package/dist/ui/ChatWindow.js.map +1 -0
- package/dist/ui/InputBar.js +136 -0
- package/dist/ui/InputBar.js.map +1 -0
- package/dist/ui/ThinkingIndicator.js +67 -0
- package/dist/ui/ThinkingIndicator.js.map +1 -0
- package/dist/ui/commands.js +395 -0
- package/dist/ui/commands.js.map +1 -0
- package/dist/ui/mascot.js +41 -0
- package/dist/ui/mascot.js.map +1 -0
- package/dist/ui/theme.js +43 -0
- package/dist/ui/theme.js.map +1 -0
- package/dist/ui/tui.js +297 -0
- package/dist/ui/tui.js.map +1 -0
- package/dist/ui/words.js +161 -0
- package/dist/ui/words.js.map +1 -0
- package/package.json +64 -0
package/dist/state.js
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
// Arc-code State Manager
|
|
2
|
+
// Tracks the conversation, current directory, token count, and a list of
|
|
3
|
+
// recently-known files. Per blueprint's "State Tracking" hard part.
|
|
4
|
+
import { promises as fs } from "fs";
|
|
5
|
+
import * as path from "path";
|
|
6
|
+
import { countTokens } from "./llm/compaction.js";
|
|
7
|
+
import { CONFIG } from "./config.js";
|
|
8
|
+
export class StateManager {
|
|
9
|
+
cwd;
|
|
10
|
+
messages = [];
|
|
11
|
+
iteration = 0;
|
|
12
|
+
working = false;
|
|
13
|
+
workingStatus = "";
|
|
14
|
+
knownFiles = new Set();
|
|
15
|
+
mode = "build";
|
|
16
|
+
// Cache token count to avoid re-encoding on every statusbar render.
|
|
17
|
+
_tokenCache = { count: 0, len: 0 };
|
|
18
|
+
constructor(cwd) {
|
|
19
|
+
this.cwd = cwd;
|
|
20
|
+
}
|
|
21
|
+
get totalTokens() {
|
|
22
|
+
// Only recount if message array length changed (simple dirty check).
|
|
23
|
+
if (this._tokenCache.len !== this.messages.length) {
|
|
24
|
+
this._tokenCache = {
|
|
25
|
+
count: countTokens(this.messages),
|
|
26
|
+
len: this.messages.length,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
return this._tokenCache.count;
|
|
30
|
+
}
|
|
31
|
+
get contextPercent() {
|
|
32
|
+
return Math.min(100, (this.totalTokens / CONFIG.CONTEXT_LIMIT) * 100);
|
|
33
|
+
}
|
|
34
|
+
addMessage(m) {
|
|
35
|
+
this.messages.push(m);
|
|
36
|
+
// Invalidate cache.
|
|
37
|
+
this._tokenCache.len = -1;
|
|
38
|
+
}
|
|
39
|
+
setMessages(m) {
|
|
40
|
+
this.messages = m;
|
|
41
|
+
// Invalidate cache.
|
|
42
|
+
this._tokenCache.len = -1;
|
|
43
|
+
}
|
|
44
|
+
setWorking(b, status = "") {
|
|
45
|
+
this.working = b;
|
|
46
|
+
this.workingStatus = status;
|
|
47
|
+
}
|
|
48
|
+
// Lightweight snapshot of the workspace - used by the retriever and shown
|
|
49
|
+
// in the status bar. Walks the top 2 levels of the cwd.
|
|
50
|
+
async refreshKnownFiles() {
|
|
51
|
+
this.knownFiles.clear();
|
|
52
|
+
await this.walkLevel(this.cwd, 0, 2);
|
|
53
|
+
}
|
|
54
|
+
async walkLevel(dir, depth, max) {
|
|
55
|
+
if (depth > max)
|
|
56
|
+
return;
|
|
57
|
+
let entries;
|
|
58
|
+
try {
|
|
59
|
+
entries = await fs.readdir(dir, { withFileTypes: true });
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
for (const e of entries) {
|
|
65
|
+
if (e.name === "node_modules" || e.name === ".git" || e.name === "dist")
|
|
66
|
+
continue;
|
|
67
|
+
const full = path.join(dir, e.name);
|
|
68
|
+
this.knownFiles.add(full);
|
|
69
|
+
if (e.isDirectory()) {
|
|
70
|
+
await this.walkLevel(full, depth + 1, max);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state.js","sourceRoot":"","sources":["../src/state.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
// delete_file - remove a file or directory from disk.
|
|
2
|
+
import { promises as fs } from "fs";
|
|
3
|
+
import * as path from "path";
|
|
4
|
+
export const deleteFileTool = {
|
|
5
|
+
definition: {
|
|
6
|
+
type: "function",
|
|
7
|
+
function: {
|
|
8
|
+
name: "delete_file",
|
|
9
|
+
description: "Delete a file or an empty/non-empty directory. For directories, pass recursive=true to remove all contents. Use with care — this is permanent.",
|
|
10
|
+
parameters: {
|
|
11
|
+
type: "object",
|
|
12
|
+
properties: {
|
|
13
|
+
path: {
|
|
14
|
+
type: "string",
|
|
15
|
+
description: "Path of the file or directory to delete. Relative paths resolve from cwd.",
|
|
16
|
+
},
|
|
17
|
+
recursive: {
|
|
18
|
+
type: "boolean",
|
|
19
|
+
description: "If true and path is a directory, delete it and all its contents. Default: false.",
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
required: ["path"],
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
execute: async (args, ctx) => {
|
|
27
|
+
if (!args.path || typeof args.path !== "string") {
|
|
28
|
+
return `Error: 'path' must be a string.`;
|
|
29
|
+
}
|
|
30
|
+
const target = path.isAbsolute(args.path)
|
|
31
|
+
? args.path
|
|
32
|
+
: path.resolve(ctx.cwd, args.path);
|
|
33
|
+
try {
|
|
34
|
+
const stat = await fs.stat(target);
|
|
35
|
+
if (stat.isDirectory()) {
|
|
36
|
+
const recursive = args.recursive === true;
|
|
37
|
+
if (!recursive) {
|
|
38
|
+
// try rmdir first (only works when empty)
|
|
39
|
+
await fs.rmdir(target);
|
|
40
|
+
return `Deleted empty directory '${args.path}'.`;
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
await fs.rm(target, { recursive: true, force: true });
|
|
44
|
+
return `Deleted directory '${args.path}' and all its contents.`;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
await fs.unlink(target);
|
|
49
|
+
return `Deleted file '${args.path}'.`;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
catch (err) {
|
|
53
|
+
if (err.code === "ENOENT") {
|
|
54
|
+
return `Error: '${args.path}' does not exist.`;
|
|
55
|
+
}
|
|
56
|
+
if (err.code === "ENOTEMPTY") {
|
|
57
|
+
return `Error: Directory '${args.path}' is not empty. Pass recursive=true to delete it along with its contents.`;
|
|
58
|
+
}
|
|
59
|
+
return `Error deleting '${args.path}': ${err?.message ?? err}`;
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
//# sourceMappingURL=delete.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"delete.js","sourceRoot":"","sources":["../../src/tools/delete.ts"],"names":[],"mappings":"AAAA,sDAAsD;AACtD,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,IAAI,CAAC;AACpC,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAG7B,MAAM,CAAC,MAAM,cAAc,GAAS;IAClC,UAAU,EAAE;QACV,IAAI,EAAE,UAAU;QAChB,QAAQ,EAAE;YACR,IAAI,EAAE,aAAa;YACnB,WAAW,EACT,gJAAgJ;YAClJ,UAAU,EAAE;gBACV,IAAI,EAAE,QAAQ;gBACd,UAAU,EAAE;oBACV,IAAI,EAAE;wBACJ,IAAI,EAAE,QAAQ;wBACd,WAAW,EAAE,2EAA2E;qBACzF;oBACD,SAAS,EAAE;wBACT,IAAI,EAAE,SAAS;wBACf,WAAW,EAAE,kFAAkF;qBAChG;iBACF;gBACD,QAAQ,EAAE,CAAC,MAAM,CAAC;aACnB;SACF;KACF;IACD,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE;QAC3B,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YAChD,OAAO,iCAAiC,CAAC;QAC3C,CAAC;QACD,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC;YACvC,CAAC,CAAC,IAAI,CAAC,IAAI;YACX,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;QAErC,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACnC,IAAI,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;gBACvB,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,KAAK,IAAI,CAAC;gBAC1C,IAAI,CAAC,SAAS,EAAE,CAAC;oBACf,0CAA0C;oBAC1C,MAAM,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;oBACvB,OAAO,4BAA4B,IAAI,CAAC,IAAI,IAAI,CAAC;gBACnD,CAAC;qBAAM,CAAC;oBACN,MAAM,EAAE,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;oBACtD,OAAO,sBAAsB,IAAI,CAAC,IAAI,yBAAyB,CAAC;gBAClE,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,MAAM,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;gBACxB,OAAO,iBAAiB,IAAI,CAAC,IAAI,IAAI,CAAC;YACxC,CAAC;QACH,CAAC;QAAC,OAAO,GAAQ,EAAE,CAAC;YAClB,IAAI,GAAG,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;gBAC1B,OAAO,WAAW,IAAI,CAAC,IAAI,mBAAmB,CAAC;YACjD,CAAC;YACD,IAAI,GAAG,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;gBAC7B,OAAO,qBAAqB,IAAI,CAAC,IAAI,2EAA2E,CAAC;YACnH,CAAC;YACD,OAAO,mBAAmB,IAAI,CAAC,IAAI,MAAM,GAAG,EAAE,OAAO,IAAI,GAAG,EAAE,CAAC;QACjE,CAAC;IACH,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
// edit_file - precise substring replacement in an existing file.
|
|
2
|
+
import { promises as fs } from "fs";
|
|
3
|
+
import * as path from "path";
|
|
4
|
+
export const editFileTool = {
|
|
5
|
+
definition: {
|
|
6
|
+
type: "function",
|
|
7
|
+
function: {
|
|
8
|
+
name: "edit_file",
|
|
9
|
+
description: "Replace a specific substring within a file with new content. Use this for targeted edits to avoid overwriting large files.",
|
|
10
|
+
parameters: {
|
|
11
|
+
type: "object",
|
|
12
|
+
properties: {
|
|
13
|
+
path: {
|
|
14
|
+
type: "string",
|
|
15
|
+
description: "Path to the file to edit. Relative paths resolve from cwd.",
|
|
16
|
+
},
|
|
17
|
+
old_string: {
|
|
18
|
+
type: "string",
|
|
19
|
+
description: "The exact text to be replaced. Must be a unique substring within the file, including whitespace and indentation.",
|
|
20
|
+
},
|
|
21
|
+
new_string: {
|
|
22
|
+
type: "string",
|
|
23
|
+
description: "The text to replace it with.",
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
required: ["path", "old_string", "new_string"],
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
execute: async (args, ctx) => {
|
|
31
|
+
if (!args.path || typeof args.path !== "string") {
|
|
32
|
+
return `Error: 'path' must be a string.`;
|
|
33
|
+
}
|
|
34
|
+
if (typeof args.old_string !== "string" || typeof args.new_string !== "string") {
|
|
35
|
+
return `Error: 'old_string' and 'new_string' must be strings.`;
|
|
36
|
+
}
|
|
37
|
+
const target = path.isAbsolute(args.path)
|
|
38
|
+
? args.path
|
|
39
|
+
: path.resolve(ctx.cwd, args.path);
|
|
40
|
+
try {
|
|
41
|
+
const content = await fs.readFile(target, "utf-8");
|
|
42
|
+
const count = content.split(args.old_string).length - 1;
|
|
43
|
+
if (count === 0) {
|
|
44
|
+
return `Error: Could not find 'old_string' in the file. Make sure you match whitespace and indentation exactly.`;
|
|
45
|
+
}
|
|
46
|
+
if (count > 1) {
|
|
47
|
+
return `Error: 'old_string' matched ${count} times. Provide a larger, more unique block of text to safely replace.`;
|
|
48
|
+
}
|
|
49
|
+
const updated = content.replace(args.old_string, args.new_string);
|
|
50
|
+
await fs.writeFile(target, updated, "utf-8");
|
|
51
|
+
const linesChanged = args.new_string.split('\n').length - args.old_string.split('\n').length;
|
|
52
|
+
const linesInfo = linesChanged > 0
|
|
53
|
+
? `(+${linesChanged} lines)`
|
|
54
|
+
: linesChanged < 0
|
|
55
|
+
? `(${linesChanged} lines)`
|
|
56
|
+
: `(0 lines change)`;
|
|
57
|
+
return `Successfully replaced targeted text in '${args.path}' ${linesInfo}.`;
|
|
58
|
+
}
|
|
59
|
+
catch (err) {
|
|
60
|
+
if (err.code === "ENOENT") {
|
|
61
|
+
return `Error: File '${args.path}' does not exist. Use write_file to create it.`;
|
|
62
|
+
}
|
|
63
|
+
return `Error editing file '${args.path}': ${err?.message ?? err}`;
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
//# sourceMappingURL=edit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"edit.js","sourceRoot":"","sources":["../../src/tools/edit.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
// execute_command - run a shell command and return stdout/stderr/exit code.
|
|
2
|
+
import { spawn } from "child_process";
|
|
3
|
+
const DEFAULT_TIMEOUT_MS = 60_000;
|
|
4
|
+
const MAX_OUTPUT_BYTES = 200_000;
|
|
5
|
+
const isWindows = process.platform === "win32";
|
|
6
|
+
export const executeCommandTool = {
|
|
7
|
+
definition: {
|
|
8
|
+
type: "function",
|
|
9
|
+
function: {
|
|
10
|
+
name: "execute_command",
|
|
11
|
+
description: "Run a shell command and return its stdout, stderr, and exit code. The command is run via the system shell. Use a sensible timeout.",
|
|
12
|
+
parameters: {
|
|
13
|
+
type: "object",
|
|
14
|
+
properties: {
|
|
15
|
+
cmd: {
|
|
16
|
+
type: "string",
|
|
17
|
+
description: "The shell command to execute.",
|
|
18
|
+
},
|
|
19
|
+
timeout_ms: {
|
|
20
|
+
type: "number",
|
|
21
|
+
description: "Optional timeout in milliseconds. Defaults to 60000 (60s).",
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
required: ["cmd"],
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
execute: async (args, ctx) => {
|
|
29
|
+
if (!args.cmd || typeof args.cmd !== "string") {
|
|
30
|
+
return `Error: 'cmd' is required and must be a string.`;
|
|
31
|
+
}
|
|
32
|
+
const cmd = args.cmd;
|
|
33
|
+
const timeout = typeof args.timeout_ms === "number" ? args.timeout_ms : DEFAULT_TIMEOUT_MS;
|
|
34
|
+
const shell = isWindows ? "cmd.exe" : "/bin/sh";
|
|
35
|
+
const shellFlag = isWindows ? "/c" : "-c";
|
|
36
|
+
return new Promise((resolve) => {
|
|
37
|
+
const child = spawn(shell, [shellFlag, cmd], {
|
|
38
|
+
cwd: ctx.cwd,
|
|
39
|
+
env: process.env,
|
|
40
|
+
windowsHide: true,
|
|
41
|
+
});
|
|
42
|
+
let out = "";
|
|
43
|
+
let err = "";
|
|
44
|
+
let killed = false;
|
|
45
|
+
const timer = setTimeout(() => {
|
|
46
|
+
killed = true;
|
|
47
|
+
child.kill();
|
|
48
|
+
}, timeout);
|
|
49
|
+
child.stdout.on("data", (d) => {
|
|
50
|
+
if (out.length < MAX_OUTPUT_BYTES) {
|
|
51
|
+
out += d.toString();
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
child.stderr.on("data", (d) => {
|
|
55
|
+
if (err.length < MAX_OUTPUT_BYTES) {
|
|
56
|
+
err += d.toString();
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
child.on("error", (e) => {
|
|
60
|
+
clearTimeout(timer);
|
|
61
|
+
resolve(`Error spawning command: ${e.message}`);
|
|
62
|
+
});
|
|
63
|
+
child.on("close", (code) => {
|
|
64
|
+
clearTimeout(timer);
|
|
65
|
+
let result = "";
|
|
66
|
+
if (killed) {
|
|
67
|
+
result += `[Command killed after ${timeout}ms timeout]\n`;
|
|
68
|
+
}
|
|
69
|
+
if (out)
|
|
70
|
+
result += `--- stdout ---\n${out}`;
|
|
71
|
+
if (err)
|
|
72
|
+
result += `${out ? "\n" : ""}--- stderr ---\n${err}`;
|
|
73
|
+
result += `${result ? "\n" : ""}[exit code: ${code}]`;
|
|
74
|
+
if (out.length >= MAX_OUTPUT_BYTES) {
|
|
75
|
+
result += `\n[stdout truncated at ${MAX_OUTPUT_BYTES} bytes]`;
|
|
76
|
+
}
|
|
77
|
+
if (err.length >= MAX_OUTPUT_BYTES) {
|
|
78
|
+
result += `\n[stderr truncated at ${MAX_OUTPUT_BYTES} bytes]`;
|
|
79
|
+
}
|
|
80
|
+
resolve(result);
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
},
|
|
84
|
+
};
|
|
85
|
+
//# sourceMappingURL=execute.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"execute.js","sourceRoot":"","sources":["../../src/tools/execute.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAGtC,MAAM,kBAAkB,GAAG,MAAM,CAAC;AAClC,MAAM,gBAAgB,GAAG,OAAO,CAAC;AACjC,MAAM,SAAS,GAAG,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC;AAE/C,MAAM,CAAC,MAAM,kBAAkB,GAAS;IACtC,UAAU,EAAE;QACV,IAAI,EAAE,UAAU;QAChB,QAAQ,EAAE;YACR,IAAI,EAAE,iBAAiB;YACvB,WAAW,EACT,oIAAoI;YACtI,UAAU,EAAE;gBACV,IAAI,EAAE,QAAQ;gBACd,UAAU,EAAE;oBACV,GAAG,EAAE;wBACH,IAAI,EAAE,QAAQ;wBACd,WAAW,EAAE,+BAA+B;qBAC7C;oBACD,UAAU,EAAE;wBACV,IAAI,EAAE,QAAQ;wBACd,WAAW,EAAE,4DAA4D;qBAC1E;iBACF;gBACD,QAAQ,EAAE,CAAC,KAAK,CAAC;aAClB;SACF;KACF;IACD,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE;QAC3B,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,OAAO,IAAI,CAAC,GAAG,KAAK,QAAQ,EAAE,CAAC;YAC9C,OAAO,gDAAgD,CAAC;QAC1D,CAAC;QACD,MAAM,GAAG,GAAW,IAAI,CAAC,GAAG,CAAC;QAC7B,MAAM,OAAO,GAAW,OAAO,IAAI,CAAC,UAAU,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,kBAAkB,CAAC;QACnG,MAAM,KAAK,GAAG,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;QAChD,MAAM,SAAS,GAAG,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;QAE1C,OAAO,IAAI,OAAO,CAAS,CAAC,OAAO,EAAE,EAAE;YACrC,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,EAAE,CAAC,SAAS,EAAE,GAAG,CAAC,EAAE;gBAC3C,GAAG,EAAE,GAAG,CAAC,GAAG;gBACZ,GAAG,EAAE,OAAO,CAAC,GAAG;gBAChB,WAAW,EAAE,IAAI;aAClB,CAAC,CAAC;YAEH,IAAI,GAAG,GAAG,EAAE,CAAC;YACb,IAAI,GAAG,GAAG,EAAE,CAAC;YACb,IAAI,MAAM,GAAG,KAAK,CAAC;YAEnB,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;gBAC5B,MAAM,GAAG,IAAI,CAAC;gBACd,KAAK,CAAC,IAAI,EAAE,CAAC;YACf,CAAC,EAAE,OAAO,CAAC,CAAC;YAEZ,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE;gBAC5B,IAAI,GAAG,CAAC,MAAM,GAAG,gBAAgB,EAAE,CAAC;oBAClC,GAAG,IAAI,CAAC,CAAC,QAAQ,EAAE,CAAC;gBACtB,CAAC;YACH,CAAC,CAAC,CAAC;YACH,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE;gBAC5B,IAAI,GAAG,CAAC,MAAM,GAAG,gBAAgB,EAAE,CAAC;oBAClC,GAAG,IAAI,CAAC,CAAC,QAAQ,EAAE,CAAC;gBACtB,CAAC;YACH,CAAC,CAAC,CAAC;YAEH,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE;gBACtB,YAAY,CAAC,KAAK,CAAC,CAAC;gBACpB,OAAO,CAAC,2BAA2B,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;YAClD,CAAC,CAAC,CAAC;YAEH,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE;gBACzB,YAAY,CAAC,KAAK,CAAC,CAAC;gBACpB,IAAI,MAAM,GAAG,EAAE,CAAC;gBAChB,IAAI,MAAM,EAAE,CAAC;oBACX,MAAM,IAAI,yBAAyB,OAAO,eAAe,CAAC;gBAC5D,CAAC;gBACD,IAAI,GAAG;oBAAE,MAAM,IAAI,mBAAmB,GAAG,EAAE,CAAC;gBAC5C,IAAI,GAAG;oBAAE,MAAM,IAAI,GAAG,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,mBAAmB,GAAG,EAAE,CAAC;gBAC9D,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,eAAe,IAAI,GAAG,CAAC;gBACtD,IAAI,GAAG,CAAC,MAAM,IAAI,gBAAgB,EAAE,CAAC;oBACnC,MAAM,IAAI,0BAA0B,gBAAgB,SAAS,CAAC;gBAChE,CAAC;gBACD,IAAI,GAAG,CAAC,MAAM,IAAI,gBAAgB,EAAE,CAAC;oBACnC,MAAM,IAAI,0BAA0B,gBAAgB,SAAS,CAAC;gBAChE,CAAC;gBACD,OAAO,CAAC,MAAM,CAAC,CAAC;YAClB,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// Arc-code Tools
|
|
2
|
+
// Available tools:
|
|
3
|
+
// read_file, write_file, edit_file, delete_file, move_file,
|
|
4
|
+
// list_directory, search_files, execute_command, web_search, read_image
|
|
5
|
+
import { readFileTool } from "./read.js";
|
|
6
|
+
import { writeFileTool } from "./write.js";
|
|
7
|
+
import { editFileTool } from "./edit.js";
|
|
8
|
+
import { deleteFileTool } from "./delete.js";
|
|
9
|
+
import { moveFileTool } from "./move.js";
|
|
10
|
+
import { listDirectoryTool } from "./list.js";
|
|
11
|
+
import { searchFilesTool } from "./search.js";
|
|
12
|
+
import { executeCommandTool } from "./execute.js";
|
|
13
|
+
import { webSearchTool } from "./websearch.js";
|
|
14
|
+
import { readImageTool } from "./read_image.js";
|
|
15
|
+
const tools = {
|
|
16
|
+
read_file: readFileTool,
|
|
17
|
+
write_file: writeFileTool,
|
|
18
|
+
edit_file: editFileTool,
|
|
19
|
+
delete_file: deleteFileTool,
|
|
20
|
+
move_file: moveFileTool,
|
|
21
|
+
list_directory: listDirectoryTool,
|
|
22
|
+
search_files: searchFilesTool,
|
|
23
|
+
execute_command: executeCommandTool,
|
|
24
|
+
web_search: webSearchTool,
|
|
25
|
+
read_image: readImageTool,
|
|
26
|
+
};
|
|
27
|
+
export function getTool(name) {
|
|
28
|
+
return tools[name];
|
|
29
|
+
}
|
|
30
|
+
export function listToolNames() {
|
|
31
|
+
return Object.keys(tools);
|
|
32
|
+
}
|
|
33
|
+
export function getAllDefinitions() {
|
|
34
|
+
return Object.values(tools).map((t) => t.definition);
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA,iBAAiB;AACjB,mBAAmB;AACnB,8DAA8D;AAC9D,0EAA0E;AAyB1E,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAEhD,MAAM,KAAK,GAA2B;IACpC,SAAS,EAAE,YAAY;IACvB,UAAU,EAAE,aAAa;IACzB,SAAS,EAAE,YAAY;IACvB,WAAW,EAAE,cAAc;IAC3B,SAAS,EAAE,YAAY;IACvB,cAAc,EAAE,iBAAiB;IACjC,YAAY,EAAE,eAAe;IAC7B,eAAe,EAAE,kBAAkB;IACnC,UAAU,EAAE,aAAa;IACzB,UAAU,EAAE,aAAa;CAC1B,CAAC;AAEF,MAAM,UAAU,OAAO,CAAC,IAAY;IAClC,OAAO,KAAK,CAAC,IAAgB,CAAC,CAAC;AACjC,CAAC;AAED,MAAM,UAAU,aAAa;IAC3B,OAAO,MAAM,CAAC,IAAI,CAAC,KAAK,CAAe,CAAC;AAC1C,CAAC;AAED,MAAM,UAAU,iBAAiB;IAC/B,OAAO,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;AACvD,CAAC"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
// list_directory - list immediate entries of a directory.
|
|
2
|
+
import { promises as fs } from "fs";
|
|
3
|
+
import * as path from "path";
|
|
4
|
+
import { isBinaryFile } from "./read.js";
|
|
5
|
+
const MAX_ENTRIES = 500;
|
|
6
|
+
export const listDirectoryTool = {
|
|
7
|
+
definition: {
|
|
8
|
+
type: "function",
|
|
9
|
+
function: {
|
|
10
|
+
name: "list_directory",
|
|
11
|
+
description: "List the immediate entries (files and subdirectories) of a directory. Hidden files (starting with '.') are included. Only lists text files (source code, logs, configs) — binary files like images are excluded.",
|
|
12
|
+
parameters: {
|
|
13
|
+
type: "object",
|
|
14
|
+
properties: {
|
|
15
|
+
path: {
|
|
16
|
+
type: "string",
|
|
17
|
+
description: "Directory to list. Defaults to the current working directory if omitted.",
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
execute: async (args, ctx) => {
|
|
24
|
+
if (args.path !== undefined && typeof args.path !== "string") {
|
|
25
|
+
return `Error: 'path' must be a string if provided.`;
|
|
26
|
+
}
|
|
27
|
+
const target = args.path
|
|
28
|
+
? path.isAbsolute(args.path)
|
|
29
|
+
? args.path
|
|
30
|
+
: path.resolve(ctx.cwd, args.path)
|
|
31
|
+
: ctx.cwd;
|
|
32
|
+
try {
|
|
33
|
+
const stat = await fs.stat(target);
|
|
34
|
+
if (!stat.isDirectory()) {
|
|
35
|
+
return `Error: '${args.path ?? "."}' is not a directory.`;
|
|
36
|
+
}
|
|
37
|
+
const entries = await fs.readdir(target, { withFileTypes: true });
|
|
38
|
+
const sorted = entries
|
|
39
|
+
.filter((e) => e.isDirectory() || !isBinaryFile(e.name))
|
|
40
|
+
.map((e) => ({
|
|
41
|
+
name: e.name,
|
|
42
|
+
kind: e.isDirectory() ? "dir" : "file",
|
|
43
|
+
}))
|
|
44
|
+
.sort((a, b) => {
|
|
45
|
+
if (a.kind !== b.kind)
|
|
46
|
+
return a.kind === "dir" ? -1 : 1;
|
|
47
|
+
return a.name.localeCompare(b.name);
|
|
48
|
+
});
|
|
49
|
+
const shown = sorted.slice(0, MAX_ENTRIES);
|
|
50
|
+
const lines = shown.map((e) => e.kind === "dir" ? `[d] ${e.name}` : ` ${e.name}`);
|
|
51
|
+
let out = lines.join("\n");
|
|
52
|
+
const binarySkipped = entries.length - sorted.length;
|
|
53
|
+
if (binarySkipped > 0) {
|
|
54
|
+
out += `\n\n[${binarySkipped} binary file(s) omitted]`;
|
|
55
|
+
}
|
|
56
|
+
if (sorted.length > MAX_ENTRIES) {
|
|
57
|
+
out += `\n\n[... ${sorted.length - MAX_ENTRIES} more entries]`;
|
|
58
|
+
}
|
|
59
|
+
return out;
|
|
60
|
+
}
|
|
61
|
+
catch (err) {
|
|
62
|
+
return `Error listing directory '${args.path ?? "."}': ${err?.message ?? err}`;
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
//# sourceMappingURL=list.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list.js","sourceRoot":"","sources":["../../src/tools/list.ts"],"names":[],"mappings":"AAAA,0DAA0D;AAC1D,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,IAAI,CAAC;AACpC,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAE7B,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAEzC,MAAM,WAAW,GAAG,GAAG,CAAC;AAExB,MAAM,CAAC,MAAM,iBAAiB,GAAS;IACrC,UAAU,EAAE;QACV,IAAI,EAAE,UAAU;QAChB,QAAQ,EAAE;YACR,IAAI,EAAE,gBAAgB;YACtB,WAAW,EACT,kNAAkN;YACpN,UAAU,EAAE;gBACV,IAAI,EAAE,QAAQ;gBACd,UAAU,EAAE;oBACV,IAAI,EAAE;wBACJ,IAAI,EAAE,QAAQ;wBACd,WAAW,EAAE,0EAA0E;qBACxF;iBACF;aACF;SACF;KACF;IACD,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE;QAC3B,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,IAAI,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YAC7D,OAAO,6CAA6C,CAAC;QACvD,CAAC;QACD,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI;YACtB,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC;gBAC1B,CAAC,CAAC,IAAI,CAAC,IAAI;gBACX,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,CAAC;YACpC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC;QACZ,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACnC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;gBACxB,OAAO,WAAW,IAAI,CAAC,IAAI,IAAI,GAAG,uBAAuB,CAAC;YAC5D,CAAC;YACD,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;YAClE,MAAM,MAAM,GAAG,OAAO;iBACnB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;iBACvD,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;gBACX,IAAI,EAAE,CAAC,CAAC,IAAI;gBACZ,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM;aACvC,CAAC,CAAC;iBACF,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;gBACb,IAAI,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,IAAI;oBAAE,OAAO,CAAC,CAAC,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;gBACxD,OAAO,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;YACtC,CAAC,CAAC,CAAC;YAEL,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC;YAC3C,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAC5B,CAAC,CAAC,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,CACrD,CAAC;YACF,IAAI,GAAG,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC3B,MAAM,aAAa,GAAG,OAAO,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;YACrD,IAAI,aAAa,GAAG,CAAC,EAAE,CAAC;gBACtB,GAAG,IAAI,QAAQ,aAAa,0BAA0B,CAAC;YACzD,CAAC;YACD,IAAI,MAAM,CAAC,MAAM,GAAG,WAAW,EAAE,CAAC;gBAChC,GAAG,IAAI,YAAY,MAAM,CAAC,MAAM,GAAG,WAAW,gBAAgB,CAAC;YACjE,CAAC;YACD,OAAO,GAAG,CAAC;QACb,CAAC;QAAC,OAAO,GAAQ,EAAE,CAAC;YAClB,OAAO,4BAA4B,IAAI,CAAC,IAAI,IAAI,GAAG,MAAM,GAAG,EAAE,OAAO,IAAI,GAAG,EAAE,CAAC;QACjF,CAAC;IACH,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
// move_file - rename or move a file/directory.
|
|
2
|
+
import { promises as fs } from "fs";
|
|
3
|
+
import * as path from "path";
|
|
4
|
+
export const moveFileTool = {
|
|
5
|
+
definition: {
|
|
6
|
+
type: "function",
|
|
7
|
+
function: {
|
|
8
|
+
name: "move_file",
|
|
9
|
+
description: "Move or rename a file or directory. The destination parent directory will be created if it does not exist.",
|
|
10
|
+
parameters: {
|
|
11
|
+
type: "object",
|
|
12
|
+
properties: {
|
|
13
|
+
source: {
|
|
14
|
+
type: "string",
|
|
15
|
+
description: "The path of the file or directory to move. Relative paths resolve from cwd.",
|
|
16
|
+
},
|
|
17
|
+
destination: {
|
|
18
|
+
type: "string",
|
|
19
|
+
description: "The destination path. Relative paths resolve from cwd.",
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
required: ["source", "destination"],
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
execute: async (args, ctx) => {
|
|
27
|
+
if (!args.source || typeof args.source !== "string") {
|
|
28
|
+
return `Error: 'source' must be a string.`;
|
|
29
|
+
}
|
|
30
|
+
if (!args.destination || typeof args.destination !== "string") {
|
|
31
|
+
return `Error: 'destination' must be a string.`;
|
|
32
|
+
}
|
|
33
|
+
const src = path.isAbsolute(args.source)
|
|
34
|
+
? args.source
|
|
35
|
+
: path.resolve(ctx.cwd, args.source);
|
|
36
|
+
const dst = path.isAbsolute(args.destination)
|
|
37
|
+
? args.destination
|
|
38
|
+
: path.resolve(ctx.cwd, args.destination);
|
|
39
|
+
try {
|
|
40
|
+
// Ensure parent directory of destination exists
|
|
41
|
+
await fs.mkdir(path.dirname(dst), { recursive: true });
|
|
42
|
+
await fs.rename(src, dst);
|
|
43
|
+
return `Moved '${args.source}' → '${args.destination}'.`;
|
|
44
|
+
}
|
|
45
|
+
catch (err) {
|
|
46
|
+
if (err.code === "ENOENT") {
|
|
47
|
+
return `Error: Source '${args.source}' does not exist.`;
|
|
48
|
+
}
|
|
49
|
+
if (err.code === "EEXIST" || err.code === "ENOTEMPTY") {
|
|
50
|
+
return `Error: Destination '${args.destination}' already exists.`;
|
|
51
|
+
}
|
|
52
|
+
return `Error moving '${args.source}' to '${args.destination}': ${err?.message ?? err}`;
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
//# sourceMappingURL=move.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"move.js","sourceRoot":"","sources":["../../src/tools/move.ts"],"names":[],"mappings":"AAAA,+CAA+C;AAC/C,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,IAAI,CAAC;AACpC,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAG7B,MAAM,CAAC,MAAM,YAAY,GAAS;IAChC,UAAU,EAAE;QACV,IAAI,EAAE,UAAU;QAChB,QAAQ,EAAE;YACR,IAAI,EAAE,WAAW;YACjB,WAAW,EACT,4GAA4G;YAC9G,UAAU,EAAE;gBACV,IAAI,EAAE,QAAQ;gBACd,UAAU,EAAE;oBACV,MAAM,EAAE;wBACN,IAAI,EAAE,QAAQ;wBACd,WAAW,EAAE,6EAA6E;qBAC3F;oBACD,WAAW,EAAE;wBACX,IAAI,EAAE,QAAQ;wBACd,WAAW,EAAE,wDAAwD;qBACtE;iBACF;gBACD,QAAQ,EAAE,CAAC,QAAQ,EAAE,aAAa,CAAC;aACpC;SACF;KACF;IACD,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE;QAC3B,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,OAAO,IAAI,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;YACpD,OAAO,mCAAmC,CAAC;QAC7C,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,WAAW,IAAI,OAAO,IAAI,CAAC,WAAW,KAAK,QAAQ,EAAE,CAAC;YAC9D,OAAO,wCAAwC,CAAC;QAClD,CAAC;QAED,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC;YACtC,CAAC,CAAC,IAAI,CAAC,MAAM;YACb,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;QACvC,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,WAAW,CAAC;YAC3C,CAAC,CAAC,IAAI,CAAC,WAAW;YAClB,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;QAE5C,IAAI,CAAC;YACH,gDAAgD;YAChD,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YACvD,MAAM,EAAE,CAAC,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;YAC1B,OAAO,UAAU,IAAI,CAAC,MAAM,QAAQ,IAAI,CAAC,WAAW,IAAI,CAAC;QAC3D,CAAC;QAAC,OAAO,GAAQ,EAAE,CAAC;YAClB,IAAI,GAAG,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;gBAC1B,OAAO,kBAAkB,IAAI,CAAC,MAAM,mBAAmB,CAAC;YAC1D,CAAC;YACD,IAAI,GAAG,CAAC,IAAI,KAAK,QAAQ,IAAI,GAAG,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;gBACtD,OAAO,uBAAuB,IAAI,CAAC,WAAW,mBAAmB,CAAC;YACpE,CAAC;YACD,OAAO,iBAAiB,IAAI,CAAC,MAAM,SAAS,IAAI,CAAC,WAAW,MAAM,GAAG,EAAE,OAAO,IAAI,GAAG,EAAE,CAAC;QAC1F,CAAC;IACH,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
// read_file - read the contents of a file (text files only).
|
|
2
|
+
import { promises as fs } from "fs";
|
|
3
|
+
import * as path from "path";
|
|
4
|
+
const MAX_BYTES = 200_000;
|
|
5
|
+
export const BINARY_EXTENSIONS = new Set([
|
|
6
|
+
".png", ".jpg", ".jpeg", ".gif", ".bmp", ".ico", ".webp", ".svgz",
|
|
7
|
+
".exe", ".dll", ".so", ".dylib", ".wasm",
|
|
8
|
+
".zip", ".tar", ".gz", ".bz2", ".7z", ".rar",
|
|
9
|
+
".bin", ".o", ".a", ".lib", ".class", ".pyc", ".pyd",
|
|
10
|
+
".woff", ".woff2", ".ttf", ".eot",
|
|
11
|
+
".mp3", ".mp4", ".avi", ".mov", ".wmv", ".flv", ".webm",
|
|
12
|
+
".pdf", ".doc", ".docx", ".xls", ".xlsx", ".ppt", ".pptx",
|
|
13
|
+
".ico", ".cur",
|
|
14
|
+
]);
|
|
15
|
+
const BINARY_CHECK_SIZE = 512;
|
|
16
|
+
export function isBinaryFile(p) {
|
|
17
|
+
const ext = path.extname(p).toLowerCase();
|
|
18
|
+
return BINARY_EXTENSIONS.has(ext);
|
|
19
|
+
}
|
|
20
|
+
function hasNullBytes(buf) {
|
|
21
|
+
const checkLen = Math.min(buf.length, BINARY_CHECK_SIZE);
|
|
22
|
+
for (let i = 0; i < checkLen; i++) {
|
|
23
|
+
if (buf[i] === 0)
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
export const readFileTool = {
|
|
29
|
+
definition: {
|
|
30
|
+
type: "function",
|
|
31
|
+
function: {
|
|
32
|
+
name: "read_file",
|
|
33
|
+
description: "Read the contents of a text file at the given path. Only works on text-based files (source code, config, markdown, logs, etc). Cannot read binary files like images, archives, or executables.",
|
|
34
|
+
parameters: {
|
|
35
|
+
type: "object",
|
|
36
|
+
properties: {
|
|
37
|
+
path: {
|
|
38
|
+
type: "string",
|
|
39
|
+
description: "Path to the file to read. Relative paths are resolved from the current working directory.",
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
required: ["path"],
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
execute: async (args, ctx) => {
|
|
47
|
+
if (!args.path || typeof args.path !== "string") {
|
|
48
|
+
return `Error: 'path' is required and must be a string.`;
|
|
49
|
+
}
|
|
50
|
+
// Reject known binary extensions by filename before checking disk.
|
|
51
|
+
if (isBinaryFile(args.path)) {
|
|
52
|
+
return `Error: cannot read '${args.path}' — it appears to be a binary/image file. This tool only reads text files (source code, logs, configs). Use list_directory to find text-only files.`;
|
|
53
|
+
}
|
|
54
|
+
const target = resolvePath(args.path, ctx.cwd);
|
|
55
|
+
try {
|
|
56
|
+
const stat = await fs.stat(target);
|
|
57
|
+
if (stat.isDirectory()) {
|
|
58
|
+
return `Error: '${args.path}' is a directory, not a file. Use list_directory instead.`;
|
|
59
|
+
}
|
|
60
|
+
const buf = await fs.readFile(target);
|
|
61
|
+
// Also check magic bytes for unknown binary formats.
|
|
62
|
+
if (hasNullBytes(buf)) {
|
|
63
|
+
return `Error: cannot read '${args.path}' — it appears to be a binary/image file. This tool only reads text files. Use list_directory to find text-only files.`;
|
|
64
|
+
}
|
|
65
|
+
if (buf.length > MAX_BYTES) {
|
|
66
|
+
const truncated = buf.slice(0, MAX_BYTES).toString("utf-8");
|
|
67
|
+
return `${truncated}\n\n[... truncated, file is ${buf.length} bytes]`;
|
|
68
|
+
}
|
|
69
|
+
return buf.toString("utf-8");
|
|
70
|
+
}
|
|
71
|
+
catch (err) {
|
|
72
|
+
return `Error reading file '${args.path}': ${err?.message ?? err}`;
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
function resolvePath(p, cwd) {
|
|
77
|
+
if (typeof p !== "string" || p.length === 0) {
|
|
78
|
+
return cwd;
|
|
79
|
+
}
|
|
80
|
+
if (path.isAbsolute(p))
|
|
81
|
+
return p;
|
|
82
|
+
return path.resolve(cwd, p);
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=read.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"read.js","sourceRoot":"","sources":["../../src/tools/read.ts"],"names":[],"mappings":"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"}
|