@dexto/tools-filesystem 1.6.25 → 1.6.27

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 (42) hide show
  1. package/dist/directory-approval.cjs +6 -4
  2. package/dist/directory-approval.d.ts.map +1 -1
  3. package/dist/directory-approval.integration.test.cjs +235 -6
  4. package/dist/directory-approval.integration.test.js +236 -6
  5. package/dist/directory-approval.js +6 -4
  6. package/dist/filesystem-service.cjs +6 -2
  7. package/dist/filesystem-service.d.ts.map +1 -1
  8. package/dist/filesystem-service.js +6 -2
  9. package/dist/glob-files-tool.cjs +3 -13
  10. package/dist/glob-files-tool.d.ts.map +1 -1
  11. package/dist/glob-files-tool.js +3 -3
  12. package/dist/glob-files-tool.test.cjs +115 -0
  13. package/dist/glob-files-tool.test.d.ts +2 -0
  14. package/dist/glob-files-tool.test.d.ts.map +1 -0
  15. package/dist/glob-files-tool.test.js +92 -0
  16. package/dist/grep-content-tool.cjs +3 -13
  17. package/dist/grep-content-tool.d.ts.map +1 -1
  18. package/dist/grep-content-tool.js +3 -3
  19. package/dist/grep-content-tool.test.cjs +115 -0
  20. package/dist/grep-content-tool.test.d.ts +2 -0
  21. package/dist/grep-content-tool.test.d.ts.map +1 -0
  22. package/dist/grep-content-tool.test.js +92 -0
  23. package/dist/path-utils.cjs +55 -0
  24. package/dist/path-utils.d.ts +11 -0
  25. package/dist/path-utils.d.ts.map +1 -0
  26. package/dist/path-utils.js +20 -0
  27. package/dist/path-utils.test.cjs +52 -0
  28. package/dist/path-utils.test.d.ts +2 -0
  29. package/dist/path-utils.test.d.ts.map +1 -0
  30. package/dist/path-utils.test.js +29 -0
  31. package/dist/path-validator.cjs +23 -9
  32. package/dist/path-validator.d.ts.map +1 -1
  33. package/dist/path-validator.js +23 -9
  34. package/dist/path-validator.test.cjs +41 -0
  35. package/dist/path-validator.test.js +19 -0
  36. package/dist/tool-factory-config.d.ts +2 -2
  37. package/dist/tool-factory.cjs +29 -50
  38. package/dist/tool-factory.d.ts.map +1 -1
  39. package/dist/tool-factory.js +29 -50
  40. package/dist/write-file-tool.test.cjs +33 -0
  41. package/dist/write-file-tool.test.js +33 -0
  42. package/package.json +3 -3
@@ -28,64 +28,43 @@ const fileSystemToolsFactory = {
28
28
  backupPath: config.backupPath,
29
29
  backupRetentionDays: config.backupRetentionDays
30
30
  };
31
- let fileSystemService;
32
31
  const resolveWorkingDirectory = (context) => context.workspace?.path ?? fileSystemConfig.workingDirectory ?? process.cwd();
33
- const applyWorkspace = (context, service) => {
34
- const workingDirectory = resolveWorkingDirectory(context);
35
- service.setWorkingDirectory(workingDirectory);
36
- };
37
- const resolveInjectedService = (context) => {
38
- const candidate = context.services?.filesystemService;
39
- if (!candidate) return null;
40
- if (candidate instanceof FileSystemService) return candidate;
41
- const hasMethods = typeof candidate.readFile === "function" && typeof candidate.writeFile === "function" && typeof candidate.setWorkingDirectory === "function" && typeof candidate.setDirectoryApprovalChecker === "function";
42
- return hasMethods ? candidate : null;
43
- };
44
- const getFileSystemService = async (context) => {
45
- const injectedService = resolveInjectedService(context);
46
- if (injectedService) {
47
- const approvalManager2 = context.services?.approval;
48
- if (!approvalManager2) {
49
- throw ToolError.configInvalid(
50
- "filesystem-tools requires ToolExecutionContext.services.approval"
51
- );
52
- }
53
- injectedService.setDirectoryApprovalChecker(
54
- (filePath) => approvalManager2.isDirectoryApproved(filePath)
55
- );
56
- applyWorkspace(context, injectedService);
57
- return injectedService;
58
- }
59
- if (fileSystemService) {
60
- const approvalManager2 = context.services?.approval;
61
- if (!approvalManager2) {
62
- throw ToolError.configInvalid(
63
- "filesystem-tools requires ToolExecutionContext.services.approval"
64
- );
65
- }
66
- fileSystemService.setDirectoryApprovalChecker(
67
- (filePath) => approvalManager2.isDirectoryApproved(filePath)
68
- );
69
- applyWorkspace(context, fileSystemService);
70
- return fileSystemService;
71
- }
72
- const logger = context.logger;
73
- fileSystemService = new FileSystemService(fileSystemConfig, logger);
32
+ const createScopedFileSystemService = (context, baseConfig) => {
74
33
  const approvalManager = context.services?.approval;
75
34
  if (!approvalManager) {
76
35
  throw ToolError.configInvalid(
77
36
  "filesystem-tools requires ToolExecutionContext.services.approval"
78
37
  );
79
38
  }
80
- fileSystemService.setDirectoryApprovalChecker(
81
- (filePath) => approvalManager.isDirectoryApproved(filePath)
39
+ const service = new FileSystemService(
40
+ {
41
+ ...baseConfig,
42
+ workingDirectory: resolveWorkingDirectory(context)
43
+ },
44
+ context.logger
45
+ );
46
+ service.setDirectoryApprovalChecker(
47
+ (filePath) => approvalManager.isDirectoryApproved(filePath, context.sessionId)
48
+ );
49
+ return service;
50
+ };
51
+ const resolveInjectedServiceConfig = (context) => {
52
+ const candidate = context.services?.filesystemService;
53
+ if (!candidate) return null;
54
+ if (candidate instanceof FileSystemService) return candidate.getConfig();
55
+ const getConfig = candidate.getConfig;
56
+ if (typeof getConfig === "function") {
57
+ return getConfig.call(candidate);
58
+ }
59
+ return null;
60
+ };
61
+ const getFileSystemService = async (context) => {
62
+ const scopedFileSystemService = createScopedFileSystemService(
63
+ context,
64
+ resolveInjectedServiceConfig(context) ?? fileSystemConfig
82
65
  );
83
- applyWorkspace(context, fileSystemService);
84
- fileSystemService.initialize().catch((error) => {
85
- const message = error instanceof Error ? error.message : String(error);
86
- logger.error(`Failed to initialize FileSystemService: ${message}`);
87
- });
88
- return fileSystemService;
66
+ await scopedFileSystemService.initialize();
67
+ return scopedFileSystemService;
89
68
  };
90
69
  const toolCreators = {
91
70
  read_file: () => createReadFileTool(getFileSystemService),
@@ -193,6 +193,39 @@ function createToolContext(logger, overrides = {}) {
193
193
  });
194
194
  });
195
195
  (0, import_vitest.describe)("File Modification Detection - New Files", () => {
196
+ (0, import_vitest.it)("should expand home-directory shorthand when creating a file", async () => {
197
+ const homeTempDir = await fs.mkdtemp(
198
+ path.join(os.homedir(), ".dexto-write-home-test-")
199
+ );
200
+ const homeRelativeDir = `~/${path.basename(homeTempDir)}`;
201
+ const fileSystemServiceForHome = new import_filesystem_service.FileSystemService(
202
+ {
203
+ allowedPaths: [homeTempDir],
204
+ blockedPaths: [],
205
+ blockedExtensions: [],
206
+ maxFileSize: 10 * 1024 * 1024,
207
+ workingDirectory: tempDir,
208
+ enableBackups: false,
209
+ backupRetentionDays: 7
210
+ },
211
+ mockLogger
212
+ );
213
+ await fileSystemServiceForHome.initialize();
214
+ const tool = (0, import_write_file_tool.createWriteFileTool)(async () => fileSystemServiceForHome);
215
+ try {
216
+ const parsedInput = tool.inputSchema.parse({
217
+ file_path: `${homeRelativeDir}/nested/new-file.txt`,
218
+ content: "brand new content",
219
+ create_dirs: true
220
+ });
221
+ const result = await tool.execute(parsedInput, createToolContext(mockLogger));
222
+ (0, import_vitest.expect)(result.success).toBe(true);
223
+ (0, import_vitest.expect)(result.path).toBe(path.join(homeTempDir, "nested", "new-file.txt"));
224
+ (0, import_vitest.expect)(await fs.readFile(result.path, "utf-8")).toBe("brand new content");
225
+ } finally {
226
+ await fs.rm(homeTempDir, { recursive: true, force: true });
227
+ }
228
+ });
196
229
  (0, import_vitest.it)("should succeed when creating new file that still does not exist", async () => {
197
230
  const tool = (0, import_write_file_tool.createWriteFileTool)(async () => fileSystemService);
198
231
  const testFile = path.join(tempDir, "new-file.txt");
@@ -170,6 +170,39 @@ describe("write_file tool", () => {
170
170
  });
171
171
  });
172
172
  describe("File Modification Detection - New Files", () => {
173
+ it("should expand home-directory shorthand when creating a file", async () => {
174
+ const homeTempDir = await fs.mkdtemp(
175
+ path.join(os.homedir(), ".dexto-write-home-test-")
176
+ );
177
+ const homeRelativeDir = `~/${path.basename(homeTempDir)}`;
178
+ const fileSystemServiceForHome = new FileSystemService(
179
+ {
180
+ allowedPaths: [homeTempDir],
181
+ blockedPaths: [],
182
+ blockedExtensions: [],
183
+ maxFileSize: 10 * 1024 * 1024,
184
+ workingDirectory: tempDir,
185
+ enableBackups: false,
186
+ backupRetentionDays: 7
187
+ },
188
+ mockLogger
189
+ );
190
+ await fileSystemServiceForHome.initialize();
191
+ const tool = createWriteFileTool(async () => fileSystemServiceForHome);
192
+ try {
193
+ const parsedInput = tool.inputSchema.parse({
194
+ file_path: `${homeRelativeDir}/nested/new-file.txt`,
195
+ content: "brand new content",
196
+ create_dirs: true
197
+ });
198
+ const result = await tool.execute(parsedInput, createToolContext(mockLogger));
199
+ expect(result.success).toBe(true);
200
+ expect(result.path).toBe(path.join(homeTempDir, "nested", "new-file.txt"));
201
+ expect(await fs.readFile(result.path, "utf-8")).toBe("brand new content");
202
+ } finally {
203
+ await fs.rm(homeTempDir, { recursive: true, force: true });
204
+ }
205
+ });
173
206
  it("should succeed when creating new file that still does not exist", async () => {
174
207
  const tool = createWriteFileTool(async () => fileSystemService);
175
208
  const testFile = path.join(tempDir, "new-file.txt");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dexto/tools-filesystem",
3
- "version": "1.6.25",
3
+ "version": "1.6.27",
4
4
  "description": "FileSystem tools factory for Dexto agents",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -22,8 +22,8 @@
22
22
  "glob": "^12.0.0",
23
23
  "safe-regex": "^2.1.1",
24
24
  "zod": "^3.25.0",
25
- "@dexto/agent-config": "1.6.25",
26
- "@dexto/core": "1.6.25"
25
+ "@dexto/agent-config": "1.6.27",
26
+ "@dexto/core": "1.6.27"
27
27
  },
28
28
  "devDependencies": {
29
29
  "@types/diff": "^5.2.3",