@dexto/tools-filesystem 1.6.0 → 1.6.1

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.
Files changed (73) hide show
  1. package/dist/directory-approval.cjs +44 -40
  2. package/dist/directory-approval.d.ts +8 -4
  3. package/dist/directory-approval.d.ts.map +1 -1
  4. package/dist/directory-approval.integration.test.cjs +107 -356
  5. package/dist/directory-approval.integration.test.d.ts +6 -6
  6. package/dist/directory-approval.integration.test.js +109 -360
  7. package/dist/directory-approval.js +45 -41
  8. package/dist/edit-file-tool.cjs +69 -47
  9. package/dist/edit-file-tool.d.ts.map +1 -1
  10. package/dist/edit-file-tool.js +77 -48
  11. package/dist/edit-file-tool.test.cjs +54 -11
  12. package/dist/edit-file-tool.test.js +54 -11
  13. package/dist/error-codes.cjs +4 -0
  14. package/dist/error-codes.d.ts +4 -0
  15. package/dist/error-codes.d.ts.map +1 -1
  16. package/dist/error-codes.js +4 -0
  17. package/dist/errors.cjs +48 -0
  18. package/dist/errors.d.ts +16 -0
  19. package/dist/errors.d.ts.map +1 -1
  20. package/dist/errors.js +48 -0
  21. package/dist/filesystem-service.cjs +307 -9
  22. package/dist/filesystem-service.d.ts +28 -1
  23. package/dist/filesystem-service.d.ts.map +1 -1
  24. package/dist/filesystem-service.js +308 -10
  25. package/dist/glob-files-tool.cjs +12 -1
  26. package/dist/glob-files-tool.d.ts.map +1 -1
  27. package/dist/glob-files-tool.js +13 -2
  28. package/dist/grep-content-tool.cjs +13 -1
  29. package/dist/grep-content-tool.d.ts.map +1 -1
  30. package/dist/grep-content-tool.js +14 -2
  31. package/dist/index.cjs +3 -0
  32. package/dist/index.d.cts +852 -16
  33. package/dist/index.d.ts +2 -1
  34. package/dist/index.d.ts.map +1 -1
  35. package/dist/index.js +2 -0
  36. package/dist/path-validator.cjs +28 -2
  37. package/dist/path-validator.d.ts +14 -0
  38. package/dist/path-validator.d.ts.map +1 -1
  39. package/dist/path-validator.js +28 -2
  40. package/dist/read-file-tool.cjs +7 -1
  41. package/dist/read-file-tool.d.ts.map +1 -1
  42. package/dist/read-file-tool.js +8 -2
  43. package/dist/tool-factory.cjs +21 -0
  44. package/dist/tool-factory.d.ts.map +1 -1
  45. package/dist/tool-factory.js +21 -0
  46. package/dist/types.d.ts +65 -0
  47. package/dist/types.d.ts.map +1 -1
  48. package/dist/write-file-tool.cjs +60 -38
  49. package/dist/write-file-tool.d.ts +1 -1
  50. package/dist/write-file-tool.d.ts.map +1 -1
  51. package/dist/write-file-tool.js +67 -39
  52. package/dist/write-file-tool.test.cjs +75 -13
  53. package/dist/write-file-tool.test.js +75 -13
  54. package/package.json +4 -4
  55. package/dist/directory-approval.d.cts +0 -22
  56. package/dist/directory-approval.integration.test.d.cts +0 -2
  57. package/dist/edit-file-tool.d.cts +0 -34
  58. package/dist/edit-file-tool.test.d.cts +0 -2
  59. package/dist/error-codes.d.cts +0 -32
  60. package/dist/errors.d.cts +0 -112
  61. package/dist/file-tool-types.d.cts +0 -18
  62. package/dist/filesystem-service.d.cts +0 -117
  63. package/dist/filesystem-service.test.d.cts +0 -2
  64. package/dist/glob-files-tool.d.cts +0 -31
  65. package/dist/grep-content-tool.d.cts +0 -40
  66. package/dist/path-validator.d.cts +0 -97
  67. package/dist/path-validator.test.d.cts +0 -2
  68. package/dist/read-file-tool.d.cts +0 -31
  69. package/dist/tool-factory-config.d.cts +0 -63
  70. package/dist/tool-factory.d.cts +0 -7
  71. package/dist/types.d.cts +0 -178
  72. package/dist/write-file-tool.d.cts +0 -34
  73. package/dist/write-file-tool.test.d.cts +0 -2
package/dist/index.d.ts CHANGED
@@ -6,11 +6,12 @@
6
6
  */
7
7
  export { fileSystemToolsFactory } from './tool-factory.js';
8
8
  export type { FileSystemServiceGetter } from './file-tool-types.js';
9
+ export { FileSystemToolsConfigSchema, type FileSystemToolsConfig } from './tool-factory-config.js';
9
10
  export { FileSystemService } from './filesystem-service.js';
10
11
  export { PathValidator } from './path-validator.js';
11
12
  export { FileSystemError } from './errors.js';
12
13
  export { FileSystemErrorCode } from './error-codes.js';
13
- export type { FileSystemConfig, FileContent, ReadFileOptions, GlobOptions, GlobResult, GrepOptions, SearchResult, SearchMatch, WriteFileOptions, WriteResult, EditFileOptions, EditResult, EditOperation, FileMetadata, PathValidation, BufferEncoding, } from './types.js';
14
+ export type { FileSystemConfig, FileContent, ReadFileOptions, GlobOptions, GlobResult, GrepOptions, SearchResult, SearchMatch, WriteFileOptions, WriteResult, EditFileOptions, EditResult, EditOperation, FileMetadata, DirectoryEntry, ListDirectoryOptions, ListDirectoryResult, CreateDirectoryOptions, CreateDirectoryResult, DeletePathOptions, DeletePathResult, RenamePathResult, PathValidation, BufferEncoding, } from './types.js';
14
15
  export { createReadFileTool } from './read-file-tool.js';
15
16
  export { createWriteFileTool } from './write-file-tool.js';
16
17
  export { createEditFileTool } from './edit-file-tool.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAC3D,YAAY,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAGpE,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAGvD,YAAY,EACR,gBAAgB,EAChB,WAAW,EACX,eAAe,EACf,WAAW,EACX,UAAU,EACV,WAAW,EACX,YAAY,EACZ,WAAW,EACX,gBAAgB,EAChB,WAAW,EACX,eAAe,EACf,UAAU,EACV,aAAa,EACb,YAAY,EACZ,cAAc,EACd,cAAc,GACjB,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAC3D,YAAY,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AACpE,OAAO,EAAE,2BAA2B,EAAE,KAAK,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AAGnG,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAGvD,YAAY,EACR,gBAAgB,EAChB,WAAW,EACX,eAAe,EACf,WAAW,EACX,UAAU,EACV,WAAW,EACX,YAAY,EACZ,WAAW,EACX,gBAAgB,EAChB,WAAW,EACX,eAAe,EACf,UAAU,EACV,aAAa,EACb,YAAY,EACZ,cAAc,EACd,oBAAoB,EACpB,mBAAmB,EACnB,sBAAsB,EACtB,qBAAqB,EACrB,iBAAiB,EACjB,gBAAgB,EAChB,gBAAgB,EAChB,cAAc,EACd,cAAc,GACjB,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC"}
package/dist/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { fileSystemToolsFactory } from "./tool-factory.js";
2
+ import { FileSystemToolsConfigSchema } from "./tool-factory-config.js";
2
3
  import { FileSystemService } from "./filesystem-service.js";
3
4
  import { PathValidator } from "./path-validator.js";
4
5
  import { FileSystemError } from "./errors.js";
@@ -12,6 +13,7 @@ export {
12
13
  FileSystemError,
13
14
  FileSystemErrorCode,
14
15
  FileSystemService,
16
+ FileSystemToolsConfigSchema,
15
17
  PathValidator,
16
18
  createEditFileTool,
17
19
  createGlobFilesTool,
@@ -68,6 +68,24 @@ class PathValidator {
68
68
  * Validate a file path for security and policy compliance
69
69
  */
70
70
  async validatePath(filePath) {
71
+ return this.validatePathInternal(filePath, { skipAllowedCheck: false });
72
+ }
73
+ /**
74
+ * Validate a file path for preview purposes.
75
+ *
76
+ * This is identical to {@link validatePath} except it does NOT enforce config-allowed roots.
77
+ * It still enforces:
78
+ * - traversal protection
79
+ * - blocked paths (absolute blocked paths only; relative blocked paths are resolved against
80
+ * config-allowed roots and may not match paths outside those roots)
81
+ * - blocked extensions
82
+ *
83
+ * Used for generating UI-only previews (e.g., diffs) before the user approves directory access.
84
+ */
85
+ async validatePathForPreview(filePath) {
86
+ return this.validatePathInternal(filePath, { skipAllowedCheck: true });
87
+ }
88
+ async validatePathInternal(filePath, options) {
71
89
  if (!filePath || filePath.trim() === "") {
72
90
  return {
73
91
  isValid: false,
@@ -75,9 +93,11 @@ class PathValidator {
75
93
  };
76
94
  }
77
95
  const workingDir = this.config.workingDirectory || process.cwd();
96
+ let resolvedPath;
78
97
  let normalizedPath;
79
98
  try {
80
- normalizedPath = path.isAbsolute(filePath) ? path.resolve(filePath) : path.resolve(workingDir, filePath);
99
+ resolvedPath = path.isAbsolute(filePath) ? path.resolve(filePath) : path.resolve(workingDir, filePath);
100
+ normalizedPath = resolvedPath;
81
101
  try {
82
102
  normalizedPath = await fs.realpath(normalizedPath);
83
103
  } catch {
@@ -94,7 +114,13 @@ class PathValidator {
94
114
  error: "Path traversal detected"
95
115
  };
96
116
  }
97
- if (!this.isPathAllowed(normalizedPath)) {
117
+ if (options.skipAllowedCheck && this.isInConfigAllowedPaths(resolvedPath) && !this.isInConfigAllowedPaths(normalizedPath)) {
118
+ return {
119
+ isValid: false,
120
+ error: "Symlink target escapes allowed paths"
121
+ };
122
+ }
123
+ if (!options.skipAllowedCheck && !this.isPathAllowed(normalizedPath)) {
98
124
  return {
99
125
  isValid: false,
100
126
  error: `Path is not within allowed paths. Allowed: ${this.normalizedAllowedPaths.join(", ")}`
@@ -42,6 +42,20 @@ export declare class PathValidator {
42
42
  * Validate a file path for security and policy compliance
43
43
  */
44
44
  validatePath(filePath: string): Promise<PathValidation>;
45
+ /**
46
+ * Validate a file path for preview purposes.
47
+ *
48
+ * This is identical to {@link validatePath} except it does NOT enforce config-allowed roots.
49
+ * It still enforces:
50
+ * - traversal protection
51
+ * - blocked paths (absolute blocked paths only; relative blocked paths are resolved against
52
+ * config-allowed roots and may not match paths outside those roots)
53
+ * - blocked extensions
54
+ *
55
+ * Used for generating UI-only previews (e.g., diffs) before the user approves directory access.
56
+ */
57
+ validatePathForPreview(filePath: string): Promise<PathValidation>;
58
+ private validatePathInternal;
45
59
  /**
46
60
  * Check if path contains traversal attempts
47
61
  */
@@ -1 +1 @@
1
- {"version":3,"file":"path-validator.d.ts","sourceRoot":"","sources":["../src/path-validator.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC9D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C;;;GAGG;AACH,MAAM,MAAM,wBAAwB,GAAG,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC;AAErE;;;;;;;;;;;;GAYG;AACH,qBAAa,aAAa;IACtB,OAAO,CAAC,MAAM,CAAmB;IACjC,OAAO,CAAC,sBAAsB,CAAW;IACzC,OAAO,CAAC,sBAAsB,CAAW;IACzC,OAAO,CAAC,2BAA2B,CAAW;IAC9C,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,wBAAwB,CAAuC;gBAE3D,MAAM,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM;IAsBpD;;;;;OAKG;IACH,2BAA2B,CAAC,OAAO,EAAE,wBAAwB,GAAG,IAAI;IAKpE;;OAEG;IACG,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IAyE7D;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAaxB;;;;OAIG;IACH,OAAO,CAAC,aAAa;IAIrB;;OAEG;IACH,OAAO,CAAC,aAAa;IAyBrB;;;OAGG;IACH,kBAAkB,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO;IAInD;;;OAGG;IACH,OAAO,CAAC,iBAAiB;IAyBzB;;;;;;;;;OASG;IACG,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IA8B7D;;;OAGG;IACH,OAAO,CAAC,sBAAsB;IAY9B;;OAEG;IACH,eAAe,IAAI,MAAM,EAAE;IAI3B;;OAEG;IACH,eAAe,IAAI,MAAM,EAAE;CAG9B"}
1
+ {"version":3,"file":"path-validator.d.ts","sourceRoot":"","sources":["../src/path-validator.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC9D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C;;;GAGG;AACH,MAAM,MAAM,wBAAwB,GAAG,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC;AAErE;;;;;;;;;;;;GAYG;AACH,qBAAa,aAAa;IACtB,OAAO,CAAC,MAAM,CAAmB;IACjC,OAAO,CAAC,sBAAsB,CAAW;IACzC,OAAO,CAAC,sBAAsB,CAAW;IACzC,OAAO,CAAC,2BAA2B,CAAW;IAC9C,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,wBAAwB,CAAuC;gBAE3D,MAAM,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM;IAsBpD;;;;;OAKG;IACH,2BAA2B,CAAC,OAAO,EAAE,wBAAwB,GAAG,IAAI;IAKpE;;OAEG;IACG,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IAI7D;;;;;;;;;;;OAWG;IACG,sBAAsB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;YAIzD,oBAAoB;IAyFlC;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAaxB;;;;OAIG;IACH,OAAO,CAAC,aAAa;IAIrB;;OAEG;IACH,OAAO,CAAC,aAAa;IAyBrB;;;OAGG;IACH,kBAAkB,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO;IAInD;;;OAGG;IACH,OAAO,CAAC,iBAAiB;IAyBzB;;;;;;;;;OASG;IACG,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IA8B7D;;;OAGG;IACH,OAAO,CAAC,sBAAsB;IAY9B;;OAEG;IACH,eAAe,IAAI,MAAM,EAAE;IAI3B;;OAEG;IACH,eAAe,IAAI,MAAM,EAAE;CAG9B"}
@@ -35,6 +35,24 @@ class PathValidator {
35
35
  * Validate a file path for security and policy compliance
36
36
  */
37
37
  async validatePath(filePath) {
38
+ return this.validatePathInternal(filePath, { skipAllowedCheck: false });
39
+ }
40
+ /**
41
+ * Validate a file path for preview purposes.
42
+ *
43
+ * This is identical to {@link validatePath} except it does NOT enforce config-allowed roots.
44
+ * It still enforces:
45
+ * - traversal protection
46
+ * - blocked paths (absolute blocked paths only; relative blocked paths are resolved against
47
+ * config-allowed roots and may not match paths outside those roots)
48
+ * - blocked extensions
49
+ *
50
+ * Used for generating UI-only previews (e.g., diffs) before the user approves directory access.
51
+ */
52
+ async validatePathForPreview(filePath) {
53
+ return this.validatePathInternal(filePath, { skipAllowedCheck: true });
54
+ }
55
+ async validatePathInternal(filePath, options) {
38
56
  if (!filePath || filePath.trim() === "") {
39
57
  return {
40
58
  isValid: false,
@@ -42,9 +60,11 @@ class PathValidator {
42
60
  };
43
61
  }
44
62
  const workingDir = this.config.workingDirectory || process.cwd();
63
+ let resolvedPath;
45
64
  let normalizedPath;
46
65
  try {
47
- normalizedPath = path.isAbsolute(filePath) ? path.resolve(filePath) : path.resolve(workingDir, filePath);
66
+ resolvedPath = path.isAbsolute(filePath) ? path.resolve(filePath) : path.resolve(workingDir, filePath);
67
+ normalizedPath = resolvedPath;
48
68
  try {
49
69
  normalizedPath = await fs.realpath(normalizedPath);
50
70
  } catch {
@@ -61,7 +81,13 @@ class PathValidator {
61
81
  error: "Path traversal detected"
62
82
  };
63
83
  }
64
- if (!this.isPathAllowed(normalizedPath)) {
84
+ if (options.skipAllowedCheck && this.isInConfigAllowedPaths(resolvedPath) && !this.isInConfigAllowedPaths(normalizedPath)) {
85
+ return {
86
+ isValid: false,
87
+ error: "Symlink target escapes allowed paths"
88
+ };
89
+ }
90
+ if (!options.skipAllowedCheck && !this.isPathAllowed(normalizedPath)) {
65
91
  return {
66
92
  isValid: false,
67
93
  error: `Path is not within allowed paths. Allowed: ${this.normalizedAllowedPaths.join(", ")}`
@@ -32,13 +32,19 @@ const ReadFileInputSchema = import_zod.z.object({
32
32
  function createReadFileTool(getFileSystemService) {
33
33
  return (0, import_core.defineTool)({
34
34
  id: "read_file",
35
- displayName: "Read",
36
35
  aliases: ["read"],
37
36
  description: "Read the contents of a file with optional pagination. Returns file content, line count, encoding, and whether the output was truncated. Use limit and offset parameters for large files to read specific sections. This tool is for reading files within allowed paths only.",
38
37
  inputSchema: ReadFileInputSchema,
38
+ presentation: {
39
+ describeHeader: (input) => (0, import_core.createLocalToolCallHeader)({
40
+ title: "Read",
41
+ argsText: (0, import_core.truncateForHeader)(input.file_path, 140)
42
+ })
43
+ },
39
44
  ...(0, import_directory_approval.createDirectoryAccessApprovalHandlers)({
40
45
  toolName: "read_file",
41
46
  operation: "read",
47
+ inputSchema: ReadFileInputSchema,
42
48
  getFileSystemService,
43
49
  resolvePaths: (input, fileSystemService) => (0, import_directory_approval.resolveFilePath)(fileSystemService.getWorkingDirectory(), input.file_path)
44
50
  }),
@@ -1 +1 @@
1
- {"version":3,"file":"read-file-tool.d.ts","sourceRoot":"","sources":["../src/read-file-tool.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,EAAmB,IAAI,EAAwB,MAAM,aAAa,CAAC;AAC/E,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAGpE,QAAA,MAAM,mBAAmB;;;;;;;;;;;;EAgBZ,CAAC;AAEd;;GAEG;AACH,wBAAgB,kBAAkB,CAC9B,oBAAoB,EAAE,uBAAuB,GAC9C,IAAI,CAAC,OAAO,mBAAmB,CAAC,CAqDlC"}
1
+ {"version":3,"file":"read-file-tool.d.ts","sourceRoot":"","sources":["../src/read-file-tool.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,EAAmB,IAAI,EAAwB,MAAM,aAAa,CAAC;AAC/E,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAGpE,QAAA,MAAM,mBAAmB;;;;;;;;;;;;EAgBZ,CAAC;AAEd;;GAEG;AACH,wBAAgB,kBAAkB,CAC9B,oBAAoB,EAAE,uBAAuB,GAC9C,IAAI,CAAC,OAAO,mBAAmB,CAAC,CA6DlC"}
@@ -1,5 +1,5 @@
1
1
  import { z } from "zod";
2
- import { defineTool } from "@dexto/core";
2
+ import { createLocalToolCallHeader, defineTool, truncateForHeader } from "@dexto/core";
3
3
  import { createDirectoryAccessApprovalHandlers, resolveFilePath } from "./directory-approval.js";
4
4
  const ReadFileInputSchema = z.object({
5
5
  file_path: z.string().min(1).describe("Absolute path to the file to read"),
@@ -9,13 +9,19 @@ const ReadFileInputSchema = z.object({
9
9
  function createReadFileTool(getFileSystemService) {
10
10
  return defineTool({
11
11
  id: "read_file",
12
- displayName: "Read",
13
12
  aliases: ["read"],
14
13
  description: "Read the contents of a file with optional pagination. Returns file content, line count, encoding, and whether the output was truncated. Use limit and offset parameters for large files to read specific sections. This tool is for reading files within allowed paths only.",
15
14
  inputSchema: ReadFileInputSchema,
15
+ presentation: {
16
+ describeHeader: (input) => createLocalToolCallHeader({
17
+ title: "Read",
18
+ argsText: truncateForHeader(input.file_path, 140)
19
+ })
20
+ },
16
21
  ...createDirectoryAccessApprovalHandlers({
17
22
  toolName: "read_file",
18
23
  operation: "read",
24
+ inputSchema: ReadFileInputSchema,
19
25
  getFileSystemService,
20
26
  resolvePaths: (input, fileSystemService) => resolveFilePath(fileSystemService.getWorkingDirectory(), input.file_path)
21
27
  }),
@@ -53,7 +53,28 @@ const fileSystemToolsFactory = {
53
53
  const workingDirectory = resolveWorkingDirectory(context);
54
54
  service.setWorkingDirectory(workingDirectory);
55
55
  };
56
+ const resolveInjectedService = (context) => {
57
+ const candidate = context.services?.filesystemService;
58
+ if (!candidate) return null;
59
+ if (candidate instanceof import_filesystem_service.FileSystemService) return candidate;
60
+ const hasMethods = typeof candidate.readFile === "function" && typeof candidate.writeFile === "function" && typeof candidate.setWorkingDirectory === "function" && typeof candidate.setDirectoryApprovalChecker === "function";
61
+ return hasMethods ? candidate : null;
62
+ };
56
63
  const getFileSystemService = async (context) => {
64
+ const injectedService = resolveInjectedService(context);
65
+ if (injectedService) {
66
+ const approvalManager2 = context.services?.approval;
67
+ if (!approvalManager2) {
68
+ throw import_core.ToolError.configInvalid(
69
+ "filesystem-tools requires ToolExecutionContext.services.approval"
70
+ );
71
+ }
72
+ injectedService.setDirectoryApprovalChecker(
73
+ (filePath) => approvalManager2.isDirectoryApproved(filePath)
74
+ );
75
+ applyWorkspace(context, injectedService);
76
+ return injectedService;
77
+ }
57
78
  if (fileSystemService) {
58
79
  const approvalManager2 = context.services?.approval;
59
80
  if (!approvalManager2) {
@@ -1 +1 @@
1
- {"version":3,"file":"tool-factory.d.ts","sourceRoot":"","sources":["../src/tool-factory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AASvD,OAAO,EAGH,KAAK,qBAAqB,EAC7B,MAAM,0BAA0B,CAAC;AAKlC,eAAO,MAAM,sBAAsB,EAAE,WAAW,CAAC,qBAAqB,CAgFrE,CAAC"}
1
+ {"version":3,"file":"tool-factory.d.ts","sourceRoot":"","sources":["../src/tool-factory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AASvD,OAAO,EAGH,KAAK,qBAAqB,EAC7B,MAAM,0BAA0B,CAAC;AAKlC,eAAO,MAAM,sBAAsB,EAAE,WAAW,CAAC,qBAAqB,CA8GrE,CAAC"}
@@ -33,7 +33,28 @@ const fileSystemToolsFactory = {
33
33
  const workingDirectory = resolveWorkingDirectory(context);
34
34
  service.setWorkingDirectory(workingDirectory);
35
35
  };
36
+ const resolveInjectedService = (context) => {
37
+ const candidate = context.services?.filesystemService;
38
+ if (!candidate) return null;
39
+ if (candidate instanceof FileSystemService) return candidate;
40
+ const hasMethods = typeof candidate.readFile === "function" && typeof candidate.writeFile === "function" && typeof candidate.setWorkingDirectory === "function" && typeof candidate.setDirectoryApprovalChecker === "function";
41
+ return hasMethods ? candidate : null;
42
+ };
36
43
  const getFileSystemService = async (context) => {
44
+ const injectedService = resolveInjectedService(context);
45
+ if (injectedService) {
46
+ const approvalManager2 = context.services?.approval;
47
+ if (!approvalManager2) {
48
+ throw ToolError.configInvalid(
49
+ "filesystem-tools requires ToolExecutionContext.services.approval"
50
+ );
51
+ }
52
+ injectedService.setDirectoryApprovalChecker(
53
+ (filePath) => approvalManager2.isDirectoryApproved(filePath)
54
+ );
55
+ applyWorkspace(context, injectedService);
56
+ return injectedService;
57
+ }
37
58
  if (fileSystemService) {
38
59
  const approvalManager2 = context.services?.approval;
39
60
  if (!approvalManager2) {
package/dist/types.d.ts CHANGED
@@ -36,6 +36,71 @@ export interface FileMetadata {
36
36
  modified: Date;
37
37
  isDirectory: boolean;
38
38
  }
39
+ /**
40
+ * Directory entry metadata
41
+ */
42
+ export interface DirectoryEntry {
43
+ name: string;
44
+ path: string;
45
+ isDirectory: boolean;
46
+ size: number;
47
+ modified: Date;
48
+ }
49
+ /**
50
+ * Options for listing directory contents
51
+ */
52
+ export interface ListDirectoryOptions {
53
+ /** Include hidden files/directories (dotfiles) */
54
+ includeHidden?: boolean | undefined;
55
+ /** Include stat metadata */
56
+ includeMetadata?: boolean | undefined;
57
+ /** Maximum number of entries to return */
58
+ maxEntries?: number | undefined;
59
+ }
60
+ /**
61
+ * Directory listing result
62
+ */
63
+ export interface ListDirectoryResult {
64
+ path: string;
65
+ entries: DirectoryEntry[];
66
+ truncated: boolean;
67
+ totalEntries: number;
68
+ }
69
+ /**
70
+ * Options for creating directories
71
+ */
72
+ export interface CreateDirectoryOptions {
73
+ /** Create intermediate directories if they don't exist */
74
+ recursive?: boolean | undefined;
75
+ }
76
+ /**
77
+ * Create directory result
78
+ */
79
+ export interface CreateDirectoryResult {
80
+ path: string;
81
+ created: boolean;
82
+ }
83
+ /**
84
+ * Options for deleting paths
85
+ */
86
+ export interface DeletePathOptions {
87
+ /** Recursively delete directories */
88
+ recursive?: boolean | undefined;
89
+ }
90
+ /**
91
+ * Delete path result
92
+ */
93
+ export interface DeletePathResult {
94
+ path: string;
95
+ deleted: boolean;
96
+ }
97
+ /**
98
+ * Rename path result
99
+ */
100
+ export interface RenamePathResult {
101
+ from: string;
102
+ to: string;
103
+ }
39
104
  /**
40
105
  * Options for glob operations
41
106
  */
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
@@ -46,6 +46,7 @@ function generateDiffPreview(filePath, originalContent, newContent) {
46
46
  const deletions = (unified.match(/^-[^-]/gm) || []).length;
47
47
  return {
48
48
  type: "diff",
49
+ title: "Update file",
49
50
  unified,
50
51
  filename: filePath,
51
52
  additions,
@@ -55,55 +56,74 @@ function generateDiffPreview(filePath, originalContent, newContent) {
55
56
  function createWriteFileTool(getFileSystemService) {
56
57
  return (0, import_core.defineTool)({
57
58
  id: "write_file",
58
- displayName: "Write",
59
59
  aliases: ["write"],
60
60
  description: "Write content to a file. Creates a new file or overwrites existing file. Automatically creates backup of existing files before overwriting. Use create_dirs to create parent directories. Requires approval for all write operations. Returns success status, path, bytes written, and backup path if applicable.",
61
61
  inputSchema: WriteFileInputSchema,
62
62
  ...(0, import_directory_approval.createDirectoryAccessApprovalHandlers)({
63
63
  toolName: "write_file",
64
64
  operation: "write",
65
+ inputSchema: WriteFileInputSchema,
65
66
  getFileSystemService,
66
67
  resolvePaths: (input, fileSystemService) => (0, import_directory_approval.resolveFilePath)(fileSystemService.getWorkingDirectory(), input.file_path)
67
68
  }),
68
- /**
69
- * Generate preview for approval UI - shows diff or file creation info
70
- * Stores content hash for change detection in execute phase.
71
- */
72
- async generatePreview(input, context) {
73
- const { file_path, content } = input;
74
- const resolvedFileSystemService = await getFileSystemService(context);
75
- const { path: resolvedPath } = (0, import_directory_approval.resolveFilePath)(
76
- resolvedFileSystemService.getWorkingDirectory(),
77
- file_path
78
- );
79
- try {
80
- const originalFile = await resolvedFileSystemService.readFile(resolvedPath);
81
- const originalContent = originalFile.content;
82
- if (context.toolCallId) {
83
- previewContentHashCache.set(
84
- context.toolCallId,
85
- computeContentHash(originalContent)
86
- );
87
- }
88
- return generateDiffPreview(resolvedPath, originalContent, content);
89
- } catch (error) {
90
- if (error instanceof import_core.DextoRuntimeError && error.code === import_error_codes.FileSystemErrorCode.FILE_NOT_FOUND) {
69
+ presentation: {
70
+ describeHeader: (input) => (0, import_core.createLocalToolCallHeader)({
71
+ title: "Write",
72
+ argsText: (0, import_core.truncateForHeader)(input.file_path, 140)
73
+ }),
74
+ /**
75
+ * Generate preview for approval UI - shows diff or file creation info
76
+ * Stores content hash for change detection in execute phase.
77
+ */
78
+ preview: async (input, context) => {
79
+ const { file_path, content } = input;
80
+ const resolvedFileSystemService = await getFileSystemService(context);
81
+ const { path: resolvedPath } = (0, import_directory_approval.resolveFilePath)(
82
+ resolvedFileSystemService.getWorkingDirectory(),
83
+ file_path
84
+ );
85
+ try {
86
+ let originalContent;
87
+ try {
88
+ const originalFile = await resolvedFileSystemService.readFile(resolvedPath);
89
+ originalContent = originalFile.content;
90
+ } catch (error) {
91
+ if (error instanceof import_core.DextoRuntimeError && error.code === import_error_codes.FileSystemErrorCode.INVALID_PATH) {
92
+ const originalFile = await resolvedFileSystemService.readFileForToolPreview(
93
+ resolvedPath
94
+ );
95
+ originalContent = originalFile.content;
96
+ } else {
97
+ throw error;
98
+ }
99
+ }
91
100
  if (context.toolCallId) {
92
- previewContentHashCache.set(context.toolCallId, FILE_NOT_EXISTS_MARKER);
101
+ previewContentHashCache.set(
102
+ context.toolCallId,
103
+ computeContentHash(originalContent)
104
+ );
105
+ }
106
+ return generateDiffPreview(resolvedPath, originalContent, content);
107
+ } catch (error) {
108
+ if (error instanceof import_core.DextoRuntimeError && error.code === import_error_codes.FileSystemErrorCode.FILE_NOT_FOUND) {
109
+ if (context.toolCallId) {
110
+ previewContentHashCache.set(context.toolCallId, FILE_NOT_EXISTS_MARKER);
111
+ }
112
+ const lineCount = content.split("\n").length;
113
+ const preview = {
114
+ type: "file",
115
+ title: "Create file",
116
+ path: resolvedPath,
117
+ operation: "create",
118
+ size: Buffer.byteLength(content, "utf8"),
119
+ lineCount,
120
+ content
121
+ // Include content for approval preview
122
+ };
123
+ return preview;
93
124
  }
94
- const lineCount = content.split("\n").length;
95
- const preview = {
96
- type: "file",
97
- path: resolvedPath,
98
- operation: "create",
99
- size: Buffer.byteLength(content, "utf8"),
100
- lineCount,
101
- content
102
- // Include content for approval preview
103
- };
104
- return preview;
125
+ throw error;
105
126
  }
106
- throw error;
107
127
  }
108
128
  },
109
129
  async execute(input, context) {
@@ -159,10 +179,12 @@ function createWriteFileTool(getFileSystemService) {
159
179
  const lineCount = content.split("\n").length;
160
180
  _display = {
161
181
  type: "file",
182
+ title: "Create file",
162
183
  path: resolvedPath,
163
184
  operation: "create",
164
185
  size: result.bytesWritten,
165
- lineCount
186
+ lineCount,
187
+ content
166
188
  };
167
189
  } else {
168
190
  _display = generateDiffPreview(resolvedPath, originalContent, content);
@@ -12,8 +12,8 @@ declare const WriteFileInputSchema: z.ZodObject<{
12
12
  create_dirs: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
13
13
  encoding: z.ZodDefault<z.ZodOptional<z.ZodEnum<["utf-8", "ascii", "latin1", "utf16le"]>>>;
14
14
  }, "strict", z.ZodTypeAny, {
15
- encoding: "ascii" | "utf-8" | "utf16le" | "latin1";
16
15
  content: string;
16
+ encoding: "ascii" | "utf-8" | "utf16le" | "latin1";
17
17
  file_path: string;
18
18
  create_dirs: boolean;
19
19
  }, {
@@ -1 +1 @@
1
- {"version":3,"file":"write-file-tool.d.ts","sourceRoot":"","sources":["../src/write-file-tool.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,OAAO,KAAK,EAAE,IAAI,EAAwB,MAAM,aAAa,CAAC;AAG9D,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAuBpE,QAAA,MAAM,oBAAoB;;;;;;;;;;;;;;;EAeb,CAAC;AAyBd;;GAEG;AACH,wBAAgB,mBAAmB,CAC/B,oBAAoB,EAAE,uBAAuB,GAC9C,IAAI,CAAC,OAAO,oBAAoB,CAAC,CA0KnC"}
1
+ {"version":3,"file":"write-file-tool.d.ts","sourceRoot":"","sources":["../src/write-file-tool.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAUxB,OAAO,KAAK,EAAE,IAAI,EAAwB,MAAM,aAAa,CAAC;AAG9D,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAuBpE,QAAA,MAAM,oBAAoB;;;;;;;;;;;;;;;EAeb,CAAC;AA0Bd;;GAEG;AACH,wBAAgB,mBAAmB,CAC/B,oBAAoB,EAAE,uBAAuB,GAC9C,IAAI,CAAC,OAAO,oBAAoB,CAAC,CAqMnC"}