@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.
- package/dist/directory-approval.cjs +94 -0
- package/dist/directory-approval.d.cts +22 -0
- package/dist/directory-approval.d.ts +20 -0
- package/dist/directory-approval.d.ts.map +1 -0
- package/dist/directory-approval.integration.test.cjs +303 -269
- package/dist/directory-approval.integration.test.d.ts +14 -2
- package/dist/directory-approval.integration.test.d.ts.map +1 -0
- package/dist/directory-approval.integration.test.js +309 -270
- package/dist/directory-approval.js +59 -0
- package/dist/edit-file-tool.cjs +57 -90
- package/dist/edit-file-tool.d.cts +20 -3
- package/dist/edit-file-tool.d.ts +22 -9
- package/dist/edit-file-tool.d.ts.map +1 -0
- package/dist/edit-file-tool.js +53 -76
- package/dist/edit-file-tool.test.cjs +66 -29
- package/dist/edit-file-tool.test.d.ts +7 -2
- package/dist/edit-file-tool.test.d.ts.map +1 -0
- package/dist/edit-file-tool.test.js +66 -29
- package/dist/error-codes.d.ts +2 -3
- package/dist/error-codes.d.ts.map +1 -0
- package/dist/errors.d.ts +4 -7
- package/dist/errors.d.ts.map +1 -0
- package/dist/file-tool-types.d.cts +7 -35
- package/dist/file-tool-types.d.ts +8 -40
- package/dist/file-tool-types.d.ts.map +1 -0
- package/dist/filesystem-service.cjs +18 -1
- package/dist/filesystem-service.d.cts +11 -6
- package/dist/filesystem-service.d.ts +14 -12
- package/dist/filesystem-service.d.ts.map +1 -0
- package/dist/filesystem-service.js +18 -1
- package/dist/filesystem-service.test.cjs +10 -2
- package/dist/filesystem-service.test.d.ts +7 -2
- package/dist/filesystem-service.test.d.ts.map +1 -0
- package/dist/filesystem-service.test.js +10 -2
- package/dist/glob-files-tool.cjs +22 -47
- package/dist/glob-files-tool.d.cts +17 -3
- package/dist/glob-files-tool.d.ts +19 -9
- package/dist/glob-files-tool.d.ts.map +1 -0
- package/dist/glob-files-tool.js +23 -48
- package/dist/grep-content-tool.cjs +29 -46
- package/dist/grep-content-tool.d.cts +26 -3
- package/dist/grep-content-tool.d.ts +28 -9
- package/dist/grep-content-tool.d.ts.map +1 -0
- package/dist/grep-content-tool.js +30 -47
- package/dist/index.cjs +3 -3
- package/dist/index.d.cts +4 -2
- package/dist/index.d.ts +10 -5
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -2
- package/dist/path-validator.d.cts +2 -2
- package/dist/path-validator.d.ts +6 -9
- package/dist/path-validator.d.ts.map +1 -0
- package/dist/path-validator.test.d.ts +7 -2
- package/dist/path-validator.test.d.ts.map +1 -0
- package/dist/read-file-tool.cjs +21 -60
- package/dist/read-file-tool.d.cts +17 -3
- package/dist/read-file-tool.d.ts +19 -9
- package/dist/read-file-tool.d.ts.map +1 -0
- package/dist/read-file-tool.js +22 -51
- package/dist/tool-factory-config.cjs +61 -0
- package/dist/{tool-provider.d.ts → tool-factory-config.d.cts} +9 -23
- package/dist/{tool-provider.d.cts → tool-factory-config.d.ts} +13 -30
- package/dist/tool-factory-config.d.ts.map +1 -0
- package/dist/tool-factory-config.js +36 -0
- package/dist/tool-factory.cjs +102 -0
- package/dist/tool-factory.d.cts +7 -0
- package/dist/tool-factory.d.ts +4 -0
- package/dist/tool-factory.d.ts.map +1 -0
- package/dist/tool-factory.js +81 -0
- package/dist/types.d.ts +17 -18
- package/dist/types.d.ts.map +1 -0
- package/dist/write-file-tool.cjs +45 -73
- package/dist/write-file-tool.d.cts +20 -3
- package/dist/write-file-tool.d.ts +22 -9
- package/dist/write-file-tool.d.ts.map +1 -0
- package/dist/write-file-tool.js +46 -68
- package/dist/write-file-tool.test.cjs +76 -32
- package/dist/write-file-tool.test.d.ts +7 -2
- package/dist/write-file-tool.test.d.ts.map +1 -0
- package/dist/write-file-tool.test.js +76 -32
- package/package.json +4 -3
- package/dist/tool-provider.cjs +0 -123
- package/dist/tool-provider.js +0 -99
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
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
|
|
14
|
-
* All defaults have been applied by the
|
|
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
|
|
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:
|
|
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
|
|
14
|
-
* All defaults have been applied by the
|
|
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
|
|
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:
|
|
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
|
|
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(
|
|
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
|
|
@@ -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(
|
|
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
|
package/dist/glob-files-tool.cjs
CHANGED
|
@@ -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(
|
|
43
|
-
|
|
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
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
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
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
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 {
|
|
2
|
-
import {
|
|
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(
|
|
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(
|
|
16
|
-
|
|
17
|
-
|
|
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"}
|
package/dist/glob-files-tool.js
CHANGED
|
@@ -1,61 +1,36 @@
|
|
|
1
1
|
import * as path from "node:path";
|
|
2
2
|
import { z } from "zod";
|
|
3
|
-
import {
|
|
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(
|
|
10
|
-
|
|
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
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
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
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
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
|