@llmist/cli 16.0.4 → 16.2.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/dist/cli.js +1777 -1136
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +7 -1
- package/dist/index.js +96 -46
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -19,6 +19,12 @@ declare class PathSandboxException extends Error {
|
|
|
19
19
|
*/
|
|
20
20
|
declare function validatePathIsWithinCwd(inputPath: string): string;
|
|
21
21
|
|
|
22
|
+
/**
|
|
23
|
+
* DeleteFile gadget - Deletes a file or directory.
|
|
24
|
+
* All paths are validated to be within the current working directory.
|
|
25
|
+
*/
|
|
26
|
+
declare const deleteFile: llmist.AbstractGadget;
|
|
27
|
+
|
|
22
28
|
declare const editFile: llmist.AbstractGadget;
|
|
23
29
|
|
|
24
30
|
/**
|
|
@@ -53,4 +59,4 @@ declare const writeFile: llmist.AbstractGadget;
|
|
|
53
59
|
*/
|
|
54
60
|
declare const runCommand: llmist.AbstractGadget;
|
|
55
61
|
|
|
56
|
-
export {
|
|
62
|
+
export { deleteFile as DeleteFile, listDirectory as ListDirectory, PathSandboxException, readFile as ReadFile, runCommand as RunCommand, writeFile as WriteFile, deleteFile, editFile, listDirectory, readFile, runCommand, validatePathIsWithinCwd, writeFile };
|
package/dist/index.js
CHANGED
|
@@ -10,6 +10,12 @@ var PathSandboxException = class extends Error {
|
|
|
10
10
|
function validatePathIsWithinCwd(inputPath) {
|
|
11
11
|
const cwd = process.cwd();
|
|
12
12
|
const resolvedPath = path.resolve(cwd, inputPath);
|
|
13
|
+
let realCwd;
|
|
14
|
+
try {
|
|
15
|
+
realCwd = fs.realpathSync(cwd);
|
|
16
|
+
} catch {
|
|
17
|
+
realCwd = cwd;
|
|
18
|
+
}
|
|
13
19
|
let finalPath;
|
|
14
20
|
try {
|
|
15
21
|
finalPath = fs.realpathSync(resolvedPath);
|
|
@@ -21,17 +27,60 @@ function validatePathIsWithinCwd(inputPath) {
|
|
|
21
27
|
throw error;
|
|
22
28
|
}
|
|
23
29
|
}
|
|
24
|
-
const cwdWithSep =
|
|
25
|
-
if (!finalPath.startsWith(cwdWithSep) && finalPath !==
|
|
30
|
+
const cwdWithSep = realCwd + path.sep;
|
|
31
|
+
if (!finalPath.startsWith(cwdWithSep) && finalPath !== realCwd) {
|
|
26
32
|
throw new PathSandboxException(inputPath, "Path is outside the current working directory");
|
|
27
33
|
}
|
|
28
34
|
return finalPath;
|
|
29
35
|
}
|
|
30
36
|
|
|
31
|
-
// src/builtins/filesystem/
|
|
32
|
-
import
|
|
37
|
+
// src/builtins/filesystem/delete-file.ts
|
|
38
|
+
import fs2 from "fs";
|
|
33
39
|
import { createGadget } from "llmist";
|
|
34
40
|
import { z } from "zod";
|
|
41
|
+
var deleteFile = createGadget({
|
|
42
|
+
name: "DeleteFile",
|
|
43
|
+
description: "Delete a file or directory from the local filesystem. The path must be within the current working directory or its subdirectories.",
|
|
44
|
+
maxConcurrent: 1,
|
|
45
|
+
// Sequential execution to prevent race conditions
|
|
46
|
+
schema: z.object({
|
|
47
|
+
filePath: z.string().describe("Path to the file or directory to delete (relative or absolute)"),
|
|
48
|
+
recursive: z.boolean().optional().default(false).describe("If true, perform a recursive deletion (required for directories)")
|
|
49
|
+
}),
|
|
50
|
+
examples: [
|
|
51
|
+
{
|
|
52
|
+
params: { filePath: "temp.txt", recursive: false },
|
|
53
|
+
output: "path=temp.txt\n\nDeleted file successfully",
|
|
54
|
+
comment: "Delete a single file"
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
params: { filePath: "tmp-dir", recursive: true },
|
|
58
|
+
output: "path=tmp-dir\n\nDeleted directory successfully",
|
|
59
|
+
comment: "Delete a directory and its contents"
|
|
60
|
+
}
|
|
61
|
+
],
|
|
62
|
+
execute: ({ filePath, recursive }) => {
|
|
63
|
+
const validatedPath = validatePathIsWithinCwd(filePath);
|
|
64
|
+
if (!fs2.existsSync(validatedPath)) {
|
|
65
|
+
return `Error: Path does not exist: ${filePath}`;
|
|
66
|
+
}
|
|
67
|
+
const stats = fs2.statSync(validatedPath);
|
|
68
|
+
const isDirectory = stats.isDirectory();
|
|
69
|
+
if (isDirectory && !recursive) {
|
|
70
|
+
return `Error: ${filePath} is a directory. Set recursive=true to delete it.`;
|
|
71
|
+
}
|
|
72
|
+
fs2.rmSync(validatedPath, { recursive, force: true });
|
|
73
|
+
const type = isDirectory ? "directory" : "file";
|
|
74
|
+
return `path=${filePath}
|
|
75
|
+
|
|
76
|
+
Deleted ${type} successfully`;
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
// src/builtins/filesystem/edit-file.ts
|
|
81
|
+
import { readFileSync, writeFileSync } from "fs";
|
|
82
|
+
import { createGadget as createGadget2 } from "llmist";
|
|
83
|
+
import { z as z2 } from "zod";
|
|
35
84
|
|
|
36
85
|
// src/builtins/filesystem/editfile/matcher.ts
|
|
37
86
|
import DiffMatchPatch from "diff-match-patch";
|
|
@@ -481,7 +530,7 @@ function formatFailure(filePath, search, failure, fileContent) {
|
|
|
481
530
|
lines.push("", "CURRENT FILE CONTENT:", "```", fileContent, "```");
|
|
482
531
|
return lines.join("\n");
|
|
483
532
|
}
|
|
484
|
-
var editFile =
|
|
533
|
+
var editFile = createGadget2({
|
|
485
534
|
name: "EditFile",
|
|
486
535
|
description: `Edit a file by searching for content and replacing it.
|
|
487
536
|
|
|
@@ -500,12 +549,12 @@ Options:
|
|
|
500
549
|
- expectedCount: Validate exact number of matches before applying`,
|
|
501
550
|
maxConcurrent: 1,
|
|
502
551
|
// Sequential execution to prevent race conditions
|
|
503
|
-
schema:
|
|
504
|
-
filePath:
|
|
505
|
-
search:
|
|
506
|
-
replace:
|
|
507
|
-
replaceAll:
|
|
508
|
-
expectedCount:
|
|
552
|
+
schema: z2.object({
|
|
553
|
+
filePath: z2.string().describe("Path to the file to edit (relative or absolute)"),
|
|
554
|
+
search: z2.string().describe("The content to search for in the file"),
|
|
555
|
+
replace: z2.string().describe("The content to replace it with (empty string to delete)"),
|
|
556
|
+
replaceAll: z2.boolean().optional().default(false).describe("Replace all occurrences instead of just the first match"),
|
|
557
|
+
expectedCount: z2.number().int().positive().optional().describe("Expected number of matches. Edit fails if actual count differs")
|
|
509
558
|
}),
|
|
510
559
|
examples: [
|
|
511
560
|
{
|
|
@@ -657,19 +706,19 @@ function executeReplaceAll(content, matches, replace) {
|
|
|
657
706
|
}
|
|
658
707
|
|
|
659
708
|
// src/builtins/filesystem/list-directory.ts
|
|
660
|
-
import
|
|
709
|
+
import fs3 from "fs";
|
|
661
710
|
import path2 from "path";
|
|
662
|
-
import { createGadget as
|
|
663
|
-
import { z as
|
|
711
|
+
import { createGadget as createGadget3 } from "llmist";
|
|
712
|
+
import { z as z3 } from "zod";
|
|
664
713
|
function listFiles(dirPath, basePath = dirPath, maxDepth = 1, currentDepth = 1) {
|
|
665
714
|
const entries = [];
|
|
666
715
|
try {
|
|
667
|
-
const items =
|
|
716
|
+
const items = fs3.readdirSync(dirPath);
|
|
668
717
|
for (const item of items) {
|
|
669
718
|
const fullPath = path2.join(dirPath, item);
|
|
670
719
|
const relativePath = path2.relative(basePath, fullPath);
|
|
671
720
|
try {
|
|
672
|
-
const stats =
|
|
721
|
+
const stats = fs3.lstatSync(fullPath);
|
|
673
722
|
let type;
|
|
674
723
|
let size;
|
|
675
724
|
if (stats.isSymbolicLink()) {
|
|
@@ -744,12 +793,12 @@ function formatEntriesAsString(entries) {
|
|
|
744
793
|
);
|
|
745
794
|
return [header, ...rows].join("\n");
|
|
746
795
|
}
|
|
747
|
-
var listDirectory =
|
|
796
|
+
var listDirectory = createGadget3({
|
|
748
797
|
name: "ListDirectory",
|
|
749
798
|
description: "List files and directories in a directory with full details (names, types, sizes, modification dates). Use maxDepth to explore subdirectories recursively. The directory path must be within the current working directory or its subdirectories.",
|
|
750
|
-
schema:
|
|
751
|
-
directoryPath:
|
|
752
|
-
maxDepth:
|
|
799
|
+
schema: z3.object({
|
|
800
|
+
directoryPath: z3.string().default(".").describe("Path to the directory to list"),
|
|
801
|
+
maxDepth: z3.number().int().min(1).max(10).default(3).describe(
|
|
753
802
|
"Maximum depth to recurse (1 = immediate children only, 2 = include grandchildren, etc.)"
|
|
754
803
|
)
|
|
755
804
|
}),
|
|
@@ -767,7 +816,7 @@ var listDirectory = createGadget2({
|
|
|
767
816
|
],
|
|
768
817
|
execute: ({ directoryPath, maxDepth }) => {
|
|
769
818
|
const validatedPath = validatePathIsWithinCwd(directoryPath);
|
|
770
|
-
const stats =
|
|
819
|
+
const stats = fs3.statSync(validatedPath);
|
|
771
820
|
if (!stats.isDirectory()) {
|
|
772
821
|
throw new Error(`Path is not a directory: ${directoryPath}`);
|
|
773
822
|
}
|
|
@@ -780,14 +829,14 @@ ${formattedList}`;
|
|
|
780
829
|
});
|
|
781
830
|
|
|
782
831
|
// src/builtins/filesystem/read-file.ts
|
|
783
|
-
import
|
|
784
|
-
import { createGadget as
|
|
785
|
-
import { z as
|
|
786
|
-
var readFile =
|
|
832
|
+
import fs4 from "fs";
|
|
833
|
+
import { createGadget as createGadget4 } from "llmist";
|
|
834
|
+
import { z as z4 } from "zod";
|
|
835
|
+
var readFile = createGadget4({
|
|
787
836
|
name: "ReadFile",
|
|
788
837
|
description: "Read the entire content of a file and return it as text. The file path must be within the current working directory or its subdirectories.",
|
|
789
|
-
schema:
|
|
790
|
-
filePath:
|
|
838
|
+
schema: z4.object({
|
|
839
|
+
filePath: z4.string().describe("Path to the file to read (relative or absolute)")
|
|
791
840
|
}),
|
|
792
841
|
examples: [
|
|
793
842
|
{
|
|
@@ -803,7 +852,7 @@ var readFile = createGadget3({
|
|
|
803
852
|
],
|
|
804
853
|
execute: ({ filePath }) => {
|
|
805
854
|
const validatedPath = validatePathIsWithinCwd(filePath);
|
|
806
|
-
const content =
|
|
855
|
+
const content = fs4.readFileSync(validatedPath, "utf-8");
|
|
807
856
|
return `path=${filePath}
|
|
808
857
|
|
|
809
858
|
${content}`;
|
|
@@ -811,18 +860,18 @@ ${content}`;
|
|
|
811
860
|
});
|
|
812
861
|
|
|
813
862
|
// src/builtins/filesystem/write-file.ts
|
|
814
|
-
import
|
|
863
|
+
import fs5 from "fs";
|
|
815
864
|
import path3 from "path";
|
|
816
|
-
import { createGadget as
|
|
817
|
-
import { z as
|
|
818
|
-
var writeFile =
|
|
865
|
+
import { createGadget as createGadget5 } from "llmist";
|
|
866
|
+
import { z as z5 } from "zod";
|
|
867
|
+
var writeFile = createGadget5({
|
|
819
868
|
name: "WriteFile",
|
|
820
869
|
description: "Write content to a file. Creates parent directories if needed. Overwrites existing files. The file path must be within the current working directory or its subdirectories.",
|
|
821
870
|
maxConcurrent: 1,
|
|
822
871
|
// Sequential execution to prevent race conditions
|
|
823
|
-
schema:
|
|
824
|
-
filePath:
|
|
825
|
-
content:
|
|
872
|
+
schema: z5.object({
|
|
873
|
+
filePath: z5.string().describe("Path to the file to write (relative or absolute)"),
|
|
874
|
+
content: z5.string().describe("Content to write to the file")
|
|
826
875
|
}),
|
|
827
876
|
examples: [
|
|
828
877
|
{
|
|
@@ -852,12 +901,12 @@ console.log(\`Server running on http://localhost:\${port}\`);`
|
|
|
852
901
|
const validatedPath = validatePathIsWithinCwd(filePath);
|
|
853
902
|
const parentDir = path3.dirname(validatedPath);
|
|
854
903
|
let createdDir = false;
|
|
855
|
-
if (!
|
|
904
|
+
if (!fs5.existsSync(parentDir)) {
|
|
856
905
|
validatePathIsWithinCwd(parentDir);
|
|
857
|
-
|
|
906
|
+
fs5.mkdirSync(parentDir, { recursive: true });
|
|
858
907
|
createdDir = true;
|
|
859
908
|
}
|
|
860
|
-
|
|
909
|
+
fs5.writeFileSync(validatedPath, content, "utf-8");
|
|
861
910
|
const bytesWritten = Buffer.byteLength(content, "utf-8");
|
|
862
911
|
const dirNote = createdDir ? ` (created directory: ${path3.dirname(filePath)})` : "";
|
|
863
912
|
return `path=${filePath}
|
|
@@ -867,8 +916,8 @@ Wrote ${bytesWritten} bytes${dirNote}`;
|
|
|
867
916
|
});
|
|
868
917
|
|
|
869
918
|
// src/builtins/run-command.ts
|
|
870
|
-
import { createGadget as
|
|
871
|
-
import { z as
|
|
919
|
+
import { createGadget as createGadget6 } from "llmist";
|
|
920
|
+
import { z as z6 } from "zod";
|
|
872
921
|
|
|
873
922
|
// src/spawn.ts
|
|
874
923
|
import { spawn as nodeSpawn } from "child_process";
|
|
@@ -929,13 +978,13 @@ function spawn(argv, options = {}) {
|
|
|
929
978
|
}
|
|
930
979
|
|
|
931
980
|
// src/builtins/run-command.ts
|
|
932
|
-
var runCommand =
|
|
981
|
+
var runCommand = createGadget6({
|
|
933
982
|
name: "RunCommand",
|
|
934
983
|
description: "Execute a command with arguments and return its output. Uses argv array to bypass shell - arguments are passed directly without interpretation. Returns stdout/stderr combined with exit status.",
|
|
935
|
-
schema:
|
|
936
|
-
argv:
|
|
937
|
-
cwd:
|
|
938
|
-
timeout:
|
|
984
|
+
schema: z6.object({
|
|
985
|
+
argv: z6.array(z6.string()).describe("Command and arguments as array (e.g., ['git', 'commit', '-m', 'message'])"),
|
|
986
|
+
cwd: z6.string().optional().describe("Working directory for the command (default: current directory)"),
|
|
987
|
+
timeout: z6.number().default(3e4).describe("Timeout in milliseconds (default: 30000)")
|
|
939
988
|
}),
|
|
940
989
|
examples: [
|
|
941
990
|
{
|
|
@@ -1036,12 +1085,13 @@ error: ${message}`;
|
|
|
1036
1085
|
}
|
|
1037
1086
|
});
|
|
1038
1087
|
export {
|
|
1039
|
-
|
|
1088
|
+
deleteFile as DeleteFile,
|
|
1040
1089
|
listDirectory as ListDirectory,
|
|
1041
1090
|
PathSandboxException,
|
|
1042
1091
|
readFile as ReadFile,
|
|
1043
1092
|
runCommand as RunCommand,
|
|
1044
1093
|
writeFile as WriteFile,
|
|
1094
|
+
deleteFile,
|
|
1045
1095
|
editFile,
|
|
1046
1096
|
listDirectory,
|
|
1047
1097
|
readFile,
|