@dexto/tools-filesystem 1.5.2 → 1.5.4
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.integration.test.cjs +36 -32
- package/dist/directory-approval.integration.test.js +36 -32
- package/dist/edit-file-tool.cjs +43 -19
- package/dist/edit-file-tool.js +43 -19
- package/dist/edit-file-tool.test.cjs +203 -0
- package/dist/edit-file-tool.test.d.cts +2 -0
- package/dist/edit-file-tool.test.d.ts +2 -0
- package/dist/edit-file-tool.test.js +180 -0
- package/dist/filesystem-service.cjs +24 -14
- package/dist/filesystem-service.d.cts +8 -3
- package/dist/filesystem-service.d.ts +8 -3
- package/dist/filesystem-service.js +24 -14
- package/dist/filesystem-service.test.cjs +233 -0
- package/dist/filesystem-service.test.d.cts +2 -0
- package/dist/filesystem-service.test.d.ts +2 -0
- package/dist/filesystem-service.test.js +210 -0
- package/dist/glob-files-tool.cjs +56 -3
- package/dist/glob-files-tool.d.cts +4 -3
- package/dist/glob-files-tool.d.ts +4 -3
- package/dist/glob-files-tool.js +46 -3
- package/dist/grep-content-tool.cjs +55 -3
- package/dist/grep-content-tool.d.cts +4 -3
- package/dist/grep-content-tool.d.ts +4 -3
- package/dist/grep-content-tool.js +45 -3
- package/dist/path-validator.cjs +29 -20
- package/dist/path-validator.d.cts +9 -2
- package/dist/path-validator.d.ts +9 -2
- package/dist/path-validator.js +29 -20
- package/dist/path-validator.test.cjs +54 -48
- package/dist/path-validator.test.js +54 -48
- package/dist/read-file-tool.cjs +2 -2
- package/dist/read-file-tool.js +2 -2
- package/dist/tool-provider.cjs +22 -7
- package/dist/tool-provider.d.cts +4 -1
- package/dist/tool-provider.d.ts +4 -1
- package/dist/tool-provider.js +22 -7
- package/dist/types.d.cts +6 -0
- package/dist/types.d.ts +6 -0
- package/dist/write-file-tool.cjs +41 -7
- package/dist/write-file-tool.js +46 -8
- package/dist/write-file-tool.test.cjs +217 -0
- package/dist/write-file-tool.test.d.cts +2 -0
- package/dist/write-file-tool.test.d.ts +2 -0
- package/dist/write-file-tool.test.js +194 -0
- package/package.json +2 -2
|
@@ -84,7 +84,7 @@ const createMockLogger = () => ({
|
|
|
84
84
|
});
|
|
85
85
|
const testFile = path.join(tempDir, "test.txt");
|
|
86
86
|
await fs.writeFile(testFile, "test content");
|
|
87
|
-
const override = tool.getApprovalOverride?.({ file_path: testFile });
|
|
87
|
+
const override = await tool.getApprovalOverride?.({ file_path: testFile });
|
|
88
88
|
(0, import_vitest.expect)(override).toBeNull();
|
|
89
89
|
});
|
|
90
90
|
(0, import_vitest.it)("should return directory access approval for external paths", async () => {
|
|
@@ -93,7 +93,7 @@ const createMockLogger = () => ({
|
|
|
93
93
|
directoryApproval
|
|
94
94
|
});
|
|
95
95
|
const externalPath = "/external/project/file.ts";
|
|
96
|
-
const override = tool.getApprovalOverride?.({ file_path: externalPath });
|
|
96
|
+
const override = await tool.getApprovalOverride?.({ file_path: externalPath });
|
|
97
97
|
(0, import_vitest.expect)(override).not.toBeNull();
|
|
98
98
|
(0, import_vitest.expect)(override?.type).toBe(import_core.ApprovalType.DIRECTORY_ACCESS);
|
|
99
99
|
const metadata = override?.metadata;
|
|
@@ -109,7 +109,7 @@ const createMockLogger = () => ({
|
|
|
109
109
|
directoryApproval
|
|
110
110
|
});
|
|
111
111
|
const externalPath = "/external/project/file.ts";
|
|
112
|
-
const override = tool.getApprovalOverride?.({ file_path: externalPath });
|
|
112
|
+
const override = await tool.getApprovalOverride?.({ file_path: externalPath });
|
|
113
113
|
(0, import_vitest.expect)(override).toBeNull();
|
|
114
114
|
(0, import_vitest.expect)(isSessionApprovedMock).toHaveBeenCalledWith(externalPath);
|
|
115
115
|
});
|
|
@@ -118,7 +118,7 @@ const createMockLogger = () => ({
|
|
|
118
118
|
fileSystemService,
|
|
119
119
|
directoryApproval
|
|
120
120
|
});
|
|
121
|
-
const override = tool.getApprovalOverride?.({});
|
|
121
|
+
const override = await tool.getApprovalOverride?.({});
|
|
122
122
|
(0, import_vitest.expect)(override).toBeNull();
|
|
123
123
|
});
|
|
124
124
|
});
|
|
@@ -129,7 +129,7 @@ const createMockLogger = () => ({
|
|
|
129
129
|
directoryApproval
|
|
130
130
|
});
|
|
131
131
|
const externalPath = "/external/project/file.ts";
|
|
132
|
-
tool.getApprovalOverride?.({ file_path: externalPath });
|
|
132
|
+
await tool.getApprovalOverride?.({ file_path: externalPath });
|
|
133
133
|
tool.onApprovalGranted?.({
|
|
134
134
|
approvalId: "test-approval",
|
|
135
135
|
status: import_core.ApprovalStatus.APPROVED,
|
|
@@ -146,7 +146,7 @@ const createMockLogger = () => ({
|
|
|
146
146
|
directoryApproval
|
|
147
147
|
});
|
|
148
148
|
const externalPath = "/external/project/file.ts";
|
|
149
|
-
tool.getApprovalOverride?.({ file_path: externalPath });
|
|
149
|
+
await tool.getApprovalOverride?.({ file_path: externalPath });
|
|
150
150
|
tool.onApprovalGranted?.({
|
|
151
151
|
approvalId: "test-approval",
|
|
152
152
|
status: import_core.ApprovalStatus.APPROVED,
|
|
@@ -163,7 +163,7 @@ const createMockLogger = () => ({
|
|
|
163
163
|
directoryApproval
|
|
164
164
|
});
|
|
165
165
|
const externalPath = "/external/project/file.ts";
|
|
166
|
-
tool.getApprovalOverride?.({ file_path: externalPath });
|
|
166
|
+
await tool.getApprovalOverride?.({ file_path: externalPath });
|
|
167
167
|
tool.onApprovalGranted?.({
|
|
168
168
|
approvalId: "test-approval",
|
|
169
169
|
status: import_core.ApprovalStatus.APPROVED,
|
|
@@ -180,7 +180,7 @@ const createMockLogger = () => ({
|
|
|
180
180
|
directoryApproval: void 0
|
|
181
181
|
});
|
|
182
182
|
const externalPath = "/external/project/file.ts";
|
|
183
|
-
tool.getApprovalOverride?.({ file_path: externalPath });
|
|
183
|
+
await tool.getApprovalOverride?.({ file_path: externalPath });
|
|
184
184
|
tool.onApprovalGranted?.({
|
|
185
185
|
approvalId: "test-approval",
|
|
186
186
|
status: import_core.ApprovalStatus.APPROVED,
|
|
@@ -211,7 +211,7 @@ const createMockLogger = () => ({
|
|
|
211
211
|
directoryApproval
|
|
212
212
|
});
|
|
213
213
|
const testFile = path.join(tempDir, "new-file.txt");
|
|
214
|
-
const override = tool.getApprovalOverride?.({
|
|
214
|
+
const override = await tool.getApprovalOverride?.({
|
|
215
215
|
file_path: testFile,
|
|
216
216
|
content: "test"
|
|
217
217
|
});
|
|
@@ -223,7 +223,7 @@ const createMockLogger = () => ({
|
|
|
223
223
|
directoryApproval
|
|
224
224
|
});
|
|
225
225
|
const externalPath = "/external/project/new.ts";
|
|
226
|
-
const override = tool.getApprovalOverride?.({
|
|
226
|
+
const override = await tool.getApprovalOverride?.({
|
|
227
227
|
file_path: externalPath,
|
|
228
228
|
content: "test"
|
|
229
229
|
});
|
|
@@ -240,7 +240,7 @@ const createMockLogger = () => ({
|
|
|
240
240
|
directoryApproval
|
|
241
241
|
});
|
|
242
242
|
const externalPath = "/external/project/new.ts";
|
|
243
|
-
const override = tool.getApprovalOverride?.({
|
|
243
|
+
const override = await tool.getApprovalOverride?.({
|
|
244
244
|
file_path: externalPath,
|
|
245
245
|
content: "test"
|
|
246
246
|
});
|
|
@@ -254,7 +254,7 @@ const createMockLogger = () => ({
|
|
|
254
254
|
directoryApproval
|
|
255
255
|
});
|
|
256
256
|
const externalPath = "/external/project/new.ts";
|
|
257
|
-
tool.getApprovalOverride?.({ file_path: externalPath, content: "test" });
|
|
257
|
+
await tool.getApprovalOverride?.({ file_path: externalPath, content: "test" });
|
|
258
258
|
tool.onApprovalGranted?.({
|
|
259
259
|
approvalId: "test-approval",
|
|
260
260
|
status: import_core.ApprovalStatus.APPROVED,
|
|
@@ -275,7 +275,7 @@ const createMockLogger = () => ({
|
|
|
275
275
|
directoryApproval
|
|
276
276
|
});
|
|
277
277
|
const testFile = path.join(tempDir, "existing.txt");
|
|
278
|
-
const override = tool.getApprovalOverride?.({
|
|
278
|
+
const override = await tool.getApprovalOverride?.({
|
|
279
279
|
file_path: testFile,
|
|
280
280
|
old_string: "old",
|
|
281
281
|
new_string: "new"
|
|
@@ -288,7 +288,7 @@ const createMockLogger = () => ({
|
|
|
288
288
|
directoryApproval
|
|
289
289
|
});
|
|
290
290
|
const externalPath = "/external/project/existing.ts";
|
|
291
|
-
const override = tool.getApprovalOverride?.({
|
|
291
|
+
const override = await tool.getApprovalOverride?.({
|
|
292
292
|
file_path: externalPath,
|
|
293
293
|
old_string: "old",
|
|
294
294
|
new_string: "new"
|
|
@@ -306,7 +306,7 @@ const createMockLogger = () => ({
|
|
|
306
306
|
directoryApproval
|
|
307
307
|
});
|
|
308
308
|
const externalPath = "/external/project/existing.ts";
|
|
309
|
-
const override = tool.getApprovalOverride?.({
|
|
309
|
+
const override = await tool.getApprovalOverride?.({
|
|
310
310
|
file_path: externalPath,
|
|
311
311
|
old_string: "old",
|
|
312
312
|
new_string: "new"
|
|
@@ -323,7 +323,7 @@ const createMockLogger = () => ({
|
|
|
323
323
|
});
|
|
324
324
|
const externalPath1 = "/external/project/file1.ts";
|
|
325
325
|
const externalPath2 = "/external/project/file2.ts";
|
|
326
|
-
let override = tool.getApprovalOverride?.({ file_path: externalPath1 });
|
|
326
|
+
let override = await tool.getApprovalOverride?.({ file_path: externalPath1 });
|
|
327
327
|
(0, import_vitest.expect)(override).not.toBeNull();
|
|
328
328
|
tool.onApprovalGranted?.({
|
|
329
329
|
approvalId: "approval-1",
|
|
@@ -335,7 +335,7 @@ const createMockLogger = () => ({
|
|
|
335
335
|
"session"
|
|
336
336
|
);
|
|
337
337
|
isSessionApprovedMock.mockReturnValue(true);
|
|
338
|
-
override = tool.getApprovalOverride?.({ file_path: externalPath2 });
|
|
338
|
+
override = await tool.getApprovalOverride?.({ file_path: externalPath2 });
|
|
339
339
|
(0, import_vitest.expect)(override).toBeNull();
|
|
340
340
|
});
|
|
341
341
|
(0, import_vitest.it)("should prompt for subsequent requests after once approval", async () => {
|
|
@@ -345,7 +345,7 @@ const createMockLogger = () => ({
|
|
|
345
345
|
});
|
|
346
346
|
const externalPath1 = "/external/project/file1.ts";
|
|
347
347
|
const externalPath2 = "/external/project/file2.ts";
|
|
348
|
-
let override = tool.getApprovalOverride?.({ file_path: externalPath1 });
|
|
348
|
+
let override = await tool.getApprovalOverride?.({ file_path: externalPath1 });
|
|
349
349
|
(0, import_vitest.expect)(override).not.toBeNull();
|
|
350
350
|
tool.onApprovalGranted?.({
|
|
351
351
|
approvalId: "approval-1",
|
|
@@ -357,7 +357,7 @@ const createMockLogger = () => ({
|
|
|
357
357
|
"once"
|
|
358
358
|
);
|
|
359
359
|
isSessionApprovedMock.mockReturnValue(false);
|
|
360
|
-
override = tool.getApprovalOverride?.({ file_path: externalPath2 });
|
|
360
|
+
override = await tool.getApprovalOverride?.({ file_path: externalPath2 });
|
|
361
361
|
(0, import_vitest.expect)(override).not.toBeNull();
|
|
362
362
|
});
|
|
363
363
|
});
|
|
@@ -372,9 +372,11 @@ const createMockLogger = () => ({
|
|
|
372
372
|
const approvedDir = "/external/project";
|
|
373
373
|
return normalizedPath.startsWith(approvedDir + path.sep) || normalizedPath === approvedDir;
|
|
374
374
|
});
|
|
375
|
-
let override = tool.getApprovalOverride?.({
|
|
375
|
+
let override = await tool.getApprovalOverride?.({
|
|
376
|
+
file_path: "/external/project/file.ts"
|
|
377
|
+
});
|
|
376
378
|
(0, import_vitest.expect)(override).toBeNull();
|
|
377
|
-
override = tool.getApprovalOverride?.({
|
|
379
|
+
override = await tool.getApprovalOverride?.({
|
|
378
380
|
file_path: "/external/project/deep/nested/file.ts"
|
|
379
381
|
});
|
|
380
382
|
(0, import_vitest.expect)(override).toBeNull();
|
|
@@ -389,9 +391,9 @@ const createMockLogger = () => ({
|
|
|
389
391
|
const approvedDir = "/external/sub";
|
|
390
392
|
return normalizedPath.startsWith(approvedDir + path.sep) || normalizedPath === approvedDir;
|
|
391
393
|
});
|
|
392
|
-
let override = tool.getApprovalOverride?.({ file_path: "/external/sub/file.ts" });
|
|
394
|
+
let override = await tool.getApprovalOverride?.({ file_path: "/external/sub/file.ts" });
|
|
393
395
|
(0, import_vitest.expect)(override).toBeNull();
|
|
394
|
-
override = tool.getApprovalOverride?.({ file_path: "/external/other/file.ts" });
|
|
396
|
+
override = await tool.getApprovalOverride?.({ file_path: "/external/other/file.ts" });
|
|
395
397
|
(0, import_vitest.expect)(override).not.toBeNull();
|
|
396
398
|
});
|
|
397
399
|
});
|
|
@@ -403,11 +405,11 @@ const createMockLogger = () => ({
|
|
|
403
405
|
});
|
|
404
406
|
const dir1Path = "/external/project1/file.ts";
|
|
405
407
|
const dir2Path = "/external/project2/file.ts";
|
|
406
|
-
const override1 = tool.getApprovalOverride?.({ file_path: dir1Path });
|
|
408
|
+
const override1 = await tool.getApprovalOverride?.({ file_path: dir1Path });
|
|
407
409
|
(0, import_vitest.expect)(override1).not.toBeNull();
|
|
408
410
|
const metadata1 = override1?.metadata;
|
|
409
411
|
(0, import_vitest.expect)(metadata1?.parentDir).toBe("/external/project1");
|
|
410
|
-
const override2 = tool.getApprovalOverride?.({ file_path: dir2Path });
|
|
412
|
+
const override2 = await tool.getApprovalOverride?.({ file_path: dir2Path });
|
|
411
413
|
(0, import_vitest.expect)(override2).not.toBeNull();
|
|
412
414
|
const metadata2 = override2?.metadata;
|
|
413
415
|
(0, import_vitest.expect)(metadata2?.parentDir).toBe("/external/project2");
|
|
@@ -420,16 +422,16 @@ const createMockLogger = () => ({
|
|
|
420
422
|
const editTool = (0, import_edit_file_tool.createEditFileTool)({ fileSystemService, directoryApproval });
|
|
421
423
|
const externalDir = "/external/project";
|
|
422
424
|
(0, import_vitest.expect)(
|
|
423
|
-
readTool.getApprovalOverride?.({ file_path: `${externalDir}/file1.ts` })
|
|
425
|
+
await readTool.getApprovalOverride?.({ file_path: `${externalDir}/file1.ts` })
|
|
424
426
|
).not.toBeNull();
|
|
425
427
|
(0, import_vitest.expect)(
|
|
426
|
-
writeTool.getApprovalOverride?.({
|
|
428
|
+
await writeTool.getApprovalOverride?.({
|
|
427
429
|
file_path: `${externalDir}/file2.ts`,
|
|
428
430
|
content: "test"
|
|
429
431
|
})
|
|
430
432
|
).not.toBeNull();
|
|
431
433
|
(0, import_vitest.expect)(
|
|
432
|
-
editTool.getApprovalOverride?.({
|
|
434
|
+
await editTool.getApprovalOverride?.({
|
|
433
435
|
file_path: `${externalDir}/file3.ts`,
|
|
434
436
|
old_string: "a",
|
|
435
437
|
new_string: "b"
|
|
@@ -437,16 +439,16 @@ const createMockLogger = () => ({
|
|
|
437
439
|
).not.toBeNull();
|
|
438
440
|
isSessionApprovedMock.mockReturnValue(true);
|
|
439
441
|
(0, import_vitest.expect)(
|
|
440
|
-
readTool.getApprovalOverride?.({ file_path: `${externalDir}/file1.ts` })
|
|
442
|
+
await readTool.getApprovalOverride?.({ file_path: `${externalDir}/file1.ts` })
|
|
441
443
|
).toBeNull();
|
|
442
444
|
(0, import_vitest.expect)(
|
|
443
|
-
writeTool.getApprovalOverride?.({
|
|
445
|
+
await writeTool.getApprovalOverride?.({
|
|
444
446
|
file_path: `${externalDir}/file2.ts`,
|
|
445
447
|
content: "test"
|
|
446
448
|
})
|
|
447
449
|
).toBeNull();
|
|
448
450
|
(0, import_vitest.expect)(
|
|
449
|
-
editTool.getApprovalOverride?.({
|
|
451
|
+
await editTool.getApprovalOverride?.({
|
|
450
452
|
file_path: `${externalDir}/file3.ts`,
|
|
451
453
|
old_string: "a",
|
|
452
454
|
new_string: "b"
|
|
@@ -460,7 +462,9 @@ const createMockLogger = () => ({
|
|
|
460
462
|
fileSystemService,
|
|
461
463
|
directoryApproval: void 0
|
|
462
464
|
});
|
|
463
|
-
const override = tool.getApprovalOverride?.({
|
|
465
|
+
const override = await tool.getApprovalOverride?.({
|
|
466
|
+
file_path: "/external/project/file.ts"
|
|
467
|
+
});
|
|
464
468
|
(0, import_vitest.expect)(override).not.toBeNull();
|
|
465
469
|
});
|
|
466
470
|
});
|
|
@@ -61,7 +61,7 @@ describe("Directory Approval Integration Tests", () => {
|
|
|
61
61
|
});
|
|
62
62
|
const testFile = path.join(tempDir, "test.txt");
|
|
63
63
|
await fs.writeFile(testFile, "test content");
|
|
64
|
-
const override = tool.getApprovalOverride?.({ file_path: testFile });
|
|
64
|
+
const override = await tool.getApprovalOverride?.({ file_path: testFile });
|
|
65
65
|
expect(override).toBeNull();
|
|
66
66
|
});
|
|
67
67
|
it("should return directory access approval for external paths", async () => {
|
|
@@ -70,7 +70,7 @@ describe("Directory Approval Integration Tests", () => {
|
|
|
70
70
|
directoryApproval
|
|
71
71
|
});
|
|
72
72
|
const externalPath = "/external/project/file.ts";
|
|
73
|
-
const override = tool.getApprovalOverride?.({ file_path: externalPath });
|
|
73
|
+
const override = await tool.getApprovalOverride?.({ file_path: externalPath });
|
|
74
74
|
expect(override).not.toBeNull();
|
|
75
75
|
expect(override?.type).toBe(ApprovalType.DIRECTORY_ACCESS);
|
|
76
76
|
const metadata = override?.metadata;
|
|
@@ -86,7 +86,7 @@ describe("Directory Approval Integration Tests", () => {
|
|
|
86
86
|
directoryApproval
|
|
87
87
|
});
|
|
88
88
|
const externalPath = "/external/project/file.ts";
|
|
89
|
-
const override = tool.getApprovalOverride?.({ file_path: externalPath });
|
|
89
|
+
const override = await tool.getApprovalOverride?.({ file_path: externalPath });
|
|
90
90
|
expect(override).toBeNull();
|
|
91
91
|
expect(isSessionApprovedMock).toHaveBeenCalledWith(externalPath);
|
|
92
92
|
});
|
|
@@ -95,7 +95,7 @@ describe("Directory Approval Integration Tests", () => {
|
|
|
95
95
|
fileSystemService,
|
|
96
96
|
directoryApproval
|
|
97
97
|
});
|
|
98
|
-
const override = tool.getApprovalOverride?.({});
|
|
98
|
+
const override = await tool.getApprovalOverride?.({});
|
|
99
99
|
expect(override).toBeNull();
|
|
100
100
|
});
|
|
101
101
|
});
|
|
@@ -106,7 +106,7 @@ describe("Directory Approval Integration Tests", () => {
|
|
|
106
106
|
directoryApproval
|
|
107
107
|
});
|
|
108
108
|
const externalPath = "/external/project/file.ts";
|
|
109
|
-
tool.getApprovalOverride?.({ file_path: externalPath });
|
|
109
|
+
await tool.getApprovalOverride?.({ file_path: externalPath });
|
|
110
110
|
tool.onApprovalGranted?.({
|
|
111
111
|
approvalId: "test-approval",
|
|
112
112
|
status: ApprovalStatus.APPROVED,
|
|
@@ -123,7 +123,7 @@ describe("Directory Approval Integration Tests", () => {
|
|
|
123
123
|
directoryApproval
|
|
124
124
|
});
|
|
125
125
|
const externalPath = "/external/project/file.ts";
|
|
126
|
-
tool.getApprovalOverride?.({ file_path: externalPath });
|
|
126
|
+
await tool.getApprovalOverride?.({ file_path: externalPath });
|
|
127
127
|
tool.onApprovalGranted?.({
|
|
128
128
|
approvalId: "test-approval",
|
|
129
129
|
status: ApprovalStatus.APPROVED,
|
|
@@ -140,7 +140,7 @@ describe("Directory Approval Integration Tests", () => {
|
|
|
140
140
|
directoryApproval
|
|
141
141
|
});
|
|
142
142
|
const externalPath = "/external/project/file.ts";
|
|
143
|
-
tool.getApprovalOverride?.({ file_path: externalPath });
|
|
143
|
+
await tool.getApprovalOverride?.({ file_path: externalPath });
|
|
144
144
|
tool.onApprovalGranted?.({
|
|
145
145
|
approvalId: "test-approval",
|
|
146
146
|
status: ApprovalStatus.APPROVED,
|
|
@@ -157,7 +157,7 @@ describe("Directory Approval Integration Tests", () => {
|
|
|
157
157
|
directoryApproval: void 0
|
|
158
158
|
});
|
|
159
159
|
const externalPath = "/external/project/file.ts";
|
|
160
|
-
tool.getApprovalOverride?.({ file_path: externalPath });
|
|
160
|
+
await tool.getApprovalOverride?.({ file_path: externalPath });
|
|
161
161
|
tool.onApprovalGranted?.({
|
|
162
162
|
approvalId: "test-approval",
|
|
163
163
|
status: ApprovalStatus.APPROVED,
|
|
@@ -188,7 +188,7 @@ describe("Directory Approval Integration Tests", () => {
|
|
|
188
188
|
directoryApproval
|
|
189
189
|
});
|
|
190
190
|
const testFile = path.join(tempDir, "new-file.txt");
|
|
191
|
-
const override = tool.getApprovalOverride?.({
|
|
191
|
+
const override = await tool.getApprovalOverride?.({
|
|
192
192
|
file_path: testFile,
|
|
193
193
|
content: "test"
|
|
194
194
|
});
|
|
@@ -200,7 +200,7 @@ describe("Directory Approval Integration Tests", () => {
|
|
|
200
200
|
directoryApproval
|
|
201
201
|
});
|
|
202
202
|
const externalPath = "/external/project/new.ts";
|
|
203
|
-
const override = tool.getApprovalOverride?.({
|
|
203
|
+
const override = await tool.getApprovalOverride?.({
|
|
204
204
|
file_path: externalPath,
|
|
205
205
|
content: "test"
|
|
206
206
|
});
|
|
@@ -217,7 +217,7 @@ describe("Directory Approval Integration Tests", () => {
|
|
|
217
217
|
directoryApproval
|
|
218
218
|
});
|
|
219
219
|
const externalPath = "/external/project/new.ts";
|
|
220
|
-
const override = tool.getApprovalOverride?.({
|
|
220
|
+
const override = await tool.getApprovalOverride?.({
|
|
221
221
|
file_path: externalPath,
|
|
222
222
|
content: "test"
|
|
223
223
|
});
|
|
@@ -231,7 +231,7 @@ describe("Directory Approval Integration Tests", () => {
|
|
|
231
231
|
directoryApproval
|
|
232
232
|
});
|
|
233
233
|
const externalPath = "/external/project/new.ts";
|
|
234
|
-
tool.getApprovalOverride?.({ file_path: externalPath, content: "test" });
|
|
234
|
+
await tool.getApprovalOverride?.({ file_path: externalPath, content: "test" });
|
|
235
235
|
tool.onApprovalGranted?.({
|
|
236
236
|
approvalId: "test-approval",
|
|
237
237
|
status: ApprovalStatus.APPROVED,
|
|
@@ -252,7 +252,7 @@ describe("Directory Approval Integration Tests", () => {
|
|
|
252
252
|
directoryApproval
|
|
253
253
|
});
|
|
254
254
|
const testFile = path.join(tempDir, "existing.txt");
|
|
255
|
-
const override = tool.getApprovalOverride?.({
|
|
255
|
+
const override = await tool.getApprovalOverride?.({
|
|
256
256
|
file_path: testFile,
|
|
257
257
|
old_string: "old",
|
|
258
258
|
new_string: "new"
|
|
@@ -265,7 +265,7 @@ describe("Directory Approval Integration Tests", () => {
|
|
|
265
265
|
directoryApproval
|
|
266
266
|
});
|
|
267
267
|
const externalPath = "/external/project/existing.ts";
|
|
268
|
-
const override = tool.getApprovalOverride?.({
|
|
268
|
+
const override = await tool.getApprovalOverride?.({
|
|
269
269
|
file_path: externalPath,
|
|
270
270
|
old_string: "old",
|
|
271
271
|
new_string: "new"
|
|
@@ -283,7 +283,7 @@ describe("Directory Approval Integration Tests", () => {
|
|
|
283
283
|
directoryApproval
|
|
284
284
|
});
|
|
285
285
|
const externalPath = "/external/project/existing.ts";
|
|
286
|
-
const override = tool.getApprovalOverride?.({
|
|
286
|
+
const override = await tool.getApprovalOverride?.({
|
|
287
287
|
file_path: externalPath,
|
|
288
288
|
old_string: "old",
|
|
289
289
|
new_string: "new"
|
|
@@ -300,7 +300,7 @@ describe("Directory Approval Integration Tests", () => {
|
|
|
300
300
|
});
|
|
301
301
|
const externalPath1 = "/external/project/file1.ts";
|
|
302
302
|
const externalPath2 = "/external/project/file2.ts";
|
|
303
|
-
let override = tool.getApprovalOverride?.({ file_path: externalPath1 });
|
|
303
|
+
let override = await tool.getApprovalOverride?.({ file_path: externalPath1 });
|
|
304
304
|
expect(override).not.toBeNull();
|
|
305
305
|
tool.onApprovalGranted?.({
|
|
306
306
|
approvalId: "approval-1",
|
|
@@ -312,7 +312,7 @@ describe("Directory Approval Integration Tests", () => {
|
|
|
312
312
|
"session"
|
|
313
313
|
);
|
|
314
314
|
isSessionApprovedMock.mockReturnValue(true);
|
|
315
|
-
override = tool.getApprovalOverride?.({ file_path: externalPath2 });
|
|
315
|
+
override = await tool.getApprovalOverride?.({ file_path: externalPath2 });
|
|
316
316
|
expect(override).toBeNull();
|
|
317
317
|
});
|
|
318
318
|
it("should prompt for subsequent requests after once approval", async () => {
|
|
@@ -322,7 +322,7 @@ describe("Directory Approval Integration Tests", () => {
|
|
|
322
322
|
});
|
|
323
323
|
const externalPath1 = "/external/project/file1.ts";
|
|
324
324
|
const externalPath2 = "/external/project/file2.ts";
|
|
325
|
-
let override = tool.getApprovalOverride?.({ file_path: externalPath1 });
|
|
325
|
+
let override = await tool.getApprovalOverride?.({ file_path: externalPath1 });
|
|
326
326
|
expect(override).not.toBeNull();
|
|
327
327
|
tool.onApprovalGranted?.({
|
|
328
328
|
approvalId: "approval-1",
|
|
@@ -334,7 +334,7 @@ describe("Directory Approval Integration Tests", () => {
|
|
|
334
334
|
"once"
|
|
335
335
|
);
|
|
336
336
|
isSessionApprovedMock.mockReturnValue(false);
|
|
337
|
-
override = tool.getApprovalOverride?.({ file_path: externalPath2 });
|
|
337
|
+
override = await tool.getApprovalOverride?.({ file_path: externalPath2 });
|
|
338
338
|
expect(override).not.toBeNull();
|
|
339
339
|
});
|
|
340
340
|
});
|
|
@@ -349,9 +349,11 @@ describe("Directory Approval Integration Tests", () => {
|
|
|
349
349
|
const approvedDir = "/external/project";
|
|
350
350
|
return normalizedPath.startsWith(approvedDir + path.sep) || normalizedPath === approvedDir;
|
|
351
351
|
});
|
|
352
|
-
let override = tool.getApprovalOverride?.({
|
|
352
|
+
let override = await tool.getApprovalOverride?.({
|
|
353
|
+
file_path: "/external/project/file.ts"
|
|
354
|
+
});
|
|
353
355
|
expect(override).toBeNull();
|
|
354
|
-
override = tool.getApprovalOverride?.({
|
|
356
|
+
override = await tool.getApprovalOverride?.({
|
|
355
357
|
file_path: "/external/project/deep/nested/file.ts"
|
|
356
358
|
});
|
|
357
359
|
expect(override).toBeNull();
|
|
@@ -366,9 +368,9 @@ describe("Directory Approval Integration Tests", () => {
|
|
|
366
368
|
const approvedDir = "/external/sub";
|
|
367
369
|
return normalizedPath.startsWith(approvedDir + path.sep) || normalizedPath === approvedDir;
|
|
368
370
|
});
|
|
369
|
-
let override = tool.getApprovalOverride?.({ file_path: "/external/sub/file.ts" });
|
|
371
|
+
let override = await tool.getApprovalOverride?.({ file_path: "/external/sub/file.ts" });
|
|
370
372
|
expect(override).toBeNull();
|
|
371
|
-
override = tool.getApprovalOverride?.({ file_path: "/external/other/file.ts" });
|
|
373
|
+
override = await tool.getApprovalOverride?.({ file_path: "/external/other/file.ts" });
|
|
372
374
|
expect(override).not.toBeNull();
|
|
373
375
|
});
|
|
374
376
|
});
|
|
@@ -380,11 +382,11 @@ describe("Directory Approval Integration Tests", () => {
|
|
|
380
382
|
});
|
|
381
383
|
const dir1Path = "/external/project1/file.ts";
|
|
382
384
|
const dir2Path = "/external/project2/file.ts";
|
|
383
|
-
const override1 = tool.getApprovalOverride?.({ file_path: dir1Path });
|
|
385
|
+
const override1 = await tool.getApprovalOverride?.({ file_path: dir1Path });
|
|
384
386
|
expect(override1).not.toBeNull();
|
|
385
387
|
const metadata1 = override1?.metadata;
|
|
386
388
|
expect(metadata1?.parentDir).toBe("/external/project1");
|
|
387
|
-
const override2 = tool.getApprovalOverride?.({ file_path: dir2Path });
|
|
389
|
+
const override2 = await tool.getApprovalOverride?.({ file_path: dir2Path });
|
|
388
390
|
expect(override2).not.toBeNull();
|
|
389
391
|
const metadata2 = override2?.metadata;
|
|
390
392
|
expect(metadata2?.parentDir).toBe("/external/project2");
|
|
@@ -397,16 +399,16 @@ describe("Directory Approval Integration Tests", () => {
|
|
|
397
399
|
const editTool = createEditFileTool({ fileSystemService, directoryApproval });
|
|
398
400
|
const externalDir = "/external/project";
|
|
399
401
|
expect(
|
|
400
|
-
readTool.getApprovalOverride?.({ file_path: `${externalDir}/file1.ts` })
|
|
402
|
+
await readTool.getApprovalOverride?.({ file_path: `${externalDir}/file1.ts` })
|
|
401
403
|
).not.toBeNull();
|
|
402
404
|
expect(
|
|
403
|
-
writeTool.getApprovalOverride?.({
|
|
405
|
+
await writeTool.getApprovalOverride?.({
|
|
404
406
|
file_path: `${externalDir}/file2.ts`,
|
|
405
407
|
content: "test"
|
|
406
408
|
})
|
|
407
409
|
).not.toBeNull();
|
|
408
410
|
expect(
|
|
409
|
-
editTool.getApprovalOverride?.({
|
|
411
|
+
await editTool.getApprovalOverride?.({
|
|
410
412
|
file_path: `${externalDir}/file3.ts`,
|
|
411
413
|
old_string: "a",
|
|
412
414
|
new_string: "b"
|
|
@@ -414,16 +416,16 @@ describe("Directory Approval Integration Tests", () => {
|
|
|
414
416
|
).not.toBeNull();
|
|
415
417
|
isSessionApprovedMock.mockReturnValue(true);
|
|
416
418
|
expect(
|
|
417
|
-
readTool.getApprovalOverride?.({ file_path: `${externalDir}/file1.ts` })
|
|
419
|
+
await readTool.getApprovalOverride?.({ file_path: `${externalDir}/file1.ts` })
|
|
418
420
|
).toBeNull();
|
|
419
421
|
expect(
|
|
420
|
-
writeTool.getApprovalOverride?.({
|
|
422
|
+
await writeTool.getApprovalOverride?.({
|
|
421
423
|
file_path: `${externalDir}/file2.ts`,
|
|
422
424
|
content: "test"
|
|
423
425
|
})
|
|
424
426
|
).toBeNull();
|
|
425
427
|
expect(
|
|
426
|
-
editTool.getApprovalOverride?.({
|
|
428
|
+
await editTool.getApprovalOverride?.({
|
|
427
429
|
file_path: `${externalDir}/file3.ts`,
|
|
428
430
|
old_string: "a",
|
|
429
431
|
new_string: "b"
|
|
@@ -437,7 +439,9 @@ describe("Directory Approval Integration Tests", () => {
|
|
|
437
439
|
fileSystemService,
|
|
438
440
|
directoryApproval: void 0
|
|
439
441
|
});
|
|
440
|
-
const override = tool.getApprovalOverride?.({
|
|
442
|
+
const override = await tool.getApprovalOverride?.({
|
|
443
|
+
file_path: "/external/project/file.ts"
|
|
444
|
+
});
|
|
441
445
|
expect(override).not.toBeNull();
|
|
442
446
|
});
|
|
443
447
|
});
|
package/dist/edit-file-tool.cjs
CHANGED
|
@@ -32,12 +32,18 @@ __export(edit_file_tool_exports, {
|
|
|
32
32
|
});
|
|
33
33
|
module.exports = __toCommonJS(edit_file_tool_exports);
|
|
34
34
|
var path = __toESM(require("node:path"), 1);
|
|
35
|
+
var import_node_crypto = require("node:crypto");
|
|
35
36
|
var import_zod = require("zod");
|
|
36
37
|
var import_diff = require("diff");
|
|
37
38
|
var import_core = require("@dexto/core");
|
|
38
39
|
var import_core2 = require("@dexto/core");
|
|
39
40
|
var import_core3 = require("@dexto/core");
|
|
40
41
|
var import_core4 = require("@dexto/core");
|
|
42
|
+
var import_error_codes = require("./error-codes.js");
|
|
43
|
+
const previewContentHashCache = /* @__PURE__ */ new Map();
|
|
44
|
+
function computeContentHash(content) {
|
|
45
|
+
return (0, import_node_crypto.createHash)("sha256").update(content, "utf8").digest("hex");
|
|
46
|
+
}
|
|
41
47
|
const EditFileInputSchema = import_zod.z.object({
|
|
42
48
|
file_path: import_zod.z.string().describe("Absolute path to the file to edit"),
|
|
43
49
|
old_string: import_zod.z.string().describe("Text to replace (must be unique unless replace_all is true)"),
|
|
@@ -69,10 +75,10 @@ function createEditFileTool(options) {
|
|
|
69
75
|
* Check if this edit operation needs directory access approval.
|
|
70
76
|
* Returns custom approval request if the file is outside allowed paths.
|
|
71
77
|
*/
|
|
72
|
-
getApprovalOverride: (args) => {
|
|
78
|
+
getApprovalOverride: async (args) => {
|
|
73
79
|
const { file_path } = args;
|
|
74
80
|
if (!file_path) return null;
|
|
75
|
-
const isAllowed = fileSystemService.isPathWithinConfigAllowed(file_path);
|
|
81
|
+
const isAllowed = await fileSystemService.isPathWithinConfigAllowed(file_path);
|
|
76
82
|
if (isAllowed) {
|
|
77
83
|
return null;
|
|
78
84
|
}
|
|
@@ -108,12 +114,19 @@ function createEditFileTool(options) {
|
|
|
108
114
|
/**
|
|
109
115
|
* Generate preview for approval UI - shows diff without modifying file
|
|
110
116
|
* Throws ToolError.validationFailed() for validation errors (file not found, string not found)
|
|
117
|
+
* Stores content hash for change detection in execute phase.
|
|
111
118
|
*/
|
|
112
|
-
generatePreview: async (input,
|
|
119
|
+
generatePreview: async (input, context) => {
|
|
113
120
|
const { file_path, old_string, new_string, replace_all } = input;
|
|
114
121
|
try {
|
|
115
122
|
const originalFile = await fileSystemService.readFile(file_path);
|
|
116
123
|
const originalContent = originalFile.content;
|
|
124
|
+
if (context?.toolCallId) {
|
|
125
|
+
previewContentHashCache.set(
|
|
126
|
+
context.toolCallId,
|
|
127
|
+
computeContentHash(originalContent)
|
|
128
|
+
);
|
|
129
|
+
}
|
|
117
130
|
if (!replace_all) {
|
|
118
131
|
const occurrences = originalContent.split(old_string).length - 1;
|
|
119
132
|
if (occurrences > 1) {
|
|
@@ -146,25 +159,36 @@ function createEditFileTool(options) {
|
|
|
146
159
|
return null;
|
|
147
160
|
}
|
|
148
161
|
},
|
|
149
|
-
execute: async (input,
|
|
162
|
+
execute: async (input, context) => {
|
|
150
163
|
const { file_path, old_string, new_string, replace_all } = input;
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
{
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
164
|
+
if (context?.toolCallId && previewContentHashCache.has(context.toolCallId)) {
|
|
165
|
+
const expectedHash = previewContentHashCache.get(context.toolCallId);
|
|
166
|
+
previewContentHashCache.delete(context.toolCallId);
|
|
167
|
+
let currentContent;
|
|
168
|
+
try {
|
|
169
|
+
const currentFile = await fileSystemService.readFile(file_path);
|
|
170
|
+
currentContent = currentFile.content;
|
|
171
|
+
} catch (error) {
|
|
172
|
+
if (error instanceof import_core4.DextoRuntimeError && error.code === import_error_codes.FileSystemErrorCode.FILE_NOT_FOUND) {
|
|
173
|
+
throw import_core2.ToolError.fileModifiedSincePreview("edit_file", file_path);
|
|
174
|
+
}
|
|
175
|
+
throw error;
|
|
176
|
+
}
|
|
177
|
+
const currentHash = computeContentHash(currentContent);
|
|
178
|
+
if (expectedHash !== currentHash) {
|
|
179
|
+
throw import_core2.ToolError.fileModifiedSincePreview("edit_file", file_path);
|
|
163
180
|
}
|
|
181
|
+
}
|
|
182
|
+
const result = await fileSystemService.editFile(file_path, {
|
|
183
|
+
oldString: old_string,
|
|
184
|
+
newString: new_string,
|
|
185
|
+
replaceAll: replace_all
|
|
186
|
+
});
|
|
187
|
+
const _display = generateDiffPreview(
|
|
188
|
+
file_path,
|
|
189
|
+
result.originalContent,
|
|
190
|
+
result.newContent
|
|
164
191
|
);
|
|
165
|
-
const newFile = await fileSystemService.readFile(file_path);
|
|
166
|
-
const newContent = newFile.content;
|
|
167
|
-
const _display = generateDiffPreview(file_path, originalContent, newContent);
|
|
168
192
|
return {
|
|
169
193
|
success: result.success,
|
|
170
194
|
path: result.path,
|