@dexto/tools-filesystem 1.5.8 → 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 (95) hide show
  1. package/dist/directory-approval.cjs +98 -0
  2. package/dist/directory-approval.d.ts +24 -0
  3. package/dist/directory-approval.d.ts.map +1 -0
  4. package/dist/directory-approval.integration.test.cjs +175 -390
  5. package/dist/directory-approval.integration.test.d.ts +14 -2
  6. package/dist/directory-approval.integration.test.d.ts.map +1 -0
  7. package/dist/directory-approval.integration.test.js +178 -390
  8. package/dist/directory-approval.js +63 -0
  9. package/dist/edit-file-tool.cjs +109 -120
  10. package/dist/edit-file-tool.d.ts +22 -9
  11. package/dist/edit-file-tool.d.ts.map +1 -0
  12. package/dist/edit-file-tool.js +116 -110
  13. package/dist/edit-file-tool.test.cjs +109 -29
  14. package/dist/edit-file-tool.test.d.ts +7 -2
  15. package/dist/edit-file-tool.test.d.ts.map +1 -0
  16. package/dist/edit-file-tool.test.js +109 -29
  17. package/dist/error-codes.cjs +4 -0
  18. package/dist/error-codes.d.ts +6 -3
  19. package/dist/error-codes.d.ts.map +1 -0
  20. package/dist/error-codes.js +4 -0
  21. package/dist/errors.cjs +48 -0
  22. package/dist/errors.d.ts +20 -7
  23. package/dist/errors.d.ts.map +1 -0
  24. package/dist/errors.js +48 -0
  25. package/dist/file-tool-types.d.ts +8 -40
  26. package/dist/file-tool-types.d.ts.map +1 -0
  27. package/dist/filesystem-service.cjs +325 -10
  28. package/dist/filesystem-service.d.ts +41 -12
  29. package/dist/filesystem-service.d.ts.map +1 -0
  30. package/dist/filesystem-service.js +326 -11
  31. package/dist/filesystem-service.test.cjs +10 -2
  32. package/dist/filesystem-service.test.d.ts +7 -2
  33. package/dist/filesystem-service.test.d.ts.map +1 -0
  34. package/dist/filesystem-service.test.js +10 -2
  35. package/dist/glob-files-tool.cjs +32 -46
  36. package/dist/glob-files-tool.d.ts +19 -9
  37. package/dist/glob-files-tool.d.ts.map +1 -0
  38. package/dist/glob-files-tool.js +33 -47
  39. package/dist/grep-content-tool.cjs +40 -45
  40. package/dist/grep-content-tool.d.ts +28 -9
  41. package/dist/grep-content-tool.d.ts.map +1 -0
  42. package/dist/grep-content-tool.js +41 -46
  43. package/dist/index.cjs +6 -3
  44. package/dist/index.d.cts +852 -14
  45. package/dist/index.d.ts +11 -5
  46. package/dist/index.d.ts.map +1 -0
  47. package/dist/index.js +4 -2
  48. package/dist/path-validator.cjs +28 -2
  49. package/dist/path-validator.d.ts +20 -9
  50. package/dist/path-validator.d.ts.map +1 -0
  51. package/dist/path-validator.js +28 -2
  52. package/dist/path-validator.test.d.ts +7 -2
  53. package/dist/path-validator.test.d.ts.map +1 -0
  54. package/dist/read-file-tool.cjs +26 -59
  55. package/dist/read-file-tool.d.ts +19 -9
  56. package/dist/read-file-tool.d.ts.map +1 -0
  57. package/dist/read-file-tool.js +27 -50
  58. package/dist/tool-factory-config.cjs +61 -0
  59. package/dist/{tool-provider.d.ts → tool-factory-config.d.ts} +13 -30
  60. package/dist/tool-factory-config.d.ts.map +1 -0
  61. package/dist/tool-factory-config.js +36 -0
  62. package/dist/tool-factory.cjs +123 -0
  63. package/dist/tool-factory.d.ts +4 -0
  64. package/dist/tool-factory.d.ts.map +1 -0
  65. package/dist/tool-factory.js +102 -0
  66. package/dist/types.d.ts +82 -18
  67. package/dist/types.d.ts.map +1 -0
  68. package/dist/write-file-tool.cjs +93 -99
  69. package/dist/write-file-tool.d.ts +22 -9
  70. package/dist/write-file-tool.d.ts.map +1 -0
  71. package/dist/write-file-tool.js +97 -91
  72. package/dist/write-file-tool.test.cjs +139 -33
  73. package/dist/write-file-tool.test.d.ts +7 -2
  74. package/dist/write-file-tool.test.d.ts.map +1 -0
  75. package/dist/write-file-tool.test.js +139 -33
  76. package/package.json +5 -4
  77. package/dist/directory-approval.integration.test.d.cts +0 -2
  78. package/dist/edit-file-tool.d.cts +0 -17
  79. package/dist/edit-file-tool.test.d.cts +0 -2
  80. package/dist/error-codes.d.cts +0 -32
  81. package/dist/errors.d.cts +0 -112
  82. package/dist/file-tool-types.d.cts +0 -46
  83. package/dist/filesystem-service.d.cts +0 -112
  84. package/dist/filesystem-service.test.d.cts +0 -2
  85. package/dist/glob-files-tool.d.cts +0 -17
  86. package/dist/grep-content-tool.d.cts +0 -17
  87. package/dist/path-validator.d.cts +0 -97
  88. package/dist/path-validator.test.d.cts +0 -2
  89. package/dist/read-file-tool.d.cts +0 -17
  90. package/dist/tool-provider.cjs +0 -123
  91. package/dist/tool-provider.d.cts +0 -77
  92. package/dist/tool-provider.js +0 -99
  93. package/dist/types.d.cts +0 -178
  94. package/dist/write-file-tool.d.cts +0 -17
  95. package/dist/write-file-tool.test.d.cts +0 -2
package/dist/index.d.ts CHANGED
@@ -1,14 +1,20 @@
1
- export { fileSystemToolsProvider } from './tool-provider.js';
2
- export { DirectoryApprovalCallbacks, FileToolOptions } from './file-tool-types.js';
1
+ /**
2
+ * @dexto/tools-filesystem
3
+ *
4
+ * FileSystem tools factory for Dexto agents.
5
+ * Provides file operation tools: read, write, edit, glob, grep.
6
+ */
7
+ export { fileSystemToolsFactory } from './tool-factory.js';
8
+ export type { FileSystemServiceGetter } from './file-tool-types.js';
9
+ export { FileSystemToolsConfigSchema, type FileSystemToolsConfig } from './tool-factory-config.js';
3
10
  export { FileSystemService } from './filesystem-service.js';
4
11
  export { PathValidator } from './path-validator.js';
5
12
  export { FileSystemError } from './errors.js';
6
13
  export { FileSystemErrorCode } from './error-codes.js';
7
- export { BufferEncoding, EditFileOptions, EditOperation, EditResult, FileContent, FileMetadata, FileSystemConfig, GlobOptions, GlobResult, GrepOptions, PathValidation, ReadFileOptions, SearchMatch, SearchResult, WriteFileOptions, WriteResult } 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';
8
15
  export { createReadFileTool } from './read-file-tool.js';
9
16
  export { createWriteFileTool } from './write-file-tool.js';
10
17
  export { createEditFileTool } from './edit-file-tool.js';
11
18
  export { createGlobFilesTool } from './glob-files-tool.js';
12
19
  export { createGrepContentTool } from './grep-content-tool.js';
13
- import 'zod';
14
- import '@dexto/core';
20
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +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;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
- import { fileSystemToolsProvider } from "./tool-provider.js";
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,11 +13,12 @@ export {
12
13
  FileSystemError,
13
14
  FileSystemErrorCode,
14
15
  FileSystemService,
16
+ FileSystemToolsConfigSchema,
15
17
  PathValidator,
16
18
  createEditFileTool,
17
19
  createGlobFilesTool,
18
20
  createGrepContentTool,
19
21
  createReadFileTool,
20
22
  createWriteFileTool,
21
- fileSystemToolsProvider
23
+ fileSystemToolsFactory
22
24
  };
@@ -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(", ")}`
@@ -1,17 +1,15 @@
1
- import { FileSystemConfig, PathValidation } from './types.js';
2
- import { IDextoLogger } from '@dexto/core';
3
-
4
1
  /**
5
2
  * Path Validator
6
3
  *
7
4
  * Security-focused path validation for file system operations
8
5
  */
9
-
6
+ import { FileSystemConfig, PathValidation } from './types.js';
7
+ import type { Logger } from '@dexto/core';
10
8
  /**
11
9
  * Callback type for checking if a path is in an approved directory.
12
10
  * Used to consult ApprovalManager without creating a direct dependency.
13
11
  */
14
- type DirectoryApprovalChecker = (filePath: string) => boolean;
12
+ export type DirectoryApprovalChecker = (filePath: string) => boolean;
15
13
  /**
16
14
  * PathValidator - Validates file paths for security and policy compliance
17
15
  *
@@ -25,14 +23,14 @@ type DirectoryApprovalChecker = (filePath: string) => boolean;
25
23
  * PathValidator can optionally consult an external approval checker (e.g., ApprovalManager)
26
24
  * to determine if paths outside the config's allowed paths are accessible.
27
25
  */
28
- declare class PathValidator {
26
+ export declare class PathValidator {
29
27
  private config;
30
28
  private normalizedAllowedPaths;
31
29
  private normalizedBlockedPaths;
32
30
  private normalizedBlockedExtensions;
33
31
  private logger;
34
32
  private directoryApprovalChecker;
35
- constructor(config: FileSystemConfig, logger: IDextoLogger);
33
+ constructor(config: FileSystemConfig, logger: Logger);
36
34
  /**
37
35
  * Set a callback to check if a path is in an approved directory.
38
36
  * This allows PathValidator to consult ApprovalManager without a direct dependency.
@@ -44,6 +42,20 @@ declare class PathValidator {
44
42
  * Validate a file path for security and policy compliance
45
43
  */
46
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;
47
59
  /**
48
60
  * Check if path contains traversal attempts
49
61
  */
@@ -93,5 +105,4 @@ declare class PathValidator {
93
105
  */
94
106
  getBlockedPaths(): string[];
95
107
  }
96
-
97
- export { type DirectoryApprovalChecker, PathValidator };
108
+ //# sourceMappingURL=path-validator.d.ts.map
@@ -0,0 +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;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(", ")}`
@@ -1,2 +1,7 @@
1
-
2
- export { }
1
+ /**
2
+ * PathValidator Unit Tests
3
+ *
4
+ * Tests for path validation, security checks, and allowed path logic.
5
+ */
6
+ export {};
7
+ //# sourceMappingURL=path-validator.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"path-validator.test.d.ts","sourceRoot":"","sources":["../src/path-validator.test.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
@@ -1,9 +1,7 @@
1
1
  "use strict";
2
- var __create = Object.create;
3
2
  var __defProp = Object.defineProperty;
4
3
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
4
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __getProtoOf = Object.getPrototypeOf;
7
5
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
6
  var __export = (target, all) => {
9
7
  for (var name in all)
@@ -17,84 +15,53 @@ var __copyProps = (to, from, except, desc) => {
17
15
  }
18
16
  return to;
19
17
  };
20
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
- // If the importer is in node compatibility mode or this is not an ESM
22
- // file that has been converted to a CommonJS file using a Babel-
23
- // compatible transform (i.e. "__esModule" has not been set), then set
24
- // "default" to the CommonJS "module.exports" for node compatibility.
25
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
- mod
27
- ));
28
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
19
  var read_file_tool_exports = {};
30
20
  __export(read_file_tool_exports, {
31
21
  createReadFileTool: () => createReadFileTool
32
22
  });
33
23
  module.exports = __toCommonJS(read_file_tool_exports);
34
- var path = __toESM(require("node:path"), 1);
35
24
  var import_zod = require("zod");
36
25
  var import_core = require("@dexto/core");
26
+ var import_directory_approval = require("./directory-approval.js");
37
27
  const ReadFileInputSchema = import_zod.z.object({
38
- file_path: import_zod.z.string().describe("Absolute path to the file to read"),
28
+ file_path: import_zod.z.string().min(1).describe("Absolute path to the file to read"),
39
29
  limit: import_zod.z.number().int().positive().optional().describe("Maximum number of lines to read (optional)"),
40
30
  offset: import_zod.z.number().int().min(1).optional().describe("Starting line number (1-based, optional)")
41
31
  }).strict();
42
- function createReadFileTool(options) {
43
- const { fileSystemService, directoryApproval } = options;
44
- let pendingApprovalParentDir;
45
- return {
32
+ function createReadFileTool(getFileSystemService) {
33
+ return (0, import_core.defineTool)({
46
34
  id: "read_file",
35
+ aliases: ["read"],
47
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.",
48
37
  inputSchema: ReadFileInputSchema,
49
- /**
50
- * Check if this read operation needs directory access approval.
51
- * Returns custom approval request if the file is outside allowed paths.
52
- */
53
- getApprovalOverride: async (args) => {
54
- const { file_path } = args;
55
- if (!file_path) return null;
56
- const isAllowed = await fileSystemService.isPathWithinConfigAllowed(file_path);
57
- if (isAllowed) {
58
- return null;
59
- }
60
- if (directoryApproval?.isSessionApproved(file_path)) {
61
- return null;
62
- }
63
- const absolutePath = path.resolve(file_path);
64
- const parentDir = path.dirname(absolutePath);
65
- pendingApprovalParentDir = parentDir;
66
- return {
67
- type: import_core.ApprovalType.DIRECTORY_ACCESS,
68
- metadata: {
69
- path: absolutePath,
70
- parentDir,
71
- operation: "read",
72
- toolName: "read_file"
73
- }
74
- };
38
+ presentation: {
39
+ describeHeader: (input) => (0, import_core.createLocalToolCallHeader)({
40
+ title: "Read",
41
+ argsText: (0, import_core.truncateForHeader)(input.file_path, 140)
42
+ })
75
43
  },
76
- /**
77
- * Handle approved directory access - remember the directory for session
78
- */
79
- onApprovalGranted: (response) => {
80
- if (!directoryApproval || !pendingApprovalParentDir) return;
81
- const data = response.data;
82
- const rememberDirectory = data?.rememberDirectory ?? false;
83
- directoryApproval.addApproved(
84
- pendingApprovalParentDir,
85
- rememberDirectory ? "session" : "once"
86
- );
87
- pendingApprovalParentDir = void 0;
88
- },
89
- execute: async (input, _context) => {
44
+ ...(0, import_directory_approval.createDirectoryAccessApprovalHandlers)({
45
+ toolName: "read_file",
46
+ operation: "read",
47
+ inputSchema: ReadFileInputSchema,
48
+ getFileSystemService,
49
+ resolvePaths: (input, fileSystemService) => (0, import_directory_approval.resolveFilePath)(fileSystemService.getWorkingDirectory(), input.file_path)
50
+ }),
51
+ async execute(input, context) {
52
+ const resolvedFileSystemService = await getFileSystemService(context);
90
53
  const { file_path, limit, offset } = input;
91
- const result = await fileSystemService.readFile(file_path, {
54
+ const { path: resolvedPath } = (0, import_directory_approval.resolveFilePath)(
55
+ resolvedFileSystemService.getWorkingDirectory(),
56
+ file_path
57
+ );
58
+ const result = await resolvedFileSystemService.readFile(resolvedPath, {
92
59
  limit,
93
60
  offset
94
61
  });
95
62
  const _display = {
96
63
  type: "file",
97
- path: file_path,
64
+ path: resolvedPath,
98
65
  operation: "read",
99
66
  size: result.size,
100
67
  lineCount: result.lines
@@ -109,7 +76,7 @@ function createReadFileTool(options) {
109
76
  _display
110
77
  };
111
78
  }
112
- };
79
+ });
113
80
  }
114
81
  // Annotate the CommonJS export names for ESM import in node:
115
82
  0 && (module.exports = {
@@ -1,17 +1,27 @@
1
- import { InternalTool } from '@dexto/core';
2
- import { FileToolOptions } from './file-tool-types.js';
3
- import './filesystem-service.js';
4
- import './types.js';
5
-
6
1
  /**
7
2
  * Read File Tool
8
3
  *
9
4
  * Internal tool for reading file contents with size limits and pagination
10
5
  */
11
-
6
+ import { z } from 'zod';
7
+ import type { Tool } from '@dexto/core';
8
+ import type { FileSystemServiceGetter } from './file-tool-types.js';
9
+ declare const ReadFileInputSchema: z.ZodObject<{
10
+ file_path: z.ZodString;
11
+ limit: z.ZodOptional<z.ZodNumber>;
12
+ offset: z.ZodOptional<z.ZodNumber>;
13
+ }, "strict", z.ZodTypeAny, {
14
+ file_path: string;
15
+ limit?: number | undefined;
16
+ offset?: number | undefined;
17
+ }, {
18
+ file_path: string;
19
+ limit?: number | undefined;
20
+ offset?: number | undefined;
21
+ }>;
12
22
  /**
13
23
  * Create the read_file internal tool with directory approval support
14
24
  */
15
- declare function createReadFileTool(options: FileToolOptions): InternalTool;
16
-
17
- export { createReadFileTool };
25
+ export declare function createReadFileTool(getFileSystemService: FileSystemServiceGetter): Tool<typeof ReadFileInputSchema>;
26
+ export {};
27
+ //# sourceMappingURL=read-file-tool.d.ts.map
@@ -0,0 +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,CA6DlC"}
@@ -1,67 +1,44 @@
1
- import * as path from "node:path";
2
1
  import { z } from "zod";
3
- import { ApprovalType } from "@dexto/core";
2
+ import { createLocalToolCallHeader, defineTool, truncateForHeader } from "@dexto/core";
3
+ import { createDirectoryAccessApprovalHandlers, resolveFilePath } from "./directory-approval.js";
4
4
  const ReadFileInputSchema = z.object({
5
- file_path: z.string().describe("Absolute path to the file to read"),
5
+ file_path: z.string().min(1).describe("Absolute path to the file to read"),
6
6
  limit: z.number().int().positive().optional().describe("Maximum number of lines to read (optional)"),
7
7
  offset: z.number().int().min(1).optional().describe("Starting line number (1-based, optional)")
8
8
  }).strict();
9
- function createReadFileTool(options) {
10
- const { fileSystemService, directoryApproval } = options;
11
- let pendingApprovalParentDir;
12
- return {
9
+ function createReadFileTool(getFileSystemService) {
10
+ return defineTool({
13
11
  id: "read_file",
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,
16
- /**
17
- * Check if this read operation needs directory access approval.
18
- * Returns custom approval request if the file is outside allowed paths.
19
- */
20
- getApprovalOverride: async (args) => {
21
- const { file_path } = args;
22
- if (!file_path) return null;
23
- const isAllowed = await fileSystemService.isPathWithinConfigAllowed(file_path);
24
- if (isAllowed) {
25
- return null;
26
- }
27
- if (directoryApproval?.isSessionApproved(file_path)) {
28
- return null;
29
- }
30
- const absolutePath = path.resolve(file_path);
31
- const parentDir = path.dirname(absolutePath);
32
- pendingApprovalParentDir = parentDir;
33
- return {
34
- type: ApprovalType.DIRECTORY_ACCESS,
35
- metadata: {
36
- path: absolutePath,
37
- parentDir,
38
- operation: "read",
39
- toolName: "read_file"
40
- }
41
- };
15
+ presentation: {
16
+ describeHeader: (input) => createLocalToolCallHeader({
17
+ title: "Read",
18
+ argsText: truncateForHeader(input.file_path, 140)
19
+ })
42
20
  },
43
- /**
44
- * Handle approved directory access - remember the directory for session
45
- */
46
- onApprovalGranted: (response) => {
47
- if (!directoryApproval || !pendingApprovalParentDir) return;
48
- const data = response.data;
49
- const rememberDirectory = data?.rememberDirectory ?? false;
50
- directoryApproval.addApproved(
51
- pendingApprovalParentDir,
52
- rememberDirectory ? "session" : "once"
53
- );
54
- pendingApprovalParentDir = void 0;
55
- },
56
- execute: async (input, _context) => {
21
+ ...createDirectoryAccessApprovalHandlers({
22
+ toolName: "read_file",
23
+ operation: "read",
24
+ inputSchema: ReadFileInputSchema,
25
+ getFileSystemService,
26
+ resolvePaths: (input, fileSystemService) => resolveFilePath(fileSystemService.getWorkingDirectory(), input.file_path)
27
+ }),
28
+ async execute(input, context) {
29
+ const resolvedFileSystemService = await getFileSystemService(context);
57
30
  const { file_path, limit, offset } = input;
58
- const result = await fileSystemService.readFile(file_path, {
31
+ const { path: resolvedPath } = resolveFilePath(
32
+ resolvedFileSystemService.getWorkingDirectory(),
33
+ file_path
34
+ );
35
+ const result = await resolvedFileSystemService.readFile(resolvedPath, {
59
36
  limit,
60
37
  offset
61
38
  });
62
39
  const _display = {
63
40
  type: "file",
64
- path: file_path,
41
+ path: resolvedPath,
65
42
  operation: "read",
66
43
  size: result.size,
67
44
  lineCount: result.lines
@@ -76,7 +53,7 @@ function createReadFileTool(options) {
76
53
  _display
77
54
  };
78
55
  }
79
- };
56
+ });
80
57
  }
81
58
  export {
82
59
  createReadFileTool
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var tool_factory_config_exports = {};
20
+ __export(tool_factory_config_exports, {
21
+ FILESYSTEM_TOOL_NAMES: () => FILESYSTEM_TOOL_NAMES,
22
+ FileSystemToolsConfigSchema: () => FileSystemToolsConfigSchema
23
+ });
24
+ module.exports = __toCommonJS(tool_factory_config_exports);
25
+ var import_zod = require("zod");
26
+ const DEFAULT_ALLOWED_PATHS = ["."];
27
+ const DEFAULT_BLOCKED_PATHS = [".git", "node_modules/.bin", ".env"];
28
+ const DEFAULT_BLOCKED_EXTENSIONS = [".exe", ".dll", ".so"];
29
+ const DEFAULT_MAX_FILE_SIZE = 10 * 1024 * 1024;
30
+ const DEFAULT_ENABLE_BACKUPS = false;
31
+ const DEFAULT_BACKUP_RETENTION_DAYS = 7;
32
+ const FILESYSTEM_TOOL_NAMES = [
33
+ "read_file",
34
+ "write_file",
35
+ "edit_file",
36
+ "glob_files",
37
+ "grep_content"
38
+ ];
39
+ const FileSystemToolsConfigSchema = import_zod.z.object({
40
+ type: import_zod.z.literal("filesystem-tools"),
41
+ allowedPaths: import_zod.z.array(import_zod.z.string()).default(DEFAULT_ALLOWED_PATHS).describe("List of allowed base paths for file operations"),
42
+ blockedPaths: import_zod.z.array(import_zod.z.string()).default(DEFAULT_BLOCKED_PATHS).describe("List of blocked paths to exclude from operations"),
43
+ blockedExtensions: import_zod.z.array(import_zod.z.string()).default(DEFAULT_BLOCKED_EXTENSIONS).describe("List of blocked file extensions"),
44
+ maxFileSize: import_zod.z.number().int().positive().default(DEFAULT_MAX_FILE_SIZE).describe(
45
+ `Maximum file size in bytes (default: ${DEFAULT_MAX_FILE_SIZE / 1024 / 1024}MB)`
46
+ ),
47
+ workingDirectory: import_zod.z.string().optional().describe("Working directory for file operations (defaults to process.cwd())"),
48
+ enableBackups: import_zod.z.boolean().default(DEFAULT_ENABLE_BACKUPS).describe("Enable automatic backups of modified files"),
49
+ backupPath: import_zod.z.string().optional().describe("Absolute path for storing file backups (if enableBackups is true)"),
50
+ backupRetentionDays: import_zod.z.number().int().positive().default(DEFAULT_BACKUP_RETENTION_DAYS).describe(
51
+ `Number of days to retain backup files (default: ${DEFAULT_BACKUP_RETENTION_DAYS})`
52
+ ),
53
+ enabledTools: import_zod.z.array(import_zod.z.enum(FILESYSTEM_TOOL_NAMES)).optional().describe(
54
+ `Subset of tools to enable. If not specified, all tools are enabled. Available: ${FILESYSTEM_TOOL_NAMES.join(", ")}`
55
+ )
56
+ }).strict();
57
+ // Annotate the CommonJS export names for ESM import in node:
58
+ 0 && (module.exports = {
59
+ FILESYSTEM_TOOL_NAMES,
60
+ FileSystemToolsConfigSchema
61
+ });
@@ -1,19 +1,17 @@
1
- import { z } from 'zod';
2
- import { CustomToolProvider } from '@dexto/core';
3
- export { FileToolOptions } from './file-tool-types.js';
4
- import './filesystem-service.js';
5
- import './types.js';
6
-
7
1
  /**
8
- * FileSystem Tools Provider
2
+ * FileSystem Tools Factory
9
3
  *
10
4
  * Provides file operation tools by wrapping FileSystemService.
11
- * When registered, the provider initializes FileSystemService and creates tools
5
+ * When registered, the factory initializes FileSystemService and creates tools
12
6
  * for file operations (read, write, edit, glob, grep).
13
7
  */
14
-
8
+ import { z } from 'zod';
9
+ /**
10
+ * Available filesystem tool names for enabledTools configuration.
11
+ */
12
+ export declare const FILESYSTEM_TOOL_NAMES: readonly ["read_file", "write_file", "edit_file", "glob_files", "grep_content"];
15
13
  /**
16
- * Configuration schema for FileSystem tools provider.
14
+ * Configuration schema for FileSystem tools factory.
17
15
  *
18
16
  * This is the SINGLE SOURCE OF TRUTH for all configuration:
19
17
  * - Validation rules
@@ -24,7 +22,7 @@ import './types.js';
24
22
  * Services receive fully-validated config from this schema and use it as-is,
25
23
  * with no additional defaults or fallbacks needed.
26
24
  */
27
- declare const FileSystemToolsConfigSchema: z.ZodObject<{
25
+ export declare const FileSystemToolsConfigSchema: z.ZodObject<{
28
26
  type: z.ZodLiteral<"filesystem-tools">;
29
27
  allowedPaths: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
30
28
  blockedPaths: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
@@ -45,7 +43,7 @@ declare const FileSystemToolsConfigSchema: z.ZodObject<{
45
43
  type: "filesystem-tools";
46
44
  backupPath?: string | undefined;
47
45
  workingDirectory?: string | undefined;
48
- enabledTools?: ("edit_file" | "glob_files" | "grep_content" | "read_file" | "write_file")[] | undefined;
46
+ enabledTools?: ("read_file" | "write_file" | "edit_file" | "glob_files" | "grep_content")[] | undefined;
49
47
  }, {
50
48
  type: "filesystem-tools";
51
49
  allowedPaths?: string[] | undefined;
@@ -56,22 +54,7 @@ declare const FileSystemToolsConfigSchema: z.ZodObject<{
56
54
  enableBackups?: boolean | undefined;
57
55
  backupRetentionDays?: number | undefined;
58
56
  workingDirectory?: string | undefined;
59
- enabledTools?: ("edit_file" | "glob_files" | "grep_content" | "read_file" | "write_file")[] | undefined;
57
+ enabledTools?: ("read_file" | "write_file" | "edit_file" | "glob_files" | "grep_content")[] | undefined;
60
58
  }>;
61
- type FileSystemToolsConfig = z.output<typeof FileSystemToolsConfigSchema>;
62
- /**
63
- * FileSystem tools provider.
64
- *
65
- * Wraps FileSystemService and provides file operation tools:
66
- * - read_file: Read file contents with pagination
67
- * - write_file: Write or overwrite file contents
68
- * - edit_file: Edit files using search/replace operations
69
- * - glob_files: Find files matching glob patterns
70
- * - grep_content: Search file contents using regex
71
- *
72
- * When registered via customToolRegistry, FileSystemService is automatically
73
- * initialized and file operation tools become available to the agent.
74
- */
75
- declare const fileSystemToolsProvider: CustomToolProvider<'filesystem-tools', FileSystemToolsConfig>;
76
-
77
- export { fileSystemToolsProvider };
59
+ export type FileSystemToolsConfig = z.output<typeof FileSystemToolsConfigSchema>;
60
+ //# sourceMappingURL=tool-factory-config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-factory-config.d.ts","sourceRoot":"","sources":["../src/tool-factory-config.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAaxB;;GAEG;AACH,eAAO,MAAM,qBAAqB,iFAMxB,CAAC;AAEX;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,2BAA2B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAkD3B,CAAC;AAEd,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,2BAA2B,CAAC,CAAC"}