@datename/fastcode-termux 0.1.6-beta → 0.1.6
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 +6 -24
- package/dist/agent/guards.d.ts +0 -8
- package/dist/agent/guards.js +0 -195
- package/dist/agent/protocol.js +1 -4
- package/dist/agent/tools.d.ts +1 -3
- package/dist/agent/tools.js +377 -2
- package/dist/app.js +103 -335
- package/dist/cli.js +311 -362
- package/dist/commands/index.js +0 -22
- package/dist/commands/login.d.ts +2 -4
- package/dist/commands/login.js +10 -12
- package/dist/commands/logout.js +16 -8
- package/dist/commands/model.d.ts +0 -13
- package/dist/commands/model.js +22 -42
- package/dist/commands/provider.d.ts +0 -13
- package/dist/commands/provider.js +9 -20
- package/dist/commands/whoami.js +5 -6
- package/dist/config/store.d.ts +12 -32
- package/dist/config/store.js +65 -117
- package/dist/config/trust.d.ts +8 -21
- package/dist/config/trust.js +13 -99
- package/dist/lib/diagnostics.d.ts +4 -29
- package/dist/lib/diagnostics.js +4 -60
- package/dist/lib/http.d.ts +1 -11
- package/dist/lib/http.js +4 -62
- package/dist/providers/anthropic.d.ts +0 -1
- package/dist/providers/anthropic.js +0 -12
- package/dist/providers/custom.d.ts +0 -9
- package/dist/providers/deepseek.d.ts +0 -10
- package/dist/providers/deepseek.js +1 -2
- package/dist/providers/google.d.ts +0 -9
- package/dist/providers/groq.d.ts +0 -10
- package/dist/providers/groq.js +1 -2
- package/dist/providers/index.d.ts +201 -10
- package/dist/providers/index.js +0 -30
- package/dist/providers/mistral.d.ts +0 -10
- package/dist/providers/mistral.js +1 -2
- package/dist/providers/moonshot.d.ts +0 -10
- package/dist/providers/moonshot.js +1 -2
- package/dist/providers/ollama.d.ts +0 -9
- package/dist/providers/openai.d.ts +0 -10
- package/dist/providers/openai.js +1 -2
- package/dist/providers/openaiCompatible.d.ts +0 -9
- package/dist/providers/openaiCompatible.js +10 -58
- package/dist/providers/openrouter.d.ts +0 -10
- package/dist/providers/openrouter.js +1 -2
- package/dist/providers/qwen.d.ts +0 -10
- package/dist/providers/qwen.js +1 -2
- package/dist/providers/xai.d.ts +0 -10
- package/dist/providers/xai.js +1 -2
- package/dist/providers/zhipu.d.ts +0 -10
- package/dist/providers/zhipu.js +1 -2
- package/dist/session/log.d.ts +12 -35
- package/dist/session/log.js +10 -206
- package/dist/types.d.ts +1 -60
- package/dist/ui/Message.d.ts +7 -1
- package/dist/ui/Message.js +2 -13
- package/dist/ui/Prompt.d.ts +2 -1
- package/dist/ui/Prompt.js +2 -2
- package/dist/ui/Spinner.js +5 -11
- package/dist/ui/StatusBar.d.ts +1 -2
- package/dist/ui/StatusBar.js +5 -6
- package/package.json +1 -1
- package/src/agent/guards.ts +0 -196
- package/src/agent/protocol.ts +1 -4
- package/src/agent/tools.ts +377 -3
- package/src/app.ts +103 -335
- package/src/cli.ts +3 -30
- package/src/commands/index.ts +0 -22
- package/src/commands/login.ts +10 -12
- package/src/commands/logout.ts +16 -8
- package/src/commands/model.ts +22 -42
- package/src/commands/provider.ts +9 -20
- package/src/commands/whoami.ts +5 -6
- package/src/config/store.ts +69 -122
- package/src/config/trust.ts +21 -137
- package/src/lib/diagnostics.ts +4 -60
- package/src/lib/http.ts +4 -66
- package/src/providers/anthropic.ts +1 -13
- package/src/providers/deepseek.ts +1 -2
- package/src/providers/groq.ts +1 -2
- package/src/providers/index.ts +1 -32
- package/src/providers/mistral.ts +1 -2
- package/src/providers/moonshot.ts +1 -2
- package/src/providers/openai.ts +1 -2
- package/src/providers/openaiCompatible.ts +10 -58
- package/src/providers/openrouter.ts +1 -2
- package/src/providers/qwen.ts +1 -2
- package/src/providers/xai.ts +1 -2
- package/src/providers/zhipu.ts +1 -2
- package/src/session/log.ts +28 -267
- package/src/types.ts +1 -63
- package/src/ui/Message.ts +2 -13
- package/src/ui/Prompt.ts +2 -2
- package/src/ui/Spinner.ts +5 -11
- package/src/ui/StatusBar.ts +5 -6
- package/dist/agent/approval.d.ts +0 -50
- package/dist/agent/approval.js +0 -7
- package/dist/agent/compaction.d.ts +0 -39
- package/dist/agent/compaction.js +0 -227
- package/dist/agent/context.d.ts +0 -29
- package/dist/agent/context.js +0 -62
- package/dist/agent/ignore.d.ts +0 -11
- package/dist/agent/ignore.js +0 -129
- package/dist/agent/process-tree.d.ts +0 -2
- package/dist/agent/process-tree.js +0 -31
- package/dist/agent/protocol-mode.d.ts +0 -6
- package/dist/agent/protocol-mode.js +0 -51
- package/dist/agent/registry.d.ts +0 -17
- package/dist/agent/registry.js +0 -90
- package/dist/agent/runner.d.ts +0 -106
- package/dist/agent/runner.js +0 -352
- package/dist/agent/shell-session.d.ts +0 -37
- package/dist/agent/shell-session.js +0 -400
- package/dist/agent/stream.d.ts +0 -29
- package/dist/agent/stream.js +0 -103
- package/dist/agent/tool-schemas.d.ts +0 -2
- package/dist/agent/tool-schemas.js +0 -63
- package/dist/agent/tools/append_file.d.ts +0 -2
- package/dist/agent/tools/append_file.js +0 -26
- package/dist/agent/tools/apply_patch.d.ts +0 -10
- package/dist/agent/tools/apply_patch.js +0 -52
- package/dist/agent/tools/copy_file.d.ts +0 -2
- package/dist/agent/tools/copy_file.js +0 -30
- package/dist/agent/tools/delete_file.d.ts +0 -2
- package/dist/agent/tools/delete_file.js +0 -24
- package/dist/agent/tools/grep.d.ts +0 -2
- package/dist/agent/tools/grep.js +0 -23
- package/dist/agent/tools/index.d.ts +0 -2
- package/dist/agent/tools/index.js +0 -32
- package/dist/agent/tools/list_files.d.ts +0 -2
- package/dist/agent/tools/list_files.js +0 -17
- package/dist/agent/tools/make_dir.d.ts +0 -2
- package/dist/agent/tools/make_dir.js +0 -24
- package/dist/agent/tools/move_path.d.ts +0 -2
- package/dist/agent/tools/move_path.js +0 -47
- package/dist/agent/tools/paths.d.ts +0 -7
- package/dist/agent/tools/paths.js +0 -84
- package/dist/agent/tools/pwd.d.ts +0 -2
- package/dist/agent/tools/pwd.js +0 -10
- package/dist/agent/tools/read_file.d.ts +0 -2
- package/dist/agent/tools/read_file.js +0 -21
- package/dist/agent/tools/read_many.d.ts +0 -2
- package/dist/agent/tools/read_many.js +0 -25
- package/dist/agent/tools/readers.d.ts +0 -6
- package/dist/agent/tools/readers.js +0 -216
- package/dist/agent/tools/replace_in_file.d.ts +0 -2
- package/dist/agent/tools/replace_in_file.js +0 -30
- package/dist/agent/tools/shell.d.ts +0 -2
- package/dist/agent/tools/shell.js +0 -48
- package/dist/agent/tools/stat_path.d.ts +0 -2
- package/dist/agent/tools/stat_path.js +0 -31
- package/dist/agent/tools/types.d.ts +0 -39
- package/dist/agent/tools/types.js +0 -1
- package/dist/agent/tools/validate.d.ts +0 -6
- package/dist/agent/tools/validate.js +0 -29
- package/dist/agent/tools/write_file.d.ts +0 -2
- package/dist/agent/tools/write_file.js +0 -26
- package/dist/commands/attach.d.ts +0 -9
- package/dist/commands/attach.js +0 -15
- package/dist/commands/bg.d.ts +0 -7
- package/dist/commands/bg.js +0 -9
- package/dist/commands/cancel.d.ts +0 -10
- package/dist/commands/cancel.js +0 -10
- package/dist/commands/compact.d.ts +0 -10
- package/dist/commands/compact.js +0 -22
- package/dist/commands/context.d.ts +0 -7
- package/dist/commands/context.js +0 -24
- package/dist/commands/edit.d.ts +0 -10
- package/dist/commands/edit.js +0 -36
- package/dist/commands/effort.d.ts +0 -25
- package/dist/commands/effort.js +0 -48
- package/dist/commands/expand.d.ts +0 -10
- package/dist/commands/expand.js +0 -8
- package/dist/commands/jobs.d.ts +0 -7
- package/dist/commands/jobs.js +0 -16
- package/dist/commands/kill.d.ts +0 -7
- package/dist/commands/kill.js +0 -11
- package/dist/commands/steer.d.ts +0 -11
- package/dist/commands/steer.js +0 -13
- package/dist/lib/model-meta.d.ts +0 -19
- package/dist/lib/model-meta.js +0 -113
- package/dist/lib/native-tools.d.ts +0 -12
- package/dist/lib/native-tools.js +0 -21
- package/dist/lib/net.d.ts +0 -33
- package/dist/lib/net.js +0 -168
- package/dist/patch/apply.d.ts +0 -15
- package/dist/patch/apply.js +0 -172
- package/dist/patch/parse.d.ts +0 -29
- package/dist/patch/parse.js +0 -112
- package/dist/patch/plan.d.ts +0 -49
- package/dist/patch/plan.js +0 -273
- package/dist/session/projection.d.ts +0 -43
- package/dist/session/projection.js +0 -257
- package/dist/ui/Picker.d.ts +0 -8
- package/dist/ui/Picker.js +0 -24
- package/src/agent/approval.ts +0 -47
- package/src/agent/compaction.ts +0 -276
- package/src/agent/context.ts +0 -97
- package/src/agent/ignore.ts +0 -147
- package/src/agent/process-tree.ts +0 -32
- package/src/agent/protocol-mode.ts +0 -59
- package/src/agent/registry.ts +0 -98
- package/src/agent/runner.ts +0 -443
- package/src/agent/shell-session.ts +0 -449
- package/src/agent/stream.ts +0 -143
- package/src/agent/tool-schemas.ts +0 -67
- package/src/agent/tools/append_file.ts +0 -28
- package/src/agent/tools/apply_patch.ts +0 -54
- package/src/agent/tools/copy_file.ts +0 -32
- package/src/agent/tools/delete_file.ts +0 -26
- package/src/agent/tools/grep.ts +0 -25
- package/src/agent/tools/index.ts +0 -34
- package/src/agent/tools/list_files.ts +0 -19
- package/src/agent/tools/make_dir.ts +0 -26
- package/src/agent/tools/move_path.ts +0 -50
- package/src/agent/tools/paths.ts +0 -92
- package/src/agent/tools/pwd.ts +0 -12
- package/src/agent/tools/read_file.ts +0 -23
- package/src/agent/tools/read_many.ts +0 -27
- package/src/agent/tools/readers.ts +0 -228
- package/src/agent/tools/replace_in_file.ts +0 -32
- package/src/agent/tools/shell.ts +0 -53
- package/src/agent/tools/stat_path.ts +0 -33
- package/src/agent/tools/types.ts +0 -42
- package/src/agent/tools/validate.ts +0 -35
- package/src/agent/tools/write_file.ts +0 -28
- package/src/commands/attach.ts +0 -16
- package/src/commands/bg.ts +0 -9
- package/src/commands/cancel.ts +0 -10
- package/src/commands/compact.ts +0 -23
- package/src/commands/context.ts +0 -25
- package/src/commands/edit.ts +0 -37
- package/src/commands/effort.ts +0 -49
- package/src/commands/expand.ts +0 -8
- package/src/commands/jobs.ts +0 -17
- package/src/commands/kill.ts +0 -12
- package/src/commands/steer.ts +0 -13
- package/src/lib/model-meta.ts +0 -138
- package/src/lib/native-tools.ts +0 -32
- package/src/lib/net.ts +0 -204
- package/src/patch/apply.ts +0 -194
- package/src/patch/parse.ts +0 -131
- package/src/patch/plan.ts +0 -317
- package/src/session/projection.ts +0 -308
- package/src/ui/Picker.ts +0 -24
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import { copyFile, mkdir } from "node:fs/promises";
|
|
2
|
-
import { dirname } from "node:path";
|
|
3
|
-
import { sandboxPath } from "./paths.js";
|
|
4
|
-
import { invalid, preparePath, requiredString } from "./validate.js";
|
|
5
|
-
export const copyFileTool = {
|
|
6
|
-
name: "copy_file",
|
|
7
|
-
requiresTrust: true,
|
|
8
|
-
stateScope: "turn",
|
|
9
|
-
revalidate: ["trust", "sandboxRoots"],
|
|
10
|
-
prepare(call, ctx) {
|
|
11
|
-
try {
|
|
12
|
-
const from = requiredString(call, "from");
|
|
13
|
-
const to = requiredString(call, "to");
|
|
14
|
-
const checkedFrom = preparePath(ctx.cwd, from);
|
|
15
|
-
if (!checkedFrom.ok)
|
|
16
|
-
return checkedFrom;
|
|
17
|
-
return preparePath(ctx.cwd, to);
|
|
18
|
-
}
|
|
19
|
-
catch (err) {
|
|
20
|
-
return invalid(err.message);
|
|
21
|
-
}
|
|
22
|
-
},
|
|
23
|
-
async execute(call, ctx) {
|
|
24
|
-
const from = sandboxPath(ctx.cwd, requiredString(call, "from"));
|
|
25
|
-
const to = sandboxPath(ctx.cwd, requiredString(call, "to"));
|
|
26
|
-
await mkdir(dirname(to), { recursive: true });
|
|
27
|
-
await copyFile(from, to);
|
|
28
|
-
return { ok: true, output: `copied ${from} to ${to}`, sideEffects: { touched: [to] } };
|
|
29
|
-
},
|
|
30
|
-
};
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { rm } from "node:fs/promises";
|
|
2
|
-
import { resolvePath } from "./paths.js";
|
|
3
|
-
import { invalid, preparePath, requiredString } from "./validate.js";
|
|
4
|
-
export const deleteFileTool = {
|
|
5
|
-
name: "delete_file",
|
|
6
|
-
requiresTrust: true,
|
|
7
|
-
stateScope: "turn",
|
|
8
|
-
revalidate: ["trust", "sandboxRoots"],
|
|
9
|
-
prepare(call, ctx) {
|
|
10
|
-
let path;
|
|
11
|
-
try {
|
|
12
|
-
path = requiredString(call, "path");
|
|
13
|
-
}
|
|
14
|
-
catch (err) {
|
|
15
|
-
return invalid(err.message);
|
|
16
|
-
}
|
|
17
|
-
return preparePath(ctx.cwd, path);
|
|
18
|
-
},
|
|
19
|
-
async execute(call, ctx) {
|
|
20
|
-
const file = resolvePath(ctx.cwd, call);
|
|
21
|
-
await rm(file, { recursive: true, force: true });
|
|
22
|
-
return { ok: true, output: `deleted ${file}`, sideEffects: { removed: [file] } };
|
|
23
|
-
},
|
|
24
|
-
};
|
package/dist/agent/tools/grep.js
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { grepFiles } from "./readers.js";
|
|
2
|
-
import { resolvePath } from "./paths.js";
|
|
3
|
-
import { invalid, numberOption, preparePath, requiredString } from "./validate.js";
|
|
4
|
-
export const grepTool = {
|
|
5
|
-
name: "grep",
|
|
6
|
-
stateScope: "call",
|
|
7
|
-
revalidate: ["sandboxRoots"],
|
|
8
|
-
prepare(call, ctx) {
|
|
9
|
-
try {
|
|
10
|
-
requiredString(call, "pattern");
|
|
11
|
-
}
|
|
12
|
-
catch (err) {
|
|
13
|
-
return invalid(err.message);
|
|
14
|
-
}
|
|
15
|
-
return preparePath(ctx.cwd, typeof call.path === "string" ? call.path : ".");
|
|
16
|
-
},
|
|
17
|
-
async execute(call, ctx) {
|
|
18
|
-
return {
|
|
19
|
-
ok: true,
|
|
20
|
-
output: await grepFiles(ctx.cwd, resolvePath(ctx.cwd, call, "."), requiredString(call, "pattern"), numberOption(call.maxDepth, 4)),
|
|
21
|
-
};
|
|
22
|
-
},
|
|
23
|
-
};
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { shellTool } from "./shell.js";
|
|
2
|
-
import { pwdTool } from "./pwd.js";
|
|
3
|
-
import { readFileTool } from "./read_file.js";
|
|
4
|
-
import { readManyTool } from "./read_many.js";
|
|
5
|
-
import { writeFileTool } from "./write_file.js";
|
|
6
|
-
import { appendFileTool } from "./append_file.js";
|
|
7
|
-
import { applyPatchTool } from "./apply_patch.js";
|
|
8
|
-
import { copyFileTool } from "./copy_file.js";
|
|
9
|
-
import { deleteFileTool } from "./delete_file.js";
|
|
10
|
-
import { listFilesTool } from "./list_files.js";
|
|
11
|
-
import { makeDirTool } from "./make_dir.js";
|
|
12
|
-
import { movePathTool } from "./move_path.js";
|
|
13
|
-
import { grepTool } from "./grep.js";
|
|
14
|
-
import { replaceInFileTool } from "./replace_in_file.js";
|
|
15
|
-
import { statPathTool } from "./stat_path.js";
|
|
16
|
-
export const TOOLS = [
|
|
17
|
-
shellTool,
|
|
18
|
-
pwdTool,
|
|
19
|
-
readFileTool,
|
|
20
|
-
readManyTool,
|
|
21
|
-
writeFileTool,
|
|
22
|
-
appendFileTool,
|
|
23
|
-
applyPatchTool,
|
|
24
|
-
copyFileTool,
|
|
25
|
-
deleteFileTool,
|
|
26
|
-
listFilesTool,
|
|
27
|
-
makeDirTool,
|
|
28
|
-
movePathTool,
|
|
29
|
-
grepTool,
|
|
30
|
-
replaceInFileTool,
|
|
31
|
-
statPathTool,
|
|
32
|
-
];
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { listFiles } from "./readers.js";
|
|
2
|
-
import { resolvePath } from "./paths.js";
|
|
3
|
-
import { numberOption, preparePath } from "./validate.js";
|
|
4
|
-
export const listFilesTool = {
|
|
5
|
-
name: "list_files",
|
|
6
|
-
stateScope: "call",
|
|
7
|
-
revalidate: ["sandboxRoots"],
|
|
8
|
-
prepare(call, ctx) {
|
|
9
|
-
return preparePath(ctx.cwd, typeof call.path === "string" ? call.path : ".");
|
|
10
|
-
},
|
|
11
|
-
async execute(call, ctx) {
|
|
12
|
-
return {
|
|
13
|
-
ok: true,
|
|
14
|
-
output: await listFiles(ctx.cwd, resolvePath(ctx.cwd, call, "."), numberOption(call.maxDepth, 2), call.detail === true),
|
|
15
|
-
};
|
|
16
|
-
},
|
|
17
|
-
};
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { mkdir } from "node:fs/promises";
|
|
2
|
-
import { resolvePath } from "./paths.js";
|
|
3
|
-
import { invalid, preparePath, requiredString } from "./validate.js";
|
|
4
|
-
export const makeDirTool = {
|
|
5
|
-
name: "make_dir",
|
|
6
|
-
requiresTrust: true,
|
|
7
|
-
stateScope: "turn",
|
|
8
|
-
revalidate: ["trust", "sandboxRoots"],
|
|
9
|
-
prepare(call, ctx) {
|
|
10
|
-
let path;
|
|
11
|
-
try {
|
|
12
|
-
path = requiredString(call, "path");
|
|
13
|
-
}
|
|
14
|
-
catch (err) {
|
|
15
|
-
return invalid(err.message);
|
|
16
|
-
}
|
|
17
|
-
return preparePath(ctx.cwd, path);
|
|
18
|
-
},
|
|
19
|
-
async execute(call, ctx) {
|
|
20
|
-
const dir = resolvePath(ctx.cwd, call);
|
|
21
|
-
await mkdir(dir, { recursive: true });
|
|
22
|
-
return { ok: true, output: `created ${dir}`, sideEffects: { created: [dir] } };
|
|
23
|
-
},
|
|
24
|
-
};
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import { mkdir, rename } from "node:fs/promises";
|
|
2
|
-
import { lstatSync } from "node:fs";
|
|
3
|
-
import { dirname } from "node:path";
|
|
4
|
-
import { sandboxPath } from "./paths.js";
|
|
5
|
-
import { invalid, preparePath, requiredString } from "./validate.js";
|
|
6
|
-
function exists(path) {
|
|
7
|
-
try {
|
|
8
|
-
lstatSync(path);
|
|
9
|
-
return true;
|
|
10
|
-
}
|
|
11
|
-
catch {
|
|
12
|
-
return false;
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
export const movePathTool = {
|
|
16
|
-
name: "move_path",
|
|
17
|
-
requiresTrust: true,
|
|
18
|
-
stateScope: "turn",
|
|
19
|
-
revalidate: ["trust", "sandboxRoots"],
|
|
20
|
-
prepare(call, ctx) {
|
|
21
|
-
try {
|
|
22
|
-
const from = requiredString(call, "from");
|
|
23
|
-
const to = requiredString(call, "to");
|
|
24
|
-
const checkedFrom = preparePath(ctx.cwd, from);
|
|
25
|
-
if (!checkedFrom.ok)
|
|
26
|
-
return checkedFrom;
|
|
27
|
-
const checkedTo = preparePath(ctx.cwd, to);
|
|
28
|
-
if (!checkedTo.ok)
|
|
29
|
-
return checkedTo;
|
|
30
|
-
if (exists(to))
|
|
31
|
-
return invalid(`move target exists: ${to}`);
|
|
32
|
-
return { ok: true };
|
|
33
|
-
}
|
|
34
|
-
catch (err) {
|
|
35
|
-
return invalid(err.message);
|
|
36
|
-
}
|
|
37
|
-
},
|
|
38
|
-
async execute(call, ctx) {
|
|
39
|
-
const from = sandboxPath(ctx.cwd, requiredString(call, "from"));
|
|
40
|
-
const to = sandboxPath(ctx.cwd, requiredString(call, "to"));
|
|
41
|
-
if (exists(to))
|
|
42
|
-
return { ok: false, output: `move target exists: ${to}` };
|
|
43
|
-
await mkdir(dirname(to), { recursive: true });
|
|
44
|
-
await rename(from, to);
|
|
45
|
-
return { ok: true, output: `moved ${from} to ${to}`, sideEffects: { removed: [from], touched: [to] } };
|
|
46
|
-
},
|
|
47
|
-
};
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import type { ToolCall } from "./types.js";
|
|
2
|
-
export declare function allowedRoots(cwd: string): string[];
|
|
3
|
-
export declare function resolveSharedDir(cwd: string, entry: string): string;
|
|
4
|
-
export declare function isInsideAny(child: string, roots: string[]): boolean;
|
|
5
|
-
export declare function resolvePath(cwd: string, call: ToolCall, fallback?: string): string;
|
|
6
|
-
export declare function sandboxPath(cwd: string, raw: string): string;
|
|
7
|
-
export declare function realpathOf(input: string): string | undefined;
|
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
import { existsSync, realpathSync } from "node:fs";
|
|
2
|
-
import { basename, delimiter, dirname, isAbsolute, join, relative, resolve } from "node:path";
|
|
3
|
-
import { detectPlatform, safeHome } from "../../lib/platform.js";
|
|
4
|
-
import { loadConfig } from "../../config/store.js";
|
|
5
|
-
export function allowedRoots(cwd) {
|
|
6
|
-
const roots = [resolve(cwd)];
|
|
7
|
-
const configured = (process.env["FASTCODE_ALLOW_PATHS"] ?? "")
|
|
8
|
-
.split(delimiter)
|
|
9
|
-
.map((entry) => entry.trim())
|
|
10
|
-
.filter(Boolean);
|
|
11
|
-
for (const entry of configured)
|
|
12
|
-
roots.push(resolve(entry));
|
|
13
|
-
const sharedDirs = loadConfig().sharedDirs;
|
|
14
|
-
if (Array.isArray(sharedDirs)) {
|
|
15
|
-
for (const entry of sharedDirs) {
|
|
16
|
-
if (typeof entry !== "string" || !entry.trim())
|
|
17
|
-
continue;
|
|
18
|
-
roots.push(resolveSharedDir(cwd, entry.trim()));
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
if (detectPlatform() === "termux" && !isDisabled(process.env["FASTCODE_ALLOW_SHARED_STORAGE"])) {
|
|
22
|
-
const home = process.env["HOME"];
|
|
23
|
-
if (home) {
|
|
24
|
-
const shared = join(home, "storage", "shared");
|
|
25
|
-
if (existsSync(shared))
|
|
26
|
-
roots.push(shared);
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
return roots;
|
|
30
|
-
}
|
|
31
|
-
export function resolveSharedDir(cwd, entry) {
|
|
32
|
-
const expanded = entry === "~" || entry.startsWith("~/") || entry.startsWith("~\\")
|
|
33
|
-
? join(safeHome(), entry.slice(1))
|
|
34
|
-
: entry;
|
|
35
|
-
return isAbsolute(expanded) ? resolve(expanded) : resolve(cwd, expanded);
|
|
36
|
-
}
|
|
37
|
-
function isDisabled(value) {
|
|
38
|
-
if (value === undefined)
|
|
39
|
-
return false;
|
|
40
|
-
return ["0", "false", "no", "off"].includes(value.trim().toLowerCase());
|
|
41
|
-
}
|
|
42
|
-
export function isInsideAny(child, roots) {
|
|
43
|
-
return roots.some((root) => {
|
|
44
|
-
const rel = relative(root, child);
|
|
45
|
-
return rel === "" || (!rel.startsWith("..") && !isAbsolute(rel));
|
|
46
|
-
});
|
|
47
|
-
}
|
|
48
|
-
export function resolvePath(cwd, call, fallback = "") {
|
|
49
|
-
const raw = typeof call.path === "string" ? call.path : fallback;
|
|
50
|
-
return sandboxPath(cwd, raw);
|
|
51
|
-
}
|
|
52
|
-
export function sandboxPath(cwd, raw) {
|
|
53
|
-
const target = resolve(cwd, raw);
|
|
54
|
-
const roots = allowedRoots(cwd);
|
|
55
|
-
const realRoots = roots.map((root) => realpathOf(root)).filter(Boolean);
|
|
56
|
-
const realTarget = realpathOf(target);
|
|
57
|
-
if (realTarget) {
|
|
58
|
-
if (isInsideAny(realTarget, realRoots))
|
|
59
|
-
return target;
|
|
60
|
-
throw new Error("path outside sandbox: " + raw);
|
|
61
|
-
}
|
|
62
|
-
if (isInsideAny(target, roots))
|
|
63
|
-
return target;
|
|
64
|
-
throw new Error("path outside sandbox: " + raw);
|
|
65
|
-
}
|
|
66
|
-
export function realpathOf(input) {
|
|
67
|
-
let current = resolve(input);
|
|
68
|
-
const missing = [];
|
|
69
|
-
for (;;) {
|
|
70
|
-
if (existsSync(current)) {
|
|
71
|
-
try {
|
|
72
|
-
return join(realpathSync(current), ...missing.slice().reverse());
|
|
73
|
-
}
|
|
74
|
-
catch {
|
|
75
|
-
return undefined;
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
const parent = dirname(current);
|
|
79
|
-
if (parent === current)
|
|
80
|
-
return undefined;
|
|
81
|
-
missing.push(basename(current));
|
|
82
|
-
current = parent;
|
|
83
|
-
}
|
|
84
|
-
}
|
package/dist/agent/tools/pwd.js
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { readTextFile } from "./readers.js";
|
|
2
|
-
import { resolvePath } from "./paths.js";
|
|
3
|
-
import { invalid, preparePath, requiredString } from "./validate.js";
|
|
4
|
-
export const readFileTool = {
|
|
5
|
-
name: "read_file",
|
|
6
|
-
stateScope: "call",
|
|
7
|
-
revalidate: ["sandboxRoots"],
|
|
8
|
-
prepare(call, ctx) {
|
|
9
|
-
let path;
|
|
10
|
-
try {
|
|
11
|
-
path = requiredString(call, "path");
|
|
12
|
-
}
|
|
13
|
-
catch (err) {
|
|
14
|
-
return invalid(err.message);
|
|
15
|
-
}
|
|
16
|
-
return preparePath(ctx.cwd, path);
|
|
17
|
-
},
|
|
18
|
-
async execute(call, ctx) {
|
|
19
|
-
return { ok: true, output: await readTextFile(resolvePath(ctx.cwd, call)) };
|
|
20
|
-
},
|
|
21
|
-
};
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { readMany } from "./readers.js";
|
|
2
|
-
import { invalid, preparePath, stringArray } from "./validate.js";
|
|
3
|
-
export const readManyTool = {
|
|
4
|
-
name: "read_many",
|
|
5
|
-
stateScope: "call",
|
|
6
|
-
revalidate: ["sandboxRoots"],
|
|
7
|
-
prepare(call, ctx) {
|
|
8
|
-
let paths;
|
|
9
|
-
try {
|
|
10
|
-
paths = stringArray(call, "paths");
|
|
11
|
-
}
|
|
12
|
-
catch (err) {
|
|
13
|
-
return invalid(err.message);
|
|
14
|
-
}
|
|
15
|
-
for (const path of paths) {
|
|
16
|
-
const checked = preparePath(ctx.cwd, path);
|
|
17
|
-
if (!checked.ok)
|
|
18
|
-
return checked;
|
|
19
|
-
}
|
|
20
|
-
return { ok: true };
|
|
21
|
-
},
|
|
22
|
-
async execute(call, ctx) {
|
|
23
|
-
return { ok: true, output: await readMany(ctx.cwd, stringArray(call, "paths")) };
|
|
24
|
-
},
|
|
25
|
-
};
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
export declare function readMany(cwd: string, paths: string[]): Promise<string>;
|
|
2
|
-
export declare function listFiles(sandbox: string, root: string, maxDepth: number, detail: boolean): Promise<string>;
|
|
3
|
-
export declare function formatSize(bytes: number): string;
|
|
4
|
-
export declare function grepFiles(sandbox: string, root: string, pattern: string, maxDepth: number): Promise<string>;
|
|
5
|
-
export declare function readTextFile(file: string, limit?: number): Promise<string>;
|
|
6
|
-
export declare function readMaxBytes(): number;
|
|
@@ -1,216 +0,0 @@
|
|
|
1
|
-
import { open, readdir, stat } from "node:fs/promises";
|
|
2
|
-
import { basename, extname, join } from "node:path";
|
|
3
|
-
import { createIgnore, isBinaryName } from "../ignore.js";
|
|
4
|
-
import { createOutputBuffer } from "../limits.js";
|
|
5
|
-
import { allowedRoots, isInsideAny, realpathOf, sandboxPath } from "./paths.js";
|
|
6
|
-
export async function readMany(cwd, paths) {
|
|
7
|
-
const blocks = [];
|
|
8
|
-
for (const path of paths) {
|
|
9
|
-
const file = sandboxPath(cwd, path);
|
|
10
|
-
blocks.push(`### ${file}\n${await readTextFile(file)}`);
|
|
11
|
-
}
|
|
12
|
-
return blocks.join("\n\n");
|
|
13
|
-
}
|
|
14
|
-
const CODE_EXT = new Set([
|
|
15
|
-
".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".py", ".go", ".rs", ".java",
|
|
16
|
-
".rb", ".php", ".cs", ".c", ".h", ".cpp", ".hpp", ".kt", ".swift", ".scala",
|
|
17
|
-
".sh", ".lua", ".ex", ".exs", ".dart", ".vue", ".svelte",
|
|
18
|
-
]);
|
|
19
|
-
export async function listFiles(sandbox, root, maxDepth, detail) {
|
|
20
|
-
const out = createOutputBuffer();
|
|
21
|
-
const ignore = createIgnore(sandbox);
|
|
22
|
-
if (detail) {
|
|
23
|
-
await walkWithin(sandbox, root, maxDepth, async (file, info) => {
|
|
24
|
-
out.line((info.isDirectory() ? "dir " : "file") + " " + file);
|
|
25
|
-
return !out.full;
|
|
26
|
-
});
|
|
27
|
-
return out.value();
|
|
28
|
-
}
|
|
29
|
-
async function visitDir(dir, depth, label) {
|
|
30
|
-
let entries;
|
|
31
|
-
try {
|
|
32
|
-
entries = await readdir(dir, { withFileTypes: true });
|
|
33
|
-
}
|
|
34
|
-
catch {
|
|
35
|
-
out.line(`${indent(depth)}${label}/ (unreadable)`);
|
|
36
|
-
return;
|
|
37
|
-
}
|
|
38
|
-
entries = entries.filter((entry) => !ignore.ignored(entry.name, join(dir, entry.name), entry.isDirectory()));
|
|
39
|
-
entries.sort((a, b) => Number(b.isDirectory()) - Number(a.isDirectory()) || a.name.localeCompare(b.name));
|
|
40
|
-
const dirs = entries.filter((entry) => entry.isDirectory());
|
|
41
|
-
const files = entries.filter((entry) => entry.isFile());
|
|
42
|
-
out.line(`${indent(depth)}${label}/ (${files.length} file${files.length === 1 ? "" : "s"}, ${dirs.length} dir${dirs.length === 1 ? "" : "s"})`);
|
|
43
|
-
for (const entry of files) {
|
|
44
|
-
const full = join(dir, entry.name);
|
|
45
|
-
const info = await stat(full).catch(() => undefined);
|
|
46
|
-
if (!info)
|
|
47
|
-
continue;
|
|
48
|
-
let line = `${indent(depth + 1)}${entry.name} (${formatSize(info.size)})`;
|
|
49
|
-
const symbols = await fileSymbols(full, entry.name, info.size);
|
|
50
|
-
if (symbols)
|
|
51
|
-
line += ` — ${symbols}`;
|
|
52
|
-
out.line(line);
|
|
53
|
-
if (out.full)
|
|
54
|
-
return;
|
|
55
|
-
}
|
|
56
|
-
if (depth >= maxDepth)
|
|
57
|
-
return;
|
|
58
|
-
for (const entry of dirs) {
|
|
59
|
-
await visitDir(join(dir, entry.name), depth + 1, entry.name);
|
|
60
|
-
if (out.full)
|
|
61
|
-
return;
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
await visitDir(root, 0, basename(root) || ".");
|
|
65
|
-
return out.value();
|
|
66
|
-
}
|
|
67
|
-
async function fileSymbols(file, name, size) {
|
|
68
|
-
if (size > 256 * 1024 || !CODE_EXT.has(extname(name).toLowerCase()))
|
|
69
|
-
return "";
|
|
70
|
-
try {
|
|
71
|
-
const text = await readTextFile(file, 64 * 1024);
|
|
72
|
-
const names = new Set();
|
|
73
|
-
const patterns = [
|
|
74
|
-
/(?:^|\n)\s*(?:export\s+)?(?:default\s+)?(?:async\s+)?(?:function|class|interface|type|enum|struct|trait|impl|def)\s+([A-Za-z_$][\w$]*)/g,
|
|
75
|
-
/(?:^|\n)\s*(?:export\s+)?(?:const|let|var)\s+([A-Za-z_$][\w$]*)\s*=\s*(?:async\s*)?(?:\(|function)/g,
|
|
76
|
-
];
|
|
77
|
-
for (const pattern of patterns) {
|
|
78
|
-
for (const match of text.matchAll(pattern)) {
|
|
79
|
-
names.add(match[1]);
|
|
80
|
-
if (names.size >= 8)
|
|
81
|
-
break;
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
return Array.from(names).slice(0, 8).join(", ");
|
|
85
|
-
}
|
|
86
|
-
catch {
|
|
87
|
-
return "";
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
function indent(depth) {
|
|
91
|
-
return " ".repeat(depth);
|
|
92
|
-
}
|
|
93
|
-
export function formatSize(bytes) {
|
|
94
|
-
if (bytes < 1024)
|
|
95
|
-
return `${bytes} B`;
|
|
96
|
-
if (bytes < 1024 * 1024)
|
|
97
|
-
return `${(bytes / 1024).toFixed(1)} KB`;
|
|
98
|
-
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
99
|
-
}
|
|
100
|
-
export async function grepFiles(sandbox, root, pattern, maxDepth) {
|
|
101
|
-
const re = new RegExp(pattern, "i");
|
|
102
|
-
const out = createOutputBuffer();
|
|
103
|
-
const maxBytes = grepMaxBytes();
|
|
104
|
-
await walkWithin(sandbox, root, maxDepth, async (file, info) => {
|
|
105
|
-
if (!info.isFile())
|
|
106
|
-
return;
|
|
107
|
-
if (isBinaryName(basename(file)))
|
|
108
|
-
return;
|
|
109
|
-
if (info.size > maxBytes) {
|
|
110
|
-
out.line(`${file}: skipped (${formatSize(info.size)} exceeds ${formatSize(maxBytes)})`);
|
|
111
|
-
return !out.full;
|
|
112
|
-
}
|
|
113
|
-
try {
|
|
114
|
-
const text = await readTextFile(file, maxBytes);
|
|
115
|
-
const lines = text.split(/\r?\n/);
|
|
116
|
-
lines.forEach((line, index) => {
|
|
117
|
-
if (re.test(line))
|
|
118
|
-
out.line(file + ":" + (index + 1) + ": " + line);
|
|
119
|
-
});
|
|
120
|
-
}
|
|
121
|
-
catch {
|
|
122
|
-
// Binary or unreadable files are skipped.
|
|
123
|
-
}
|
|
124
|
-
return !out.full;
|
|
125
|
-
});
|
|
126
|
-
return out.value();
|
|
127
|
-
}
|
|
128
|
-
export async function readTextFile(file, limit = readMaxBytes()) {
|
|
129
|
-
const info = await stat(file);
|
|
130
|
-
if (!info.isFile())
|
|
131
|
-
throw new Error(`not a file: ${file}`);
|
|
132
|
-
const length = Math.min(info.size, limit);
|
|
133
|
-
const handle = await open(file, "r");
|
|
134
|
-
try {
|
|
135
|
-
const buffer = Buffer.alloc(length);
|
|
136
|
-
const { bytesRead } = await handle.read(buffer, 0, length, 0);
|
|
137
|
-
const slice = buffer.subarray(0, bytesRead);
|
|
138
|
-
if (slice.subarray(0, Math.min(8192, slice.length)).includes(0))
|
|
139
|
-
return `[binary file omitted: ${file} (${info.size} bytes)]`;
|
|
140
|
-
const text = slice.toString("utf8");
|
|
141
|
-
return info.size > length
|
|
142
|
-
? `${text}\n[... truncated at ${length} of ${info.size} bytes; use grep or read a narrower file ...]`
|
|
143
|
-
: text;
|
|
144
|
-
}
|
|
145
|
-
finally {
|
|
146
|
-
await handle.close();
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
export function readMaxBytes() {
|
|
150
|
-
const raw = Number(process.env["FASTCODE_READ_MAX_BYTES"]);
|
|
151
|
-
return Number.isFinite(raw) && raw > 0 ? Math.floor(raw) : 200_000;
|
|
152
|
-
}
|
|
153
|
-
function grepMaxBytes() {
|
|
154
|
-
const raw = Number(process.env["FASTCODE_GREP_MAX_BYTES"]);
|
|
155
|
-
return Number.isFinite(raw) && raw > 0 ? Math.floor(raw) : 1_000_000;
|
|
156
|
-
}
|
|
157
|
-
async function walkWithin(sandbox, root, maxDepth, visit) {
|
|
158
|
-
const roots = allowedRoots(sandbox).map((entry) => realpathOf(entry)).filter(Boolean);
|
|
159
|
-
const ignore = createIgnore(sandbox);
|
|
160
|
-
await walk(root, maxDepth, visit, 0, { roots, visited: 0, maxVisited: 5000, ignore }, []);
|
|
161
|
-
}
|
|
162
|
-
async function walk(node, maxDepth, visit, depth = 0, state, chain = []) {
|
|
163
|
-
if (state.visited >= state.maxVisited)
|
|
164
|
-
return;
|
|
165
|
-
let info;
|
|
166
|
-
try {
|
|
167
|
-
info = await stat(node);
|
|
168
|
-
}
|
|
169
|
-
catch {
|
|
170
|
-
return;
|
|
171
|
-
}
|
|
172
|
-
let real;
|
|
173
|
-
try {
|
|
174
|
-
real = await realpathOf(node) ?? node;
|
|
175
|
-
}
|
|
176
|
-
catch {
|
|
177
|
-
real = node;
|
|
178
|
-
}
|
|
179
|
-
if (chain.includes(real))
|
|
180
|
-
return;
|
|
181
|
-
state.visited += 1;
|
|
182
|
-
const insideSandbox = !state.roots || state.roots.length === 0 || isInsideAny(real, state.roots);
|
|
183
|
-
let keepGoing = true;
|
|
184
|
-
try {
|
|
185
|
-
keepGoing = await visit(node, info);
|
|
186
|
-
}
|
|
187
|
-
catch {
|
|
188
|
-
// A visitor failure must not abort the surrounding walk.
|
|
189
|
-
}
|
|
190
|
-
if (keepGoing === false)
|
|
191
|
-
return false;
|
|
192
|
-
if (!info.isDirectory() || depth >= maxDepth || !insideSandbox)
|
|
193
|
-
return;
|
|
194
|
-
let entries;
|
|
195
|
-
try {
|
|
196
|
-
entries = await readdir(node, { withFileTypes: true });
|
|
197
|
-
}
|
|
198
|
-
catch {
|
|
199
|
-
return;
|
|
200
|
-
}
|
|
201
|
-
const nextChain = chain.concat(real);
|
|
202
|
-
for (const entry of entries) {
|
|
203
|
-
if (state.ignore?.ignored(entry.name, join(node, entry.name), entry.isDirectory()))
|
|
204
|
-
continue;
|
|
205
|
-
if (state.visited >= state.maxVisited)
|
|
206
|
-
return;
|
|
207
|
-
try {
|
|
208
|
-
const keepWalking = await walk(join(node, entry.name), maxDepth, visit, depth + 1, state, nextChain);
|
|
209
|
-
if (keepWalking === false)
|
|
210
|
-
return false;
|
|
211
|
-
}
|
|
212
|
-
catch {
|
|
213
|
-
// Keep walking siblings.
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import { readFile, writeFile } from "node:fs/promises";
|
|
2
|
-
import { resolvePath } from "./paths.js";
|
|
3
|
-
import { invalid, preparePath, requiredString } from "./validate.js";
|
|
4
|
-
export const replaceInFileTool = {
|
|
5
|
-
name: "replace_in_file",
|
|
6
|
-
requiresTrust: true,
|
|
7
|
-
stateScope: "turn",
|
|
8
|
-
revalidate: ["trust", "sandboxRoots"],
|
|
9
|
-
prepare(call, ctx) {
|
|
10
|
-
try {
|
|
11
|
-
requiredString(call, "path");
|
|
12
|
-
requiredString(call, "find");
|
|
13
|
-
requiredString(call, "replace");
|
|
14
|
-
}
|
|
15
|
-
catch (err) {
|
|
16
|
-
return invalid(err.message);
|
|
17
|
-
}
|
|
18
|
-
return preparePath(ctx.cwd, requiredString(call, "path"));
|
|
19
|
-
},
|
|
20
|
-
async execute(call, ctx) {
|
|
21
|
-
const file = resolvePath(ctx.cwd, call);
|
|
22
|
-
const find = requiredString(call, "find");
|
|
23
|
-
const replacement = requiredString(call, "replace");
|
|
24
|
-
const source = await readFile(file, "utf8");
|
|
25
|
-
if (!source.includes(find))
|
|
26
|
-
return { ok: false, output: `text not found in ${file}` };
|
|
27
|
-
await writeFile(file, source.split(find).join(replacement), "utf8");
|
|
28
|
-
return { ok: true, output: `replaced text in ${file}`, sideEffects: { touched: [file] } };
|
|
29
|
-
},
|
|
30
|
-
};
|