@dexto/tools-filesystem 1.6.0 → 1.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/directory-approval.cjs +44 -40
- package/dist/directory-approval.d.ts +8 -4
- package/dist/directory-approval.d.ts.map +1 -1
- package/dist/directory-approval.integration.test.cjs +107 -356
- package/dist/directory-approval.integration.test.d.ts +6 -6
- package/dist/directory-approval.integration.test.js +109 -360
- package/dist/directory-approval.js +45 -41
- package/dist/edit-file-tool.cjs +69 -47
- package/dist/edit-file-tool.d.ts.map +1 -1
- package/dist/edit-file-tool.js +77 -48
- package/dist/edit-file-tool.test.cjs +54 -11
- package/dist/edit-file-tool.test.js +54 -11
- package/dist/error-codes.cjs +4 -0
- package/dist/error-codes.d.ts +4 -0
- package/dist/error-codes.d.ts.map +1 -1
- package/dist/error-codes.js +4 -0
- package/dist/errors.cjs +48 -0
- package/dist/errors.d.ts +16 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +48 -0
- package/dist/filesystem-service.cjs +307 -9
- package/dist/filesystem-service.d.ts +28 -1
- package/dist/filesystem-service.d.ts.map +1 -1
- package/dist/filesystem-service.js +308 -10
- package/dist/glob-files-tool.cjs +12 -1
- package/dist/glob-files-tool.d.ts.map +1 -1
- package/dist/glob-files-tool.js +13 -2
- package/dist/grep-content-tool.cjs +13 -1
- package/dist/grep-content-tool.d.ts.map +1 -1
- package/dist/grep-content-tool.js +14 -2
- package/dist/index.cjs +3 -0
- package/dist/index.d.cts +852 -16
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/path-validator.cjs +28 -2
- package/dist/path-validator.d.ts +14 -0
- package/dist/path-validator.d.ts.map +1 -1
- package/dist/path-validator.js +28 -2
- package/dist/read-file-tool.cjs +7 -1
- package/dist/read-file-tool.d.ts.map +1 -1
- package/dist/read-file-tool.js +8 -2
- package/dist/tool-factory.cjs +21 -0
- package/dist/tool-factory.d.ts.map +1 -1
- package/dist/tool-factory.js +21 -0
- package/dist/types.d.ts +65 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/write-file-tool.cjs +60 -38
- package/dist/write-file-tool.d.ts +1 -1
- package/dist/write-file-tool.d.ts.map +1 -1
- package/dist/write-file-tool.js +67 -39
- package/dist/write-file-tool.test.cjs +75 -13
- package/dist/write-file-tool.test.js +75 -13
- package/package.json +4 -4
- package/dist/directory-approval.d.cts +0 -22
- package/dist/directory-approval.integration.test.d.cts +0 -2
- package/dist/edit-file-tool.d.cts +0 -34
- package/dist/edit-file-tool.test.d.cts +0 -2
- package/dist/error-codes.d.cts +0 -32
- package/dist/errors.d.cts +0 -112
- package/dist/file-tool-types.d.cts +0 -18
- package/dist/filesystem-service.d.cts +0 -117
- package/dist/filesystem-service.test.d.cts +0 -2
- package/dist/glob-files-tool.d.cts +0 -31
- package/dist/grep-content-tool.d.cts +0 -40
- package/dist/path-validator.d.cts +0 -97
- package/dist/path-validator.test.d.cts +0 -2
- package/dist/read-file-tool.d.cts +0 -31
- package/dist/tool-factory-config.d.cts +0 -63
- package/dist/tool-factory.d.cts +0 -7
- package/dist/types.d.cts +0 -178
- package/dist/write-file-tool.d.cts +0 -34
- package/dist/write-file-tool.test.d.cts +0 -2
|
@@ -2,12 +2,14 @@ import * as fs from "node:fs/promises";
|
|
|
2
2
|
import * as path from "node:path";
|
|
3
3
|
import { glob } from "glob";
|
|
4
4
|
import safeRegex from "safe-regex";
|
|
5
|
-
import { getDextoPath, DextoLogComponent } from "@dexto/core";
|
|
5
|
+
import { DextoRuntimeError, getDextoPath, DextoLogComponent } from "@dexto/core";
|
|
6
6
|
import { PathValidator } from "./path-validator.js";
|
|
7
7
|
import { FileSystemError } from "./errors.js";
|
|
8
8
|
const DEFAULT_ENCODING = "utf-8";
|
|
9
9
|
const DEFAULT_MAX_RESULTS = 1e3;
|
|
10
10
|
const DEFAULT_MAX_SEARCH_RESULTS = 100;
|
|
11
|
+
const DEFAULT_MAX_LIST_RESULTS = 5e3;
|
|
12
|
+
const DEFAULT_LIST_CONCURRENCY = 16;
|
|
11
13
|
class FileSystemService {
|
|
12
14
|
config;
|
|
13
15
|
pathValidator;
|
|
@@ -120,16 +122,14 @@ class FileSystemService {
|
|
|
120
122
|
async isPathWithinConfigAllowed(filePath) {
|
|
121
123
|
return this.pathValidator.isPathWithinAllowed(filePath);
|
|
122
124
|
}
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
*/
|
|
126
|
-
async readFile(filePath, options = {}) {
|
|
127
|
-
await this.ensureInitialized();
|
|
128
|
-
const validation = await this.pathValidator.validatePath(filePath);
|
|
125
|
+
async validateReadPath(filePath, mode) {
|
|
126
|
+
const validation = mode === "toolPreview" ? await this.pathValidator.validatePathForPreview(filePath) : await this.pathValidator.validatePath(filePath);
|
|
129
127
|
if (!validation.isValid || !validation.normalizedPath) {
|
|
130
128
|
throw FileSystemError.invalidPath(filePath, validation.error || "Unknown error");
|
|
131
129
|
}
|
|
132
|
-
|
|
130
|
+
return validation.normalizedPath;
|
|
131
|
+
}
|
|
132
|
+
async readNormalizedFile(normalizedPath, options = {}) {
|
|
133
133
|
try {
|
|
134
134
|
const stats = await fs.stat(normalizedPath);
|
|
135
135
|
if (!stats.isFile()) {
|
|
@@ -143,12 +143,18 @@ class FileSystemService {
|
|
|
143
143
|
);
|
|
144
144
|
}
|
|
145
145
|
} catch (error) {
|
|
146
|
+
if (error instanceof DextoRuntimeError && error.scope === "filesystem") {
|
|
147
|
+
throw error;
|
|
148
|
+
}
|
|
146
149
|
if (error.code === "ENOENT") {
|
|
147
150
|
throw FileSystemError.fileNotFound(normalizedPath);
|
|
148
151
|
}
|
|
149
152
|
if (error.code === "EACCES") {
|
|
150
153
|
throw FileSystemError.permissionDenied(normalizedPath, "read");
|
|
151
154
|
}
|
|
155
|
+
if (error instanceof DextoRuntimeError) {
|
|
156
|
+
throw error;
|
|
157
|
+
}
|
|
152
158
|
throw FileSystemError.readFailed(
|
|
153
159
|
normalizedPath,
|
|
154
160
|
error instanceof Error ? error.message : String(error)
|
|
@@ -170,20 +176,44 @@ class FileSystemService {
|
|
|
170
176
|
} else {
|
|
171
177
|
selectedLines = lines;
|
|
172
178
|
}
|
|
179
|
+
const returnedContent = selectedLines.join("\n");
|
|
173
180
|
return {
|
|
174
|
-
content:
|
|
181
|
+
content: returnedContent,
|
|
175
182
|
lines: selectedLines.length,
|
|
176
183
|
encoding,
|
|
177
184
|
truncated,
|
|
178
|
-
size: Buffer.byteLength(
|
|
185
|
+
size: Buffer.byteLength(returnedContent, encoding)
|
|
179
186
|
};
|
|
180
187
|
} catch (error) {
|
|
188
|
+
if (error instanceof DextoRuntimeError && error.scope === "filesystem") {
|
|
189
|
+
throw error;
|
|
190
|
+
}
|
|
181
191
|
throw FileSystemError.readFailed(
|
|
182
192
|
normalizedPath,
|
|
183
193
|
error instanceof Error ? error.message : String(error)
|
|
184
194
|
);
|
|
185
195
|
}
|
|
186
196
|
}
|
|
197
|
+
/**
|
|
198
|
+
* Read a file with validation and size limits
|
|
199
|
+
*/
|
|
200
|
+
async readFile(filePath, options = {}) {
|
|
201
|
+
await this.ensureInitialized();
|
|
202
|
+
const normalizedPath = await this.validateReadPath(filePath, "execute");
|
|
203
|
+
return await this.readNormalizedFile(normalizedPath, options);
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Preview-only file read that bypasses config-allowed roots.
|
|
207
|
+
*
|
|
208
|
+
* This is intended for UI previews (diffs, create previews) shown BEFORE a user
|
|
209
|
+
* confirms directory access for the tool call. The returned content is UI-only
|
|
210
|
+
* and should not be forwarded to the LLM.
|
|
211
|
+
*/
|
|
212
|
+
async readFileForToolPreview(filePath, options = {}) {
|
|
213
|
+
await this.ensureInitialized();
|
|
214
|
+
const normalizedPath = await this.validateReadPath(filePath, "toolPreview");
|
|
215
|
+
return await this.readNormalizedFile(normalizedPath, options);
|
|
216
|
+
}
|
|
187
217
|
/**
|
|
188
218
|
* Find files matching a glob pattern
|
|
189
219
|
*/
|
|
@@ -246,6 +276,274 @@ class FileSystemService {
|
|
|
246
276
|
);
|
|
247
277
|
}
|
|
248
278
|
}
|
|
279
|
+
/**
|
|
280
|
+
* List contents of a directory (non-recursive)
|
|
281
|
+
*/
|
|
282
|
+
async listDirectory(dirPath, options = {}) {
|
|
283
|
+
await this.ensureInitialized();
|
|
284
|
+
const validation = await this.pathValidator.validatePath(dirPath);
|
|
285
|
+
if (!validation.isValid || !validation.normalizedPath) {
|
|
286
|
+
throw FileSystemError.invalidPath(dirPath, validation.error || "Unknown error");
|
|
287
|
+
}
|
|
288
|
+
const normalizedPath = validation.normalizedPath;
|
|
289
|
+
try {
|
|
290
|
+
const stats = await fs.stat(normalizedPath);
|
|
291
|
+
if (!stats.isDirectory()) {
|
|
292
|
+
throw FileSystemError.invalidPath(normalizedPath, "Path is not a directory");
|
|
293
|
+
}
|
|
294
|
+
} catch (error) {
|
|
295
|
+
if (error instanceof DextoRuntimeError && error.scope === "filesystem") {
|
|
296
|
+
throw error;
|
|
297
|
+
}
|
|
298
|
+
if (error.code === "ENOENT") {
|
|
299
|
+
throw FileSystemError.directoryNotFound(normalizedPath);
|
|
300
|
+
}
|
|
301
|
+
if (error.code === "EACCES") {
|
|
302
|
+
throw FileSystemError.permissionDenied(normalizedPath, "read");
|
|
303
|
+
}
|
|
304
|
+
throw FileSystemError.listFailed(
|
|
305
|
+
normalizedPath,
|
|
306
|
+
error instanceof Error ? error.message : String(error)
|
|
307
|
+
);
|
|
308
|
+
}
|
|
309
|
+
const includeHidden = options.includeHidden ?? true;
|
|
310
|
+
const includeMetadata = options.includeMetadata !== false;
|
|
311
|
+
const maxEntries = options.maxEntries ?? DEFAULT_MAX_LIST_RESULTS;
|
|
312
|
+
try {
|
|
313
|
+
const dirEntries = await fs.readdir(normalizedPath, { withFileTypes: true });
|
|
314
|
+
const candidates = dirEntries.filter(
|
|
315
|
+
(entry) => includeHidden || !entry.name.startsWith(".")
|
|
316
|
+
);
|
|
317
|
+
const concurrency = DEFAULT_LIST_CONCURRENCY;
|
|
318
|
+
const validatedEntries = await this.mapWithConcurrency(
|
|
319
|
+
candidates,
|
|
320
|
+
concurrency,
|
|
321
|
+
async (entry) => {
|
|
322
|
+
const entryPath = path.join(normalizedPath, entry.name);
|
|
323
|
+
const entryValidation = await this.pathValidator.validatePath(entryPath);
|
|
324
|
+
if (!entryValidation.isValid || !entryValidation.normalizedPath) {
|
|
325
|
+
return null;
|
|
326
|
+
}
|
|
327
|
+
return {
|
|
328
|
+
entry,
|
|
329
|
+
normalizedPath: entryValidation.normalizedPath
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
);
|
|
333
|
+
const validEntries = validatedEntries.filter(Boolean);
|
|
334
|
+
if (maxEntries <= 0) {
|
|
335
|
+
return {
|
|
336
|
+
path: normalizedPath,
|
|
337
|
+
entries: [],
|
|
338
|
+
truncated: validEntries.length > 0,
|
|
339
|
+
totalEntries: validEntries.length
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
if (!includeMetadata) {
|
|
343
|
+
const entries2 = validEntries.slice(0, maxEntries).map((entry) => ({
|
|
344
|
+
name: entry.entry.name,
|
|
345
|
+
path: entry.normalizedPath,
|
|
346
|
+
isDirectory: entry.entry.isDirectory(),
|
|
347
|
+
size: 0,
|
|
348
|
+
modified: /* @__PURE__ */ new Date()
|
|
349
|
+
}));
|
|
350
|
+
return {
|
|
351
|
+
path: normalizedPath,
|
|
352
|
+
entries: entries2,
|
|
353
|
+
truncated: validEntries.length > maxEntries,
|
|
354
|
+
totalEntries: validEntries.length
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
const metadataEntries = await this.mapWithConcurrency(
|
|
358
|
+
validEntries,
|
|
359
|
+
concurrency,
|
|
360
|
+
async (entry) => {
|
|
361
|
+
try {
|
|
362
|
+
const stat = await fs.stat(entry.normalizedPath);
|
|
363
|
+
return {
|
|
364
|
+
name: entry.entry.name,
|
|
365
|
+
path: entry.normalizedPath,
|
|
366
|
+
isDirectory: entry.entry.isDirectory(),
|
|
367
|
+
size: stat.size,
|
|
368
|
+
modified: stat.mtime
|
|
369
|
+
};
|
|
370
|
+
} catch {
|
|
371
|
+
return null;
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
);
|
|
375
|
+
const entries = [];
|
|
376
|
+
let successfulStats = 0;
|
|
377
|
+
let cutoffIndex = -1;
|
|
378
|
+
for (let index = 0; index < metadataEntries.length; index += 1) {
|
|
379
|
+
const entry = metadataEntries[index];
|
|
380
|
+
if (!entry) {
|
|
381
|
+
continue;
|
|
382
|
+
}
|
|
383
|
+
successfulStats += 1;
|
|
384
|
+
if (entries.length < maxEntries) {
|
|
385
|
+
entries.push(entry);
|
|
386
|
+
}
|
|
387
|
+
if (successfulStats === maxEntries) {
|
|
388
|
+
cutoffIndex = index;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
const remainingSuccessful = cutoffIndex >= 0 ? metadataEntries.slice(cutoffIndex + 1).filter((entry) => entry !== null).length : 0;
|
|
392
|
+
const totalEntries = successfulStats < maxEntries ? successfulStats : maxEntries + remainingSuccessful;
|
|
393
|
+
return {
|
|
394
|
+
path: normalizedPath,
|
|
395
|
+
entries,
|
|
396
|
+
truncated: totalEntries > maxEntries,
|
|
397
|
+
totalEntries
|
|
398
|
+
};
|
|
399
|
+
} catch (error) {
|
|
400
|
+
throw FileSystemError.listFailed(
|
|
401
|
+
normalizedPath,
|
|
402
|
+
error instanceof Error ? error.message : String(error)
|
|
403
|
+
);
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
async mapWithConcurrency(items, limit, mapper) {
|
|
407
|
+
if (items.length === 0) {
|
|
408
|
+
return [];
|
|
409
|
+
}
|
|
410
|
+
const results = new Array(items.length);
|
|
411
|
+
let nextIndex = 0;
|
|
412
|
+
const workerCount = Math.min(Math.max(1, limit), items.length);
|
|
413
|
+
const workers = Array.from({ length: workerCount }, async () => {
|
|
414
|
+
while (true) {
|
|
415
|
+
const current = nextIndex++;
|
|
416
|
+
if (current >= items.length) {
|
|
417
|
+
return;
|
|
418
|
+
}
|
|
419
|
+
const item = items[current];
|
|
420
|
+
if (item === void 0) {
|
|
421
|
+
continue;
|
|
422
|
+
}
|
|
423
|
+
results[current] = await mapper(item, current);
|
|
424
|
+
}
|
|
425
|
+
});
|
|
426
|
+
await Promise.all(workers);
|
|
427
|
+
return results;
|
|
428
|
+
}
|
|
429
|
+
/**
|
|
430
|
+
* Create a directory
|
|
431
|
+
*/
|
|
432
|
+
async createDirectory(dirPath, options = {}) {
|
|
433
|
+
await this.ensureInitialized();
|
|
434
|
+
const validation = await this.pathValidator.validatePath(dirPath);
|
|
435
|
+
if (!validation.isValid || !validation.normalizedPath) {
|
|
436
|
+
throw FileSystemError.invalidPath(dirPath, validation.error || "Unknown error");
|
|
437
|
+
}
|
|
438
|
+
const normalizedPath = validation.normalizedPath;
|
|
439
|
+
const recursive = options.recursive ?? false;
|
|
440
|
+
try {
|
|
441
|
+
const firstCreated = await fs.mkdir(normalizedPath, { recursive });
|
|
442
|
+
const created = recursive ? typeof firstCreated === "string" : true;
|
|
443
|
+
return { path: normalizedPath, created };
|
|
444
|
+
} catch (error) {
|
|
445
|
+
const code = error.code;
|
|
446
|
+
if (code === "EEXIST") {
|
|
447
|
+
try {
|
|
448
|
+
const stat = await fs.stat(normalizedPath);
|
|
449
|
+
if (stat.isDirectory()) {
|
|
450
|
+
return { path: normalizedPath, created: false };
|
|
451
|
+
}
|
|
452
|
+
} catch {
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
if (code === "EACCES" || code === "EPERM") {
|
|
456
|
+
throw FileSystemError.permissionDenied(normalizedPath, "create directory");
|
|
457
|
+
}
|
|
458
|
+
throw FileSystemError.createDirFailed(
|
|
459
|
+
normalizedPath,
|
|
460
|
+
error instanceof Error ? error.message : String(error)
|
|
461
|
+
);
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
/**
|
|
465
|
+
* Delete a file or directory
|
|
466
|
+
*/
|
|
467
|
+
async deletePath(targetPath, options = {}) {
|
|
468
|
+
await this.ensureInitialized();
|
|
469
|
+
const validation = await this.pathValidator.validatePath(targetPath);
|
|
470
|
+
if (!validation.isValid || !validation.normalizedPath) {
|
|
471
|
+
throw FileSystemError.invalidPath(targetPath, validation.error || "Unknown error");
|
|
472
|
+
}
|
|
473
|
+
const normalizedPath = validation.normalizedPath;
|
|
474
|
+
try {
|
|
475
|
+
await fs.rm(normalizedPath, { recursive: options.recursive ?? false, force: false });
|
|
476
|
+
return { path: normalizedPath, deleted: true };
|
|
477
|
+
} catch (error) {
|
|
478
|
+
const code = error.code;
|
|
479
|
+
if (code === "ENOENT") {
|
|
480
|
+
throw FileSystemError.fileNotFound(normalizedPath);
|
|
481
|
+
}
|
|
482
|
+
if (code === "EACCES" || code === "EPERM") {
|
|
483
|
+
throw FileSystemError.permissionDenied(normalizedPath, "delete");
|
|
484
|
+
}
|
|
485
|
+
throw FileSystemError.deleteFailed(
|
|
486
|
+
normalizedPath,
|
|
487
|
+
error instanceof Error ? error.message : String(error)
|
|
488
|
+
);
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
/**
|
|
492
|
+
* Rename or move a file or directory
|
|
493
|
+
*/
|
|
494
|
+
async renamePath(fromPath, toPath) {
|
|
495
|
+
await this.ensureInitialized();
|
|
496
|
+
const fromValidation = await this.pathValidator.validatePath(fromPath);
|
|
497
|
+
if (!fromValidation.isValid || !fromValidation.normalizedPath) {
|
|
498
|
+
throw FileSystemError.invalidPath(fromPath, fromValidation.error || "Unknown error");
|
|
499
|
+
}
|
|
500
|
+
const toValidation = await this.pathValidator.validatePath(toPath);
|
|
501
|
+
if (!toValidation.isValid || !toValidation.normalizedPath) {
|
|
502
|
+
throw FileSystemError.invalidPath(toPath, toValidation.error || "Unknown error");
|
|
503
|
+
}
|
|
504
|
+
const normalizedFrom = fromValidation.normalizedPath;
|
|
505
|
+
const normalizedTo = toValidation.normalizedPath;
|
|
506
|
+
if (normalizedFrom === normalizedTo) {
|
|
507
|
+
return { from: normalizedFrom, to: normalizedTo };
|
|
508
|
+
}
|
|
509
|
+
try {
|
|
510
|
+
await fs.access(normalizedTo);
|
|
511
|
+
throw FileSystemError.renameFailed(
|
|
512
|
+
normalizedFrom,
|
|
513
|
+
`Target already exists: ${normalizedTo}`
|
|
514
|
+
);
|
|
515
|
+
} catch (error) {
|
|
516
|
+
const code = error.code;
|
|
517
|
+
if (!code) {
|
|
518
|
+
throw error;
|
|
519
|
+
}
|
|
520
|
+
if (code === "ENOENT") {
|
|
521
|
+
} else if (code === "EACCES" || code === "EPERM") {
|
|
522
|
+
throw FileSystemError.permissionDenied(normalizedTo, "rename");
|
|
523
|
+
} else {
|
|
524
|
+
throw FileSystemError.renameFailed(
|
|
525
|
+
normalizedFrom,
|
|
526
|
+
error instanceof Error ? error.message : String(error)
|
|
527
|
+
);
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
try {
|
|
531
|
+
await fs.rename(normalizedFrom, normalizedTo);
|
|
532
|
+
return { from: normalizedFrom, to: normalizedTo };
|
|
533
|
+
} catch (error) {
|
|
534
|
+
const code = error.code;
|
|
535
|
+
if (code === "ENOENT") {
|
|
536
|
+
throw FileSystemError.fileNotFound(normalizedFrom);
|
|
537
|
+
}
|
|
538
|
+
if (code === "EACCES" || code === "EPERM") {
|
|
539
|
+
throw FileSystemError.permissionDenied(normalizedFrom, "rename");
|
|
540
|
+
}
|
|
541
|
+
throw FileSystemError.renameFailed(
|
|
542
|
+
normalizedFrom,
|
|
543
|
+
error instanceof Error ? error.message : String(error)
|
|
544
|
+
);
|
|
545
|
+
}
|
|
546
|
+
}
|
|
249
547
|
/**
|
|
250
548
|
* Search for content in files (grep-like functionality)
|
|
251
549
|
*/
|
package/dist/glob-files-tool.cjs
CHANGED
|
@@ -43,13 +43,24 @@ const GlobFilesInputSchema = import_zod.z.object({
|
|
|
43
43
|
function createGlobFilesTool(getFileSystemService) {
|
|
44
44
|
return (0, import_core.defineTool)({
|
|
45
45
|
id: "glob_files",
|
|
46
|
-
displayName: "Find Files",
|
|
47
46
|
aliases: ["glob"],
|
|
48
47
|
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.",
|
|
49
48
|
inputSchema: GlobFilesInputSchema,
|
|
49
|
+
presentation: {
|
|
50
|
+
describeHeader: (input) => {
|
|
51
|
+
const bits = [`pattern=${input.pattern}`];
|
|
52
|
+
if (input.path) bits.push(`path=${input.path}`);
|
|
53
|
+
if (typeof input.max_results === "number") bits.push(`max=${input.max_results}`);
|
|
54
|
+
return (0, import_core.createLocalToolCallHeader)({
|
|
55
|
+
title: "Find Files",
|
|
56
|
+
argsText: (0, import_core.truncateForHeader)(bits.join(", "), 140)
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
},
|
|
50
60
|
...(0, import_directory_approval.createDirectoryAccessApprovalHandlers)({
|
|
51
61
|
toolName: "glob_files",
|
|
52
62
|
operation: "read",
|
|
63
|
+
inputSchema: GlobFilesInputSchema,
|
|
53
64
|
getFileSystemService,
|
|
54
65
|
resolvePaths: (input, fileSystemService) => {
|
|
55
66
|
const baseDir = fileSystemService.getWorkingDirectory();
|
|
@@ -1 +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,
|
|
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,CA2EnC"}
|
package/dist/glob-files-tool.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as path from "node:path";
|
|
2
2
|
import { z } from "zod";
|
|
3
|
-
import { defineTool } from "@dexto/core";
|
|
3
|
+
import { createLocalToolCallHeader, defineTool, truncateForHeader } from "@dexto/core";
|
|
4
4
|
import { createDirectoryAccessApprovalHandlers } from "./directory-approval.js";
|
|
5
5
|
const GlobFilesInputSchema = z.object({
|
|
6
6
|
pattern: z.string().describe('Glob pattern to match files (e.g., "**/*.ts", "src/**/*.js")'),
|
|
@@ -10,13 +10,24 @@ const GlobFilesInputSchema = z.object({
|
|
|
10
10
|
function createGlobFilesTool(getFileSystemService) {
|
|
11
11
|
return defineTool({
|
|
12
12
|
id: "glob_files",
|
|
13
|
-
displayName: "Find Files",
|
|
14
13
|
aliases: ["glob"],
|
|
15
14
|
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.",
|
|
16
15
|
inputSchema: GlobFilesInputSchema,
|
|
16
|
+
presentation: {
|
|
17
|
+
describeHeader: (input) => {
|
|
18
|
+
const bits = [`pattern=${input.pattern}`];
|
|
19
|
+
if (input.path) bits.push(`path=${input.path}`);
|
|
20
|
+
if (typeof input.max_results === "number") bits.push(`max=${input.max_results}`);
|
|
21
|
+
return createLocalToolCallHeader({
|
|
22
|
+
title: "Find Files",
|
|
23
|
+
argsText: truncateForHeader(bits.join(", "), 140)
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
},
|
|
17
27
|
...createDirectoryAccessApprovalHandlers({
|
|
18
28
|
toolName: "glob_files",
|
|
19
29
|
operation: "read",
|
|
30
|
+
inputSchema: GlobFilesInputSchema,
|
|
20
31
|
getFileSystemService,
|
|
21
32
|
resolvePaths: (input, fileSystemService) => {
|
|
22
33
|
const baseDir = fileSystemService.getWorkingDirectory();
|
|
@@ -48,13 +48,25 @@ const GrepContentInputSchema = import_zod.z.object({
|
|
|
48
48
|
function createGrepContentTool(getFileSystemService) {
|
|
49
49
|
return (0, import_core.defineTool)({
|
|
50
50
|
id: "grep_content",
|
|
51
|
-
displayName: "Search Files",
|
|
52
51
|
aliases: ["grep"],
|
|
53
52
|
description: 'Search for text patterns in files using regular expressions. Returns matching lines with file path, line number, and optional context lines. Use glob parameter to filter specific file types (e.g., "*.ts"). Supports case-insensitive search. Great for finding code patterns, function definitions, or specific text across multiple files.',
|
|
54
53
|
inputSchema: GrepContentInputSchema,
|
|
54
|
+
presentation: {
|
|
55
|
+
describeHeader: (input) => {
|
|
56
|
+
const bits = [`pattern=${input.pattern}`];
|
|
57
|
+
if (input.glob) bits.push(`glob=${input.glob}`);
|
|
58
|
+
if (input.path) bits.push(`path=${input.path}`);
|
|
59
|
+
if (typeof input.max_results === "number") bits.push(`max=${input.max_results}`);
|
|
60
|
+
return (0, import_core.createLocalToolCallHeader)({
|
|
61
|
+
title: "Search Files",
|
|
62
|
+
argsText: (0, import_core.truncateForHeader)(bits.join(", "), 140)
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
},
|
|
55
66
|
...(0, import_directory_approval.createDirectoryAccessApprovalHandlers)({
|
|
56
67
|
toolName: "grep_content",
|
|
57
68
|
operation: "read",
|
|
69
|
+
inputSchema: GrepContentInputSchema,
|
|
58
70
|
getFileSystemService,
|
|
59
71
|
resolvePaths: (input, fileSystemService) => {
|
|
60
72
|
const baseDir = fileSystemService.getWorkingDirectory();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"grep-content-tool.d.ts","sourceRoot":"","sources":["../src/grep-content-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,sBAAsB;;;;;;;;;;;;;;;;;;;;;EAiCf,CAAC;AAEd;;GAEG;AACH,wBAAgB,qBAAqB,CACjC,oBAAoB,EAAE,uBAAuB,GAC9C,IAAI,CAAC,OAAO,sBAAsB,CAAC,
|
|
1
|
+
{"version":3,"file":"grep-content-tool.d.ts","sourceRoot":"","sources":["../src/grep-content-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,sBAAsB;;;;;;;;;;;;;;;;;;;;;EAiCf,CAAC;AAEd;;GAEG;AACH,wBAAgB,qBAAqB,CACjC,oBAAoB,EAAE,uBAAuB,GAC9C,IAAI,CAAC,OAAO,sBAAsB,CAAC,CA6FrC"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as path from "node:path";
|
|
2
2
|
import { z } from "zod";
|
|
3
|
-
import { defineTool } from "@dexto/core";
|
|
3
|
+
import { createLocalToolCallHeader, defineTool, truncateForHeader } from "@dexto/core";
|
|
4
4
|
import { createDirectoryAccessApprovalHandlers } from "./directory-approval.js";
|
|
5
5
|
const GrepContentInputSchema = z.object({
|
|
6
6
|
pattern: z.string().describe("Regular expression pattern to search for"),
|
|
@@ -15,13 +15,25 @@ const GrepContentInputSchema = z.object({
|
|
|
15
15
|
function createGrepContentTool(getFileSystemService) {
|
|
16
16
|
return defineTool({
|
|
17
17
|
id: "grep_content",
|
|
18
|
-
displayName: "Search Files",
|
|
19
18
|
aliases: ["grep"],
|
|
20
19
|
description: 'Search for text patterns in files using regular expressions. Returns matching lines with file path, line number, and optional context lines. Use glob parameter to filter specific file types (e.g., "*.ts"). Supports case-insensitive search. Great for finding code patterns, function definitions, or specific text across multiple files.',
|
|
21
20
|
inputSchema: GrepContentInputSchema,
|
|
21
|
+
presentation: {
|
|
22
|
+
describeHeader: (input) => {
|
|
23
|
+
const bits = [`pattern=${input.pattern}`];
|
|
24
|
+
if (input.glob) bits.push(`glob=${input.glob}`);
|
|
25
|
+
if (input.path) bits.push(`path=${input.path}`);
|
|
26
|
+
if (typeof input.max_results === "number") bits.push(`max=${input.max_results}`);
|
|
27
|
+
return createLocalToolCallHeader({
|
|
28
|
+
title: "Search Files",
|
|
29
|
+
argsText: truncateForHeader(bits.join(", "), 140)
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
},
|
|
22
33
|
...createDirectoryAccessApprovalHandlers({
|
|
23
34
|
toolName: "grep_content",
|
|
24
35
|
operation: "read",
|
|
36
|
+
inputSchema: GrepContentInputSchema,
|
|
25
37
|
getFileSystemService,
|
|
26
38
|
resolvePaths: (input, fileSystemService) => {
|
|
27
39
|
const baseDir = fileSystemService.getWorkingDirectory();
|
package/dist/index.cjs
CHANGED
|
@@ -21,6 +21,7 @@ __export(index_exports, {
|
|
|
21
21
|
FileSystemError: () => import_errors.FileSystemError,
|
|
22
22
|
FileSystemErrorCode: () => import_error_codes.FileSystemErrorCode,
|
|
23
23
|
FileSystemService: () => import_filesystem_service.FileSystemService,
|
|
24
|
+
FileSystemToolsConfigSchema: () => import_tool_factory_config.FileSystemToolsConfigSchema,
|
|
24
25
|
PathValidator: () => import_path_validator.PathValidator,
|
|
25
26
|
createEditFileTool: () => import_edit_file_tool.createEditFileTool,
|
|
26
27
|
createGlobFilesTool: () => import_glob_files_tool.createGlobFilesTool,
|
|
@@ -31,6 +32,7 @@ __export(index_exports, {
|
|
|
31
32
|
});
|
|
32
33
|
module.exports = __toCommonJS(index_exports);
|
|
33
34
|
var import_tool_factory = require("./tool-factory.js");
|
|
35
|
+
var import_tool_factory_config = require("./tool-factory-config.js");
|
|
34
36
|
var import_filesystem_service = require("./filesystem-service.js");
|
|
35
37
|
var import_path_validator = require("./path-validator.js");
|
|
36
38
|
var import_errors = require("./errors.js");
|
|
@@ -45,6 +47,7 @@ var import_grep_content_tool = require("./grep-content-tool.js");
|
|
|
45
47
|
FileSystemError,
|
|
46
48
|
FileSystemErrorCode,
|
|
47
49
|
FileSystemService,
|
|
50
|
+
FileSystemToolsConfigSchema,
|
|
48
51
|
PathValidator,
|
|
49
52
|
createEditFileTool,
|
|
50
53
|
createGlobFilesTool,
|