@dexto/tools-filesystem 1.5.8 → 1.6.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.
Files changed (83) hide show
  1. package/dist/directory-approval.cjs +94 -0
  2. package/dist/directory-approval.d.cts +22 -0
  3. package/dist/directory-approval.d.ts +20 -0
  4. package/dist/directory-approval.d.ts.map +1 -0
  5. package/dist/directory-approval.integration.test.cjs +303 -269
  6. package/dist/directory-approval.integration.test.d.ts +14 -2
  7. package/dist/directory-approval.integration.test.d.ts.map +1 -0
  8. package/dist/directory-approval.integration.test.js +309 -270
  9. package/dist/directory-approval.js +59 -0
  10. package/dist/edit-file-tool.cjs +57 -90
  11. package/dist/edit-file-tool.d.cts +20 -3
  12. package/dist/edit-file-tool.d.ts +22 -9
  13. package/dist/edit-file-tool.d.ts.map +1 -0
  14. package/dist/edit-file-tool.js +53 -76
  15. package/dist/edit-file-tool.test.cjs +66 -29
  16. package/dist/edit-file-tool.test.d.ts +7 -2
  17. package/dist/edit-file-tool.test.d.ts.map +1 -0
  18. package/dist/edit-file-tool.test.js +66 -29
  19. package/dist/error-codes.d.ts +2 -3
  20. package/dist/error-codes.d.ts.map +1 -0
  21. package/dist/errors.d.ts +4 -7
  22. package/dist/errors.d.ts.map +1 -0
  23. package/dist/file-tool-types.d.cts +7 -35
  24. package/dist/file-tool-types.d.ts +8 -40
  25. package/dist/file-tool-types.d.ts.map +1 -0
  26. package/dist/filesystem-service.cjs +18 -1
  27. package/dist/filesystem-service.d.cts +11 -6
  28. package/dist/filesystem-service.d.ts +14 -12
  29. package/dist/filesystem-service.d.ts.map +1 -0
  30. package/dist/filesystem-service.js +18 -1
  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 +22 -47
  36. package/dist/glob-files-tool.d.cts +17 -3
  37. package/dist/glob-files-tool.d.ts +19 -9
  38. package/dist/glob-files-tool.d.ts.map +1 -0
  39. package/dist/glob-files-tool.js +23 -48
  40. package/dist/grep-content-tool.cjs +29 -46
  41. package/dist/grep-content-tool.d.cts +26 -3
  42. package/dist/grep-content-tool.d.ts +28 -9
  43. package/dist/grep-content-tool.d.ts.map +1 -0
  44. package/dist/grep-content-tool.js +30 -47
  45. package/dist/index.cjs +3 -3
  46. package/dist/index.d.cts +4 -2
  47. package/dist/index.d.ts +10 -5
  48. package/dist/index.d.ts.map +1 -0
  49. package/dist/index.js +2 -2
  50. package/dist/path-validator.d.cts +2 -2
  51. package/dist/path-validator.d.ts +6 -9
  52. package/dist/path-validator.d.ts.map +1 -0
  53. package/dist/path-validator.test.d.ts +7 -2
  54. package/dist/path-validator.test.d.ts.map +1 -0
  55. package/dist/read-file-tool.cjs +21 -60
  56. package/dist/read-file-tool.d.cts +17 -3
  57. package/dist/read-file-tool.d.ts +19 -9
  58. package/dist/read-file-tool.d.ts.map +1 -0
  59. package/dist/read-file-tool.js +22 -51
  60. package/dist/tool-factory-config.cjs +61 -0
  61. package/dist/{tool-provider.d.ts → tool-factory-config.d.cts} +9 -23
  62. package/dist/{tool-provider.d.cts → tool-factory-config.d.ts} +13 -30
  63. package/dist/tool-factory-config.d.ts.map +1 -0
  64. package/dist/tool-factory-config.js +36 -0
  65. package/dist/tool-factory.cjs +102 -0
  66. package/dist/tool-factory.d.cts +7 -0
  67. package/dist/tool-factory.d.ts +4 -0
  68. package/dist/tool-factory.d.ts.map +1 -0
  69. package/dist/tool-factory.js +81 -0
  70. package/dist/types.d.ts +17 -18
  71. package/dist/types.d.ts.map +1 -0
  72. package/dist/write-file-tool.cjs +45 -73
  73. package/dist/write-file-tool.d.cts +20 -3
  74. package/dist/write-file-tool.d.ts +22 -9
  75. package/dist/write-file-tool.d.ts.map +1 -0
  76. package/dist/write-file-tool.js +46 -68
  77. package/dist/write-file-tool.test.cjs +76 -32
  78. package/dist/write-file-tool.test.d.ts +7 -2
  79. package/dist/write-file-tool.test.d.ts.map +1 -0
  80. package/dist/write-file-tool.test.js +76 -32
  81. package/package.json +4 -3
  82. package/dist/tool-provider.cjs +0 -123
  83. package/dist/tool-provider.js +0 -99
@@ -1,4 +1,4 @@
1
- import { IDextoLogger } from '@dexto/core';
1
+ import { Logger } from '@dexto/core';
2
2
  import { FileSystemConfig, ReadFileOptions, FileContent, GlobOptions, GlobResult, GrepOptions, SearchResult, WriteFileOptions, WriteResult, EditOperation, EditFileOptions, EditResult } from './types.cjs';
3
3
 
4
4
  /**
@@ -10,11 +10,10 @@ import { FileSystemConfig, ReadFileOptions, FileContent, GlobOptions, GlobResult
10
10
  /**
11
11
  * FileSystemService - Handles all file system operations with security checks
12
12
  *
13
- * This service receives fully-validated configuration from the FileSystem Tools Provider.
14
- * All defaults have been applied by the provider's schema, so the service trusts the config
13
+ * This service receives fully-validated configuration from the FileSystem Tools Factory.
14
+ * All defaults have been applied by the factory's schema, so the service trusts the config
15
15
  * and uses it as-is without any fallback logic.
16
16
  *
17
- * TODO: Add tests for this class
18
17
  * TODO: instantiate only when internal file tools are enabled to avoid file dependencies which won't work in serverless
19
18
  */
20
19
  declare class FileSystemService {
@@ -23,14 +22,15 @@ declare class FileSystemService {
23
22
  private initialized;
24
23
  private initPromise;
25
24
  private logger;
25
+ private directoryApprovalChecker?;
26
26
  /**
27
27
  * Create a new FileSystemService with validated configuration.
28
28
  *
29
- * @param config - Fully-validated configuration from provider schema.
29
+ * @param config - Fully-validated configuration from the factory schema.
30
30
  * All required fields have values, defaults already applied.
31
31
  * @param logger - Logger instance for this service
32
32
  */
33
- constructor(config: FileSystemConfig, logger: IDextoLogger);
33
+ constructor(config: FileSystemConfig, logger: Logger);
34
34
  /**
35
35
  * Get backup directory path (context-aware with optional override)
36
36
  * TODO: Migrate to explicit configuration via CLI enrichment layer (per-agent paths)
@@ -63,6 +63,11 @@ declare class FileSystemService {
63
63
  * @param checker Function that returns true if path is in an approved directory
64
64
  */
65
65
  setDirectoryApprovalChecker(checker: (filePath: string) => boolean): void;
66
+ /**
67
+ * Update the working directory at runtime (e.g., when workspace changes).
68
+ * Rebuilds the PathValidator so allowed/blocked path roots are recalculated.
69
+ */
70
+ setWorkingDirectory(workingDirectory: string): void;
66
71
  /**
67
72
  * Check if a file path is within the configured allowed paths (config only).
68
73
  * This is used by file tools to determine if directory approval is needed.
@@ -1,36 +1,34 @@
1
- import { IDextoLogger } from '@dexto/core';
2
- import { FileSystemConfig, ReadFileOptions, FileContent, GlobOptions, GlobResult, GrepOptions, SearchResult, WriteFileOptions, WriteResult, EditOperation, EditFileOptions, EditResult } from './types.js';
3
-
4
1
  /**
5
2
  * FileSystem Service
6
3
  *
7
4
  * Secure file system operations for Dexto internal tools
8
5
  */
9
-
6
+ import { Logger } from '@dexto/core';
7
+ import { FileSystemConfig, FileContent, ReadFileOptions, GlobOptions, GlobResult, GrepOptions, SearchResult, WriteFileOptions, WriteResult, EditFileOptions, EditResult, EditOperation } from './types.js';
10
8
  /**
11
9
  * FileSystemService - Handles all file system operations with security checks
12
10
  *
13
- * This service receives fully-validated configuration from the FileSystem Tools Provider.
14
- * All defaults have been applied by the provider's schema, so the service trusts the config
11
+ * This service receives fully-validated configuration from the FileSystem Tools Factory.
12
+ * All defaults have been applied by the factory's schema, so the service trusts the config
15
13
  * and uses it as-is without any fallback logic.
16
14
  *
17
- * TODO: Add tests for this class
18
15
  * TODO: instantiate only when internal file tools are enabled to avoid file dependencies which won't work in serverless
19
16
  */
20
- declare class FileSystemService {
17
+ export declare class FileSystemService {
21
18
  private config;
22
19
  private pathValidator;
23
20
  private initialized;
24
21
  private initPromise;
25
22
  private logger;
23
+ private directoryApprovalChecker?;
26
24
  /**
27
25
  * Create a new FileSystemService with validated configuration.
28
26
  *
29
- * @param config - Fully-validated configuration from provider schema.
27
+ * @param config - Fully-validated configuration from the factory schema.
30
28
  * All required fields have values, defaults already applied.
31
29
  * @param logger - Logger instance for this service
32
30
  */
33
- constructor(config: FileSystemConfig, logger: IDextoLogger);
31
+ constructor(config: FileSystemConfig, logger: Logger);
34
32
  /**
35
33
  * Get backup directory path (context-aware with optional override)
36
34
  * TODO: Migrate to explicit configuration via CLI enrichment layer (per-agent paths)
@@ -63,6 +61,11 @@ declare class FileSystemService {
63
61
  * @param checker Function that returns true if path is in an approved directory
64
62
  */
65
63
  setDirectoryApprovalChecker(checker: (filePath: string) => boolean): void;
64
+ /**
65
+ * Update the working directory at runtime (e.g., when workspace changes).
66
+ * Rebuilds the PathValidator so allowed/blocked path roots are recalculated.
67
+ */
68
+ setWorkingDirectory(workingDirectory: string): void;
66
69
  /**
67
70
  * Check if a file path is within the configured allowed paths (config only).
68
71
  * This is used by file tools to determine if directory approval is needed.
@@ -108,5 +111,4 @@ declare class FileSystemService {
108
111
  */
109
112
  isPathAllowed(filePath: string): Promise<boolean>;
110
113
  }
111
-
112
- export { FileSystemService };
114
+ //# sourceMappingURL=filesystem-service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"filesystem-service.d.ts","sourceRoot":"","sources":["../src/filesystem-service.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAMH,OAAO,EAAgB,MAAM,EAAqB,MAAM,aAAa,CAAC;AACtE,OAAO,EACH,gBAAgB,EAChB,WAAW,EACX,eAAe,EACf,WAAW,EACX,UAAU,EACV,WAAW,EACX,YAAY,EAEZ,gBAAgB,EAChB,WAAW,EACX,eAAe,EACf,UAAU,EACV,aAAa,EAGhB,MAAM,YAAY,CAAC;AAQpB;;;;;;;;GAQG;AACH,qBAAa,iBAAiB;IAC1B,OAAO,CAAC,MAAM,CAAmB;IACjC,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,WAAW,CAAkB;IACrC,OAAO,CAAC,WAAW,CAA8B;IACjD,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,wBAAwB,CAAC,CAAgC;IAEjE;;;;;;OAMG;gBACS,MAAM,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM;IAQpD;;;OAGG;IACH,OAAO,CAAC,YAAY;IAKpB;;;OAGG;IACH,mBAAmB,IAAI,MAAM;IAI7B;;;OAGG;IACH,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAS3B;;OAEG;YACW,YAAY;IAuB1B;;;;OAIG;IACG,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC;IAOxC;;;;;OAKG;IACH,2BAA2B,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,GAAG,IAAI;IAKzE;;;OAGG;IACH,mBAAmB,CAAC,gBAAgB,EAAE,MAAM,GAAG,IAAI;IAanD;;;;;;OAMG;IACG,yBAAyB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAInE;;OAEG;IACG,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,GAAE,eAAoB,GAAG,OAAO,CAAC,WAAW,CAAC;IA6ErF;;OAEG;IACG,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,UAAU,CAAC;IAsEhF;;OAEG;IACG,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,YAAY,CAAC;IAyItF;;OAEG;IACG,SAAS,CACX,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,gBAAqB,GAC/B,OAAO,CAAC,WAAW,CAAC;IAwDvB;;OAEG;IACG,QAAQ,CACV,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,aAAa,EACxB,OAAO,GAAE,eAAoB,GAC9B,OAAO,CAAC,UAAU,CAAC;IAqEtB;;OAEG;YACW,YAAY;IA0B1B;;OAEG;IACG,iBAAiB,IAAI,OAAO,CAAC,MAAM,CAAC;IA6D1C;;OAEG;IACH,SAAS,IAAI,QAAQ,CAAC,gBAAgB,CAAC;IAIvC;;OAEG;IACG,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CAI1D"}
@@ -14,10 +14,11 @@ class FileSystemService {
14
14
  initialized = false;
15
15
  initPromise = null;
16
16
  logger;
17
+ directoryApprovalChecker;
17
18
  /**
18
19
  * Create a new FileSystemService with validated configuration.
19
20
  *
20
- * @param config - Fully-validated configuration from provider schema.
21
+ * @param config - Fully-validated configuration from the factory schema.
21
22
  * All required fields have values, defaults already applied.
22
23
  * @param logger - Logger instance for this service
23
24
  */
@@ -91,8 +92,24 @@ class FileSystemService {
91
92
  * @param checker Function that returns true if path is in an approved directory
92
93
  */
93
94
  setDirectoryApprovalChecker(checker) {
95
+ this.directoryApprovalChecker = checker;
94
96
  this.pathValidator.setDirectoryApprovalChecker(checker);
95
97
  }
98
+ /**
99
+ * Update the working directory at runtime (e.g., when workspace changes).
100
+ * Rebuilds the PathValidator so allowed/blocked path roots are recalculated.
101
+ */
102
+ setWorkingDirectory(workingDirectory) {
103
+ const normalized = workingDirectory?.trim();
104
+ if (!normalized) return;
105
+ if (this.config.workingDirectory === normalized) return;
106
+ this.config = { ...this.config, workingDirectory: normalized };
107
+ this.pathValidator = new PathValidator(this.config, this.logger);
108
+ if (this.directoryApprovalChecker) {
109
+ this.pathValidator.setDirectoryApprovalChecker(this.directoryApprovalChecker);
110
+ }
111
+ this.logger.info(`FileSystemService working directory set to ${normalized}`);
112
+ }
96
113
  /**
97
114
  * Check if a file path is within the configured allowed paths (config only).
98
115
  * This is used by file tools to determine if directory approval is needed.
@@ -36,10 +36,12 @@ const createMockLogger = () => ({
36
36
  (0, import_vitest.describe)("FileSystemService", () => {
37
37
  let mockLogger;
38
38
  let tempDir;
39
+ let backupDir;
39
40
  (0, import_vitest.beforeEach)(async () => {
40
41
  mockLogger = createMockLogger();
41
42
  const rawTempDir = await fs.mkdtemp(path.join(os.tmpdir(), "dexto-fs-test-"));
42
43
  tempDir = await fs.realpath(rawTempDir);
44
+ backupDir = path.join(tempDir, ".dexto", "backups");
43
45
  import_vitest.vi.clearAllMocks();
44
46
  });
45
47
  (0, import_vitest.afterEach)(async () => {
@@ -59,6 +61,7 @@ const createMockLogger = () => ({
59
61
  maxFileSize: 10 * 1024 * 1024,
60
62
  workingDirectory: tempDir,
61
63
  enableBackups: false,
64
+ backupPath: backupDir,
62
65
  backupRetentionDays: 7
63
66
  },
64
67
  mockLogger
@@ -69,7 +72,6 @@ const createMockLogger = () => ({
69
72
  const result = await fileSystemService.writeFile(testFile, "new content");
70
73
  (0, import_vitest.expect)(result.success).toBe(true);
71
74
  (0, import_vitest.expect)(result.backupPath).toBeUndefined();
72
- const backupDir = path.join(tempDir, ".dexto-backups");
73
75
  try {
74
76
  const files = await fs.readdir(backupDir);
75
77
  (0, import_vitest.expect)(files.length).toBe(0);
@@ -85,6 +87,7 @@ const createMockLogger = () => ({
85
87
  maxFileSize: 10 * 1024 * 1024,
86
88
  workingDirectory: tempDir,
87
89
  enableBackups: true,
90
+ backupPath: backupDir,
88
91
  backupRetentionDays: 7
89
92
  },
90
93
  mockLogger
@@ -95,7 +98,7 @@ const createMockLogger = () => ({
95
98
  const result = await fileSystemService.writeFile(testFile, "new content");
96
99
  (0, import_vitest.expect)(result.success).toBe(true);
97
100
  (0, import_vitest.expect)(result.backupPath).toBeDefined();
98
- (0, import_vitest.expect)(result.backupPath).toContain(".dexto");
101
+ (0, import_vitest.expect)(result.backupPath).toContain(backupDir);
99
102
  (0, import_vitest.expect)(result.backupPath).toContain("backup");
100
103
  const backupContent = await fs.readFile(result.backupPath, "utf-8");
101
104
  (0, import_vitest.expect)(backupContent).toBe("original content");
@@ -111,6 +114,7 @@ const createMockLogger = () => ({
111
114
  maxFileSize: 10 * 1024 * 1024,
112
115
  workingDirectory: tempDir,
113
116
  enableBackups: true,
117
+ backupPath: backupDir,
114
118
  backupRetentionDays: 7
115
119
  },
116
120
  mockLogger
@@ -133,6 +137,7 @@ const createMockLogger = () => ({
133
137
  workingDirectory: tempDir,
134
138
  enableBackups: false,
135
139
  // Config says no backups
140
+ backupPath: backupDir,
136
141
  backupRetentionDays: 7
137
142
  },
138
143
  mockLogger
@@ -157,6 +162,7 @@ const createMockLogger = () => ({
157
162
  maxFileSize: 10 * 1024 * 1024,
158
163
  workingDirectory: tempDir,
159
164
  enableBackups: false,
165
+ backupPath: backupDir,
160
166
  backupRetentionDays: 7
161
167
  },
162
168
  mockLogger
@@ -182,6 +188,7 @@ const createMockLogger = () => ({
182
188
  maxFileSize: 10 * 1024 * 1024,
183
189
  workingDirectory: tempDir,
184
190
  enableBackups: true,
191
+ backupPath: backupDir,
185
192
  backupRetentionDays: 7
186
193
  },
187
194
  mockLogger
@@ -210,6 +217,7 @@ const createMockLogger = () => ({
210
217
  workingDirectory: tempDir,
211
218
  enableBackups: false,
212
219
  // Config says no backups
220
+ backupPath: backupDir,
213
221
  backupRetentionDays: 7
214
222
  },
215
223
  mockLogger
@@ -1,2 +1,7 @@
1
-
2
- export { }
1
+ /**
2
+ * FileSystemService Tests
3
+ *
4
+ * Tests for the core filesystem service including backup behavior.
5
+ */
6
+ export {};
7
+ //# sourceMappingURL=filesystem-service.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"filesystem-service.test.d.ts","sourceRoot":"","sources":["../src/filesystem-service.test.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
@@ -13,10 +13,12 @@ const createMockLogger = () => ({
13
13
  describe("FileSystemService", () => {
14
14
  let mockLogger;
15
15
  let tempDir;
16
+ let backupDir;
16
17
  beforeEach(async () => {
17
18
  mockLogger = createMockLogger();
18
19
  const rawTempDir = await fs.mkdtemp(path.join(os.tmpdir(), "dexto-fs-test-"));
19
20
  tempDir = await fs.realpath(rawTempDir);
21
+ backupDir = path.join(tempDir, ".dexto", "backups");
20
22
  vi.clearAllMocks();
21
23
  });
22
24
  afterEach(async () => {
@@ -36,6 +38,7 @@ describe("FileSystemService", () => {
36
38
  maxFileSize: 10 * 1024 * 1024,
37
39
  workingDirectory: tempDir,
38
40
  enableBackups: false,
41
+ backupPath: backupDir,
39
42
  backupRetentionDays: 7
40
43
  },
41
44
  mockLogger
@@ -46,7 +49,6 @@ describe("FileSystemService", () => {
46
49
  const result = await fileSystemService.writeFile(testFile, "new content");
47
50
  expect(result.success).toBe(true);
48
51
  expect(result.backupPath).toBeUndefined();
49
- const backupDir = path.join(tempDir, ".dexto-backups");
50
52
  try {
51
53
  const files = await fs.readdir(backupDir);
52
54
  expect(files.length).toBe(0);
@@ -62,6 +64,7 @@ describe("FileSystemService", () => {
62
64
  maxFileSize: 10 * 1024 * 1024,
63
65
  workingDirectory: tempDir,
64
66
  enableBackups: true,
67
+ backupPath: backupDir,
65
68
  backupRetentionDays: 7
66
69
  },
67
70
  mockLogger
@@ -72,7 +75,7 @@ describe("FileSystemService", () => {
72
75
  const result = await fileSystemService.writeFile(testFile, "new content");
73
76
  expect(result.success).toBe(true);
74
77
  expect(result.backupPath).toBeDefined();
75
- expect(result.backupPath).toContain(".dexto");
78
+ expect(result.backupPath).toContain(backupDir);
76
79
  expect(result.backupPath).toContain("backup");
77
80
  const backupContent = await fs.readFile(result.backupPath, "utf-8");
78
81
  expect(backupContent).toBe("original content");
@@ -88,6 +91,7 @@ describe("FileSystemService", () => {
88
91
  maxFileSize: 10 * 1024 * 1024,
89
92
  workingDirectory: tempDir,
90
93
  enableBackups: true,
94
+ backupPath: backupDir,
91
95
  backupRetentionDays: 7
92
96
  },
93
97
  mockLogger
@@ -110,6 +114,7 @@ describe("FileSystemService", () => {
110
114
  workingDirectory: tempDir,
111
115
  enableBackups: false,
112
116
  // Config says no backups
117
+ backupPath: backupDir,
113
118
  backupRetentionDays: 7
114
119
  },
115
120
  mockLogger
@@ -134,6 +139,7 @@ describe("FileSystemService", () => {
134
139
  maxFileSize: 10 * 1024 * 1024,
135
140
  workingDirectory: tempDir,
136
141
  enableBackups: false,
142
+ backupPath: backupDir,
137
143
  backupRetentionDays: 7
138
144
  },
139
145
  mockLogger
@@ -159,6 +165,7 @@ describe("FileSystemService", () => {
159
165
  maxFileSize: 10 * 1024 * 1024,
160
166
  workingDirectory: tempDir,
161
167
  enableBackups: true,
168
+ backupPath: backupDir,
162
169
  backupRetentionDays: 7
163
170
  },
164
171
  mockLogger
@@ -187,6 +194,7 @@ describe("FileSystemService", () => {
187
194
  workingDirectory: tempDir,
188
195
  enableBackups: false,
189
196
  // Config says no backups
197
+ backupPath: backupDir,
190
198
  backupRetentionDays: 7
191
199
  },
192
200
  mockLogger
@@ -34,61 +34,36 @@ module.exports = __toCommonJS(glob_files_tool_exports);
34
34
  var path = __toESM(require("node:path"), 1);
35
35
  var import_zod = require("zod");
36
36
  var import_core = require("@dexto/core");
37
+ var import_directory_approval = require("./directory-approval.js");
37
38
  const GlobFilesInputSchema = import_zod.z.object({
38
39
  pattern: import_zod.z.string().describe('Glob pattern to match files (e.g., "**/*.ts", "src/**/*.js")'),
39
40
  path: import_zod.z.string().optional().describe("Base directory to search from (defaults to working directory)"),
40
41
  max_results: import_zod.z.number().int().positive().optional().default(1e3).describe("Maximum number of results to return (default: 1000)")
41
42
  }).strict();
42
- function createGlobFilesTool(options) {
43
- const { fileSystemService, directoryApproval } = options;
44
- let pendingApprovalSearchDir;
45
- return {
43
+ function createGlobFilesTool(getFileSystemService) {
44
+ return (0, import_core.defineTool)({
46
45
  id: "glob_files",
46
+ displayName: "Find Files",
47
+ aliases: ["glob"],
47
48
  description: "Find files matching a glob pattern. Supports standard glob syntax like **/*.js for recursive matches, *.ts for files in current directory, and src/**/*.tsx for nested paths. Returns array of file paths with metadata (size, modified date). Results are limited to allowed paths only.",
48
49
  inputSchema: GlobFilesInputSchema,
49
- /**
50
- * Check if this glob operation needs directory access approval.
51
- * Returns custom approval request if the search directory is outside allowed paths.
52
- */
53
- getApprovalOverride: async (args) => {
54
- const { path: searchPath } = args;
55
- const baseDir = fileSystemService.getWorkingDirectory();
56
- const searchDir = path.resolve(baseDir, searchPath || ".");
57
- const isAllowed = await fileSystemService.isPathWithinConfigAllowed(searchDir);
58
- if (isAllowed) {
59
- return null;
50
+ ...(0, import_directory_approval.createDirectoryAccessApprovalHandlers)({
51
+ toolName: "glob_files",
52
+ operation: "read",
53
+ getFileSystemService,
54
+ resolvePaths: (input, fileSystemService) => {
55
+ const baseDir = fileSystemService.getWorkingDirectory();
56
+ const searchDir = path.resolve(baseDir, input.path || ".");
57
+ return { path: searchDir, parentDir: searchDir };
60
58
  }
61
- if (directoryApproval?.isSessionApproved(searchDir)) {
62
- return null;
63
- }
64
- pendingApprovalSearchDir = searchDir;
65
- return {
66
- type: import_core.ApprovalType.DIRECTORY_ACCESS,
67
- metadata: {
68
- path: searchDir,
69
- parentDir: searchDir,
70
- operation: "search",
71
- toolName: "glob_files"
72
- }
73
- };
74
- },
75
- /**
76
- * Handle approved directory access - remember the directory for session
77
- */
78
- onApprovalGranted: (response) => {
79
- if (!directoryApproval || !pendingApprovalSearchDir) return;
80
- const data = response.data;
81
- const rememberDirectory = data?.rememberDirectory ?? false;
82
- directoryApproval.addApproved(
83
- pendingApprovalSearchDir,
84
- rememberDirectory ? "session" : "once"
85
- );
86
- pendingApprovalSearchDir = void 0;
87
- },
88
- execute: async (input, _context) => {
89
- const { pattern, path: path2, max_results } = input;
90
- const result = await fileSystemService.globFiles(pattern, {
91
- cwd: path2,
59
+ }),
60
+ async execute(input, context) {
61
+ const resolvedFileSystemService = await getFileSystemService(context);
62
+ const { pattern, path: searchPath, max_results } = input;
63
+ const baseDir = resolvedFileSystemService.getWorkingDirectory();
64
+ const resolvedSearchPath = path.resolve(baseDir, searchPath || ".");
65
+ const result = await resolvedFileSystemService.globFiles(pattern, {
66
+ cwd: resolvedSearchPath,
92
67
  maxResults: max_results,
93
68
  includeMetadata: true
94
69
  });
@@ -115,7 +90,7 @@ function createGlobFilesTool(options) {
115
90
  _display
116
91
  };
117
92
  }
118
- };
93
+ });
119
94
  }
120
95
  // Annotate the CommonJS export names for ESM import in node:
121
96
  0 && (module.exports = {
@@ -1,5 +1,6 @@
1
- import { InternalTool } from '@dexto/core';
2
- import { FileToolOptions } from './file-tool-types.cjs';
1
+ import { z } from 'zod';
2
+ import { Tool } from '@dexto/core';
3
+ import { FileSystemServiceGetter } from './file-tool-types.cjs';
3
4
  import './filesystem-service.cjs';
4
5
  import './types.cjs';
5
6
 
@@ -9,9 +10,22 @@ import './types.cjs';
9
10
  * Internal tool for finding files using glob patterns
10
11
  */
11
12
 
13
+ declare const GlobFilesInputSchema: z.ZodObject<{
14
+ pattern: z.ZodString;
15
+ path: z.ZodOptional<z.ZodString>;
16
+ max_results: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
17
+ }, "strict", z.ZodTypeAny, {
18
+ pattern: string;
19
+ max_results: number;
20
+ path?: string | undefined;
21
+ }, {
22
+ pattern: string;
23
+ path?: string | undefined;
24
+ max_results?: number | undefined;
25
+ }>;
12
26
  /**
13
27
  * Create the glob_files internal tool with directory approval support
14
28
  */
15
- declare function createGlobFilesTool(options: FileToolOptions): InternalTool;
29
+ declare function createGlobFilesTool(getFileSystemService: FileSystemServiceGetter): Tool<typeof GlobFilesInputSchema>;
16
30
 
17
31
  export { createGlobFilesTool };
@@ -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
  * Glob Files Tool
8
3
  *
9
4
  * Internal tool for finding files using glob patterns
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 GlobFilesInputSchema: z.ZodObject<{
10
+ pattern: z.ZodString;
11
+ path: z.ZodOptional<z.ZodString>;
12
+ max_results: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
13
+ }, "strict", z.ZodTypeAny, {
14
+ pattern: string;
15
+ max_results: number;
16
+ path?: string | undefined;
17
+ }, {
18
+ pattern: string;
19
+ path?: string | undefined;
20
+ max_results?: number | undefined;
21
+ }>;
12
22
  /**
13
23
  * Create the glob_files internal tool with directory approval support
14
24
  */
15
- declare function createGlobFilesTool(options: FileToolOptions): InternalTool;
16
-
17
- export { createGlobFilesTool };
25
+ export declare function createGlobFilesTool(getFileSystemService: FileSystemServiceGetter): Tool<typeof GlobFilesInputSchema>;
26
+ export {};
27
+ //# sourceMappingURL=glob-files-tool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"glob-files-tool.d.ts","sourceRoot":"","sources":["../src/glob-files-tool.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,KAAK,EAAE,IAAI,EAAwB,MAAM,aAAa,CAAC;AAC9D,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAGpE,QAAA,MAAM,oBAAoB;;;;;;;;;;;;EAiBb,CAAC;AAEd;;GAEG;AACH,wBAAgB,mBAAmB,CAC/B,oBAAoB,EAAE,uBAAuB,GAC9C,IAAI,CAAC,OAAO,oBAAoB,CAAC,CA8DnC"}
@@ -1,61 +1,36 @@
1
1
  import * as path from "node:path";
2
2
  import { z } from "zod";
3
- import { ApprovalType } from "@dexto/core";
3
+ import { defineTool } from "@dexto/core";
4
+ import { createDirectoryAccessApprovalHandlers } from "./directory-approval.js";
4
5
  const GlobFilesInputSchema = z.object({
5
6
  pattern: z.string().describe('Glob pattern to match files (e.g., "**/*.ts", "src/**/*.js")'),
6
7
  path: z.string().optional().describe("Base directory to search from (defaults to working directory)"),
7
8
  max_results: z.number().int().positive().optional().default(1e3).describe("Maximum number of results to return (default: 1000)")
8
9
  }).strict();
9
- function createGlobFilesTool(options) {
10
- const { fileSystemService, directoryApproval } = options;
11
- let pendingApprovalSearchDir;
12
- return {
10
+ function createGlobFilesTool(getFileSystemService) {
11
+ return defineTool({
13
12
  id: "glob_files",
13
+ displayName: "Find Files",
14
+ aliases: ["glob"],
14
15
  description: "Find files matching a glob pattern. Supports standard glob syntax like **/*.js for recursive matches, *.ts for files in current directory, and src/**/*.tsx for nested paths. Returns array of file paths with metadata (size, modified date). Results are limited to allowed paths only.",
15
16
  inputSchema: GlobFilesInputSchema,
16
- /**
17
- * Check if this glob operation needs directory access approval.
18
- * Returns custom approval request if the search directory is outside allowed paths.
19
- */
20
- getApprovalOverride: async (args) => {
21
- const { path: searchPath } = args;
22
- const baseDir = fileSystemService.getWorkingDirectory();
23
- const searchDir = path.resolve(baseDir, searchPath || ".");
24
- const isAllowed = await fileSystemService.isPathWithinConfigAllowed(searchDir);
25
- if (isAllowed) {
26
- return null;
17
+ ...createDirectoryAccessApprovalHandlers({
18
+ toolName: "glob_files",
19
+ operation: "read",
20
+ getFileSystemService,
21
+ resolvePaths: (input, fileSystemService) => {
22
+ const baseDir = fileSystemService.getWorkingDirectory();
23
+ const searchDir = path.resolve(baseDir, input.path || ".");
24
+ return { path: searchDir, parentDir: searchDir };
27
25
  }
28
- if (directoryApproval?.isSessionApproved(searchDir)) {
29
- return null;
30
- }
31
- pendingApprovalSearchDir = searchDir;
32
- return {
33
- type: ApprovalType.DIRECTORY_ACCESS,
34
- metadata: {
35
- path: searchDir,
36
- parentDir: searchDir,
37
- operation: "search",
38
- toolName: "glob_files"
39
- }
40
- };
41
- },
42
- /**
43
- * Handle approved directory access - remember the directory for session
44
- */
45
- onApprovalGranted: (response) => {
46
- if (!directoryApproval || !pendingApprovalSearchDir) return;
47
- const data = response.data;
48
- const rememberDirectory = data?.rememberDirectory ?? false;
49
- directoryApproval.addApproved(
50
- pendingApprovalSearchDir,
51
- rememberDirectory ? "session" : "once"
52
- );
53
- pendingApprovalSearchDir = void 0;
54
- },
55
- execute: async (input, _context) => {
56
- const { pattern, path: path2, max_results } = input;
57
- const result = await fileSystemService.globFiles(pattern, {
58
- cwd: path2,
26
+ }),
27
+ async execute(input, context) {
28
+ const resolvedFileSystemService = await getFileSystemService(context);
29
+ const { pattern, path: searchPath, max_results } = input;
30
+ const baseDir = resolvedFileSystemService.getWorkingDirectory();
31
+ const resolvedSearchPath = path.resolve(baseDir, searchPath || ".");
32
+ const result = await resolvedFileSystemService.globFiles(pattern, {
33
+ cwd: resolvedSearchPath,
59
34
  maxResults: max_results,
60
35
  includeMetadata: true
61
36
  });
@@ -82,7 +57,7 @@ function createGlobFilesTool(options) {
82
57
  _display
83
58
  };
84
59
  }
85
- };
60
+ });
86
61
  }
87
62
  export {
88
63
  createGlobFilesTool