@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/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 { editFile as EditFile, listDirectory as ListDirectory, PathSandboxException, readFile as ReadFile, runCommand as RunCommand, writeFile as WriteFile, editFile, listDirectory, readFile, runCommand, validatePathIsWithinCwd, writeFile };
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 = cwd + path.sep;
25
- if (!finalPath.startsWith(cwdWithSep) && finalPath !== cwd) {
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/edit-file.ts
32
- import { readFileSync, writeFileSync } from "fs";
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 = createGadget({
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: z.object({
504
- filePath: z.string().describe("Path to the file to edit (relative or absolute)"),
505
- search: z.string().describe("The content to search for in the file"),
506
- replace: z.string().describe("The content to replace it with (empty string to delete)"),
507
- replaceAll: z.boolean().optional().default(false).describe("Replace all occurrences instead of just the first match"),
508
- expectedCount: z.number().int().positive().optional().describe("Expected number of matches. Edit fails if actual count differs")
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 fs2 from "fs";
709
+ import fs3 from "fs";
661
710
  import path2 from "path";
662
- import { createGadget as createGadget2 } from "llmist";
663
- import { z as z2 } from "zod";
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 = fs2.readdirSync(dirPath);
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 = fs2.lstatSync(fullPath);
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 = createGadget2({
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: z2.object({
751
- directoryPath: z2.string().default(".").describe("Path to the directory to list"),
752
- maxDepth: z2.number().int().min(1).max(10).default(3).describe(
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 = fs2.statSync(validatedPath);
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 fs3 from "fs";
784
- import { createGadget as createGadget3 } from "llmist";
785
- import { z as z3 } from "zod";
786
- var readFile = createGadget3({
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: z3.object({
790
- filePath: z3.string().describe("Path to the file to read (relative or absolute)")
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 = fs3.readFileSync(validatedPath, "utf-8");
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 fs4 from "fs";
863
+ import fs5 from "fs";
815
864
  import path3 from "path";
816
- import { createGadget as createGadget4 } from "llmist";
817
- import { z as z4 } from "zod";
818
- var writeFile = createGadget4({
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: z4.object({
824
- filePath: z4.string().describe("Path to the file to write (relative or absolute)"),
825
- content: z4.string().describe("Content to write to the file")
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 (!fs4.existsSync(parentDir)) {
904
+ if (!fs5.existsSync(parentDir)) {
856
905
  validatePathIsWithinCwd(parentDir);
857
- fs4.mkdirSync(parentDir, { recursive: true });
906
+ fs5.mkdirSync(parentDir, { recursive: true });
858
907
  createdDir = true;
859
908
  }
860
- fs4.writeFileSync(validatedPath, content, "utf-8");
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 createGadget5 } from "llmist";
871
- import { z as z5 } from "zod";
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 = createGadget5({
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: z5.object({
936
- argv: z5.array(z5.string()).describe("Command and arguments as array (e.g., ['git', 'commit', '-m', 'message'])"),
937
- cwd: z5.string().optional().describe("Working directory for the command (default: current directory)"),
938
- timeout: z5.number().default(3e4).describe("Timeout in milliseconds (default: 30000)")
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
- editFile as EditFile,
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,