@agentforge/tools 0.16.77 → 0.16.78
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/README.md +21 -0
- package/dist/index.cjs +219 -71
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +93 -37
- package/dist/index.d.ts +93 -37
- package/dist/index.js +214 -71
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -204,6 +204,27 @@ Tools for file system operations.
|
|
|
204
204
|
- **`pathRelative`** - Get relative path
|
|
205
205
|
- **`pathNormalize`** - Normalize paths
|
|
206
206
|
|
|
207
|
+
#### Filesystem Confinement
|
|
208
|
+
|
|
209
|
+
The standalone filesystem tool exports are intentionally powerful for trusted local automation. For model-exposed tools, configure a shared policy on the factory functions so every file and directory operation uses the same allowed roots and symlink checks:
|
|
210
|
+
|
|
211
|
+
```typescript
|
|
212
|
+
import {
|
|
213
|
+
createDirectoryOperationTools,
|
|
214
|
+
createFileOperationTools,
|
|
215
|
+
createFileSystemPolicy,
|
|
216
|
+
} from '@agentforge/tools';
|
|
217
|
+
|
|
218
|
+
const policy = createFileSystemPolicy({
|
|
219
|
+
workspaceRoot: process.cwd(),
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
const safeFileTools = createFileOperationTools({ policy });
|
|
223
|
+
const safeDirectoryTools = createDirectoryOperationTools({ policy });
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
The policy rejects `..` traversal, resolved symlink escapes, paths outside configured roots, and recursive deletion of a configured root. Use `allowedRoots` for multiple roots. Keep the default unrestricted exports for trusted local automation only; `allowOutsideRoots: true` is an explicit privileged opt-out when a configured factory must access the wider host filesystem. The `file-exists` tool preserves its legacy result shape for successful and missing-path checks, while policy violations return `{ success: false, error }`. Detailed `directory-list` results use non-following `lstat` metadata for symlink entries under both default and confined policies.
|
|
227
|
+
|
|
207
228
|
### Utility Tools (22 tools)
|
|
208
229
|
|
|
209
230
|
General utility tools for common operations.
|
package/dist/index.cjs
CHANGED
|
@@ -16,7 +16,7 @@ var events = require('events');
|
|
|
16
16
|
var stream = require('stream');
|
|
17
17
|
var crypto = require('crypto');
|
|
18
18
|
var fs = require('fs');
|
|
19
|
-
var
|
|
19
|
+
var path = require('path');
|
|
20
20
|
var dateFns = require('date-fns');
|
|
21
21
|
|
|
22
22
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
@@ -43,7 +43,7 @@ var net__default = /*#__PURE__*/_interopDefault(net);
|
|
|
43
43
|
var axios13__default = /*#__PURE__*/_interopDefault(axios13);
|
|
44
44
|
var cheerio__namespace = /*#__PURE__*/_interopNamespace(cheerio);
|
|
45
45
|
var neo4j__default = /*#__PURE__*/_interopDefault(neo4j);
|
|
46
|
-
var
|
|
46
|
+
var path__namespace = /*#__PURE__*/_interopNamespace(path);
|
|
47
47
|
|
|
48
48
|
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
49
49
|
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
@@ -698,7 +698,7 @@ function isRetryableError(error) {
|
|
|
698
698
|
return false;
|
|
699
699
|
}
|
|
700
700
|
function sleep(ms) {
|
|
701
|
-
return new Promise((
|
|
701
|
+
return new Promise((resolve3) => setTimeout(resolve3, ms));
|
|
702
702
|
}
|
|
703
703
|
async function retryWithBackoff(fn, config = DEFAULT_RETRY_CONFIG) {
|
|
704
704
|
let lastError;
|
|
@@ -2207,8 +2207,8 @@ var objectOmitSchema = zod.z.object({
|
|
|
2207
2207
|
});
|
|
2208
2208
|
|
|
2209
2209
|
// src/data/transformer/tools/shared.ts
|
|
2210
|
-
function getNestedValue(value,
|
|
2211
|
-
return
|
|
2210
|
+
function getNestedValue(value, path13) {
|
|
2211
|
+
return path13.split(".").reduce((current, key) => {
|
|
2212
2212
|
if (current == null) {
|
|
2213
2213
|
return void 0;
|
|
2214
2214
|
}
|
|
@@ -2598,7 +2598,7 @@ function isRetryableError2(error) {
|
|
|
2598
2598
|
return false;
|
|
2599
2599
|
}
|
|
2600
2600
|
function sleep2(ms) {
|
|
2601
|
-
return new Promise((
|
|
2601
|
+
return new Promise((resolve3) => setTimeout(resolve3, ms));
|
|
2602
2602
|
}
|
|
2603
2603
|
async function retryWithBackoff2(fn, config = DEFAULT_RETRY_CONFIG2) {
|
|
2604
2604
|
let lastError;
|
|
@@ -3497,16 +3497,16 @@ function formatRelationship(rel) {
|
|
|
3497
3497
|
properties: formatValue(rel.properties)
|
|
3498
3498
|
};
|
|
3499
3499
|
}
|
|
3500
|
-
function formatPath(
|
|
3500
|
+
function formatPath(path13) {
|
|
3501
3501
|
return {
|
|
3502
|
-
start: formatNode(
|
|
3503
|
-
end: formatNode(
|
|
3504
|
-
segments:
|
|
3502
|
+
start: formatNode(path13.start),
|
|
3503
|
+
end: formatNode(path13.end),
|
|
3504
|
+
segments: path13.segments.map((segment) => ({
|
|
3505
3505
|
start: formatNode(segment.start),
|
|
3506
3506
|
relationship: formatRelationship(segment.relationship),
|
|
3507
3507
|
end: formatNode(segment.end)
|
|
3508
3508
|
})),
|
|
3509
|
-
length:
|
|
3509
|
+
length: path13.length
|
|
3510
3510
|
};
|
|
3511
3511
|
}
|
|
3512
3512
|
function formatResults(records) {
|
|
@@ -5683,8 +5683,8 @@ function toBatchErrorMessage(error) {
|
|
|
5683
5683
|
return error instanceof Error ? error.message : String(error);
|
|
5684
5684
|
}
|
|
5685
5685
|
function delayBatchRetry(ms) {
|
|
5686
|
-
return new Promise((
|
|
5687
|
-
setTimeout(
|
|
5686
|
+
return new Promise((resolve3) => {
|
|
5687
|
+
setTimeout(resolve3, ms);
|
|
5688
5688
|
});
|
|
5689
5689
|
}
|
|
5690
5690
|
|
|
@@ -6110,7 +6110,7 @@ function withTransactionTimeout(operation, timeoutMs, onTimeout) {
|
|
|
6110
6110
|
if (!timeoutMs) {
|
|
6111
6111
|
return operation;
|
|
6112
6112
|
}
|
|
6113
|
-
return new Promise((
|
|
6113
|
+
return new Promise((resolve3, reject) => {
|
|
6114
6114
|
let timedOut = false;
|
|
6115
6115
|
const timer = setTimeout(() => {
|
|
6116
6116
|
timedOut = true;
|
|
@@ -6122,7 +6122,7 @@ function withTransactionTimeout(operation, timeoutMs, onTimeout) {
|
|
|
6122
6122
|
return;
|
|
6123
6123
|
}
|
|
6124
6124
|
clearTimeout(timer);
|
|
6125
|
-
|
|
6125
|
+
resolve3(result);
|
|
6126
6126
|
}).catch((error) => {
|
|
6127
6127
|
if (timedOut) {
|
|
6128
6128
|
return;
|
|
@@ -9355,11 +9355,135 @@ var fileDeleteSchema = zod.z.object({
|
|
|
9355
9355
|
var fileExistsSchema = zod.z.object({
|
|
9356
9356
|
path: zod.z.string().describe("Path to check")
|
|
9357
9357
|
});
|
|
9358
|
-
|
|
9358
|
+
var FileSystemPolicyError = class extends Error {
|
|
9359
|
+
constructor(message, operation, inputPath) {
|
|
9360
|
+
super(message);
|
|
9361
|
+
this.operation = operation;
|
|
9362
|
+
this.inputPath = inputPath;
|
|
9363
|
+
this.name = "FileSystemPolicyError";
|
|
9364
|
+
}
|
|
9365
|
+
code = "FILE_SYSTEM_POLICY_VIOLATION";
|
|
9366
|
+
};
|
|
9367
|
+
function containsTraversal(inputPath) {
|
|
9368
|
+
return inputPath.split(/[\\/]+/).includes("..");
|
|
9369
|
+
}
|
|
9370
|
+
function isWithinRoot(root, target) {
|
|
9371
|
+
const relative4 = path__namespace.relative(root, target);
|
|
9372
|
+
return relative4 === "" || !relative4.startsWith(`..${path__namespace.sep}`) && relative4 !== ".." && !path__namespace.isAbsolute(relative4);
|
|
9373
|
+
}
|
|
9374
|
+
async function resolveWithMissingTail(inputPath) {
|
|
9375
|
+
let currentPath = inputPath;
|
|
9376
|
+
const missingSegments = [];
|
|
9377
|
+
while (true) {
|
|
9378
|
+
try {
|
|
9379
|
+
const resolvedPath = await fs.promises.realpath(currentPath);
|
|
9380
|
+
return path__namespace.join(resolvedPath, ...missingSegments);
|
|
9381
|
+
} catch (error) {
|
|
9382
|
+
const code = error.code;
|
|
9383
|
+
if (code !== "ENOENT" && code !== "ENOTDIR") {
|
|
9384
|
+
throw error;
|
|
9385
|
+
}
|
|
9386
|
+
const parentPath = path__namespace.dirname(currentPath);
|
|
9387
|
+
if (parentPath === currentPath) {
|
|
9388
|
+
throw error;
|
|
9389
|
+
}
|
|
9390
|
+
missingSegments.unshift(path__namespace.basename(currentPath));
|
|
9391
|
+
currentPath = parentPath;
|
|
9392
|
+
}
|
|
9393
|
+
}
|
|
9394
|
+
}
|
|
9395
|
+
var FileSystemPolicy = class {
|
|
9396
|
+
allowedRoots;
|
|
9397
|
+
allowOutsideRoots;
|
|
9398
|
+
allowRootDeletion;
|
|
9399
|
+
baseDirectory;
|
|
9400
|
+
constructor(options = {}) {
|
|
9401
|
+
const configuredRoots = [
|
|
9402
|
+
...options.allowedRoots ?? [],
|
|
9403
|
+
...options.workspaceRoot ? [options.workspaceRoot] : []
|
|
9404
|
+
];
|
|
9405
|
+
this.allowedRoots = [...new Set(configuredRoots.map((root) => path__namespace.resolve(root)))];
|
|
9406
|
+
this.baseDirectory = path__namespace.resolve(options.workspaceRoot ?? process.cwd());
|
|
9407
|
+
this.allowOutsideRoots = options.allowOutsideRoots ?? this.allowedRoots.length === 0;
|
|
9408
|
+
this.allowRootDeletion = options.allowRootDeletion ?? this.allowOutsideRoots;
|
|
9409
|
+
}
|
|
9410
|
+
async resolvePath(inputPath, operation) {
|
|
9411
|
+
const { resolvedPath } = await this.resolvePathWithRoots(inputPath, operation);
|
|
9412
|
+
return resolvedPath;
|
|
9413
|
+
}
|
|
9414
|
+
async resolveDeletePath(inputPath, recursive) {
|
|
9415
|
+
const { resolvedPath, resolvedRoots } = await this.resolvePathWithRoots(inputPath, "directory deletion");
|
|
9416
|
+
if (recursive && !this.allowRootDeletion && resolvedRoots.some((root) => root === resolvedPath)) {
|
|
9417
|
+
throw new FileSystemPolicyError(
|
|
9418
|
+
"Filesystem policy blocked directory deletion: recursive deletion of an allowed root is not permitted",
|
|
9419
|
+
"directory deletion",
|
|
9420
|
+
inputPath
|
|
9421
|
+
);
|
|
9422
|
+
}
|
|
9423
|
+
return resolvedPath;
|
|
9424
|
+
}
|
|
9425
|
+
async resolvePathWithRoots(inputPath, operation) {
|
|
9426
|
+
const absolutePath = path__namespace.resolve(this.baseDirectory, inputPath);
|
|
9427
|
+
if (this.allowOutsideRoots) {
|
|
9428
|
+
return { resolvedPath: absolutePath, resolvedRoots: [] };
|
|
9429
|
+
}
|
|
9430
|
+
if (containsTraversal(inputPath)) {
|
|
9431
|
+
throw new FileSystemPolicyError(
|
|
9432
|
+
`Filesystem policy blocked ${operation}: path traversal is not allowed`,
|
|
9433
|
+
operation,
|
|
9434
|
+
inputPath
|
|
9435
|
+
);
|
|
9436
|
+
}
|
|
9437
|
+
let resolvedPath;
|
|
9438
|
+
try {
|
|
9439
|
+
resolvedPath = await resolveWithMissingTail(absolutePath);
|
|
9440
|
+
} catch {
|
|
9441
|
+
throw new FileSystemPolicyError(
|
|
9442
|
+
`Filesystem policy could not resolve ${operation} path`,
|
|
9443
|
+
operation,
|
|
9444
|
+
inputPath
|
|
9445
|
+
);
|
|
9446
|
+
}
|
|
9447
|
+
const resolvedRoots = await this.resolveRoots(operation, inputPath);
|
|
9448
|
+
if (!resolvedRoots.some((root) => isWithinRoot(root, resolvedPath))) {
|
|
9449
|
+
throw new FileSystemPolicyError(
|
|
9450
|
+
`Filesystem policy blocked ${operation}: path is outside the allowed roots`,
|
|
9451
|
+
operation,
|
|
9452
|
+
inputPath
|
|
9453
|
+
);
|
|
9454
|
+
}
|
|
9455
|
+
return { resolvedPath, resolvedRoots };
|
|
9456
|
+
}
|
|
9457
|
+
async resolveRoots(operation, inputPath) {
|
|
9458
|
+
try {
|
|
9459
|
+
return await Promise.all(this.allowedRoots.map((root) => fs.promises.realpath(root)));
|
|
9460
|
+
} catch {
|
|
9461
|
+
throw new FileSystemPolicyError(
|
|
9462
|
+
`Filesystem policy could not resolve an allowed root for ${operation}`,
|
|
9463
|
+
operation,
|
|
9464
|
+
inputPath
|
|
9465
|
+
);
|
|
9466
|
+
}
|
|
9467
|
+
}
|
|
9468
|
+
};
|
|
9469
|
+
var DEFAULT_FILE_SYSTEM_POLICY = new FileSystemPolicy();
|
|
9470
|
+
function createFileSystemPolicy(options = {}) {
|
|
9471
|
+
return new FileSystemPolicy(options);
|
|
9472
|
+
}
|
|
9473
|
+
function resolveFileSystemPolicy(policy) {
|
|
9474
|
+
if (!policy) {
|
|
9475
|
+
return DEFAULT_FILE_SYSTEM_POLICY;
|
|
9476
|
+
}
|
|
9477
|
+
return policy instanceof FileSystemPolicy ? policy : createFileSystemPolicy(policy);
|
|
9478
|
+
}
|
|
9479
|
+
|
|
9480
|
+
// src/file/operations/tools/file-reader.ts
|
|
9481
|
+
function createFileReaderTool(defaultEncoding = "utf8", policy = DEFAULT_FILE_SYSTEM_POLICY) {
|
|
9359
9482
|
return core.toolBuilder().name("file-reader").description("Read the contents of a file from the file system. Supports text and binary files with various encodings.").category(core.ToolCategory.FILE_SYSTEM).tags(["file", "read", "io", "filesystem"]).schema(fileReaderSchema).implementSafe(async (input) => {
|
|
9360
9483
|
const encoding = input.encoding || defaultEncoding;
|
|
9361
|
-
const
|
|
9362
|
-
const
|
|
9484
|
+
const safePath = await policy.resolvePath(input.path, "file read");
|
|
9485
|
+
const content = await fs.promises.readFile(safePath, encoding);
|
|
9486
|
+
const stats = await fs.promises.stat(safePath);
|
|
9363
9487
|
return {
|
|
9364
9488
|
content,
|
|
9365
9489
|
size: stats.size,
|
|
@@ -9368,16 +9492,17 @@ function createFileReaderTool(defaultEncoding = "utf8") {
|
|
|
9368
9492
|
};
|
|
9369
9493
|
}).build();
|
|
9370
9494
|
}
|
|
9371
|
-
function createFileWriterTool(defaultEncoding = "utf8", createDirsDefault = false) {
|
|
9495
|
+
function createFileWriterTool(defaultEncoding = "utf8", createDirsDefault = false, policy = DEFAULT_FILE_SYSTEM_POLICY) {
|
|
9372
9496
|
return core.toolBuilder().name("file-writer").description("Write content to a file. Creates the file if it doesn't exist, or overwrites it if it does.").category(core.ToolCategory.FILE_SYSTEM).tags(["file", "write", "io", "filesystem"]).schema(fileWriterSchema).implementSafe(async (input) => {
|
|
9373
9497
|
const encoding = input.encoding || defaultEncoding;
|
|
9374
9498
|
const createDirs = input.createDirs ?? createDirsDefault;
|
|
9499
|
+
const safePath = await policy.resolvePath(input.path, "file write");
|
|
9375
9500
|
if (createDirs) {
|
|
9376
|
-
const dir =
|
|
9501
|
+
const dir = path__namespace.dirname(safePath);
|
|
9377
9502
|
await fs.promises.mkdir(dir, { recursive: true });
|
|
9378
9503
|
}
|
|
9379
|
-
await fs.promises.writeFile(
|
|
9380
|
-
const stats = await fs.promises.stat(
|
|
9504
|
+
await fs.promises.writeFile(safePath, input.content, encoding);
|
|
9505
|
+
const stats = await fs.promises.stat(safePath);
|
|
9381
9506
|
return {
|
|
9382
9507
|
path: input.path,
|
|
9383
9508
|
size: stats.size,
|
|
@@ -9385,31 +9510,34 @@ function createFileWriterTool(defaultEncoding = "utf8", createDirsDefault = fals
|
|
|
9385
9510
|
};
|
|
9386
9511
|
}).build();
|
|
9387
9512
|
}
|
|
9388
|
-
function createFileAppendTool(defaultEncoding = "utf8") {
|
|
9513
|
+
function createFileAppendTool(defaultEncoding = "utf8", policy = DEFAULT_FILE_SYSTEM_POLICY) {
|
|
9389
9514
|
return core.toolBuilder().name("file-append").description("Append content to the end of a file. Creates the file if it doesn't exist.").category(core.ToolCategory.FILE_SYSTEM).tags(["file", "append", "io", "filesystem"]).schema(fileAppendSchema).implementSafe(async (input) => {
|
|
9390
9515
|
const encoding = input.encoding || defaultEncoding;
|
|
9391
|
-
await
|
|
9392
|
-
|
|
9516
|
+
const safePath = await policy.resolvePath(input.path, "file append");
|
|
9517
|
+
await fs.promises.appendFile(safePath, input.content, encoding);
|
|
9518
|
+
const stats = await fs.promises.stat(safePath);
|
|
9393
9519
|
return {
|
|
9394
9520
|
path: input.path,
|
|
9395
9521
|
size: stats.size
|
|
9396
9522
|
};
|
|
9397
9523
|
}).build();
|
|
9398
9524
|
}
|
|
9399
|
-
function createFileDeleteTool() {
|
|
9525
|
+
function createFileDeleteTool(policy = DEFAULT_FILE_SYSTEM_POLICY) {
|
|
9400
9526
|
return core.toolBuilder().name("file-delete").description("Delete a file from the file system. Returns an error if the file doesn't exist.").category(core.ToolCategory.FILE_SYSTEM).tags(["file", "delete", "remove", "filesystem"]).schema(fileDeleteSchema).implementSafe(async (input) => {
|
|
9401
|
-
await
|
|
9527
|
+
const safePath = await policy.resolvePath(input.path, "file deletion");
|
|
9528
|
+
await fs.promises.unlink(safePath);
|
|
9402
9529
|
return {
|
|
9403
9530
|
path: input.path,
|
|
9404
9531
|
message: "File deleted successfully"
|
|
9405
9532
|
};
|
|
9406
9533
|
}).build();
|
|
9407
9534
|
}
|
|
9408
|
-
function createFileExistsTool() {
|
|
9535
|
+
function createFileExistsTool(policy = DEFAULT_FILE_SYSTEM_POLICY) {
|
|
9409
9536
|
return core.toolBuilder().name("file-exists").description("Check if a file or directory exists at the specified path.").category(core.ToolCategory.FILE_SYSTEM).tags(["file", "exists", "check", "filesystem"]).schema(fileExistsSchema).implement(async (input) => {
|
|
9410
9537
|
try {
|
|
9411
|
-
await
|
|
9412
|
-
|
|
9538
|
+
const safePath = await policy.resolvePath(input.path, "file existence check");
|
|
9539
|
+
await fs.promises.access(safePath);
|
|
9540
|
+
const stats = await fs.promises.stat(safePath);
|
|
9413
9541
|
return {
|
|
9414
9542
|
exists: true,
|
|
9415
9543
|
path: input.path,
|
|
@@ -9418,7 +9546,13 @@ function createFileExistsTool() {
|
|
|
9418
9546
|
size: stats.size,
|
|
9419
9547
|
modified: stats.mtime.toISOString()
|
|
9420
9548
|
};
|
|
9421
|
-
} catch {
|
|
9549
|
+
} catch (error) {
|
|
9550
|
+
if (error instanceof FileSystemPolicyError) {
|
|
9551
|
+
return {
|
|
9552
|
+
success: false,
|
|
9553
|
+
error: error.message
|
|
9554
|
+
};
|
|
9555
|
+
}
|
|
9422
9556
|
return {
|
|
9423
9557
|
exists: false,
|
|
9424
9558
|
path: input.path
|
|
@@ -9443,14 +9577,16 @@ var fileOperationTools = [
|
|
|
9443
9577
|
function createFileOperationTools(config = {}) {
|
|
9444
9578
|
const {
|
|
9445
9579
|
defaultEncoding = "utf8",
|
|
9446
|
-
createDirsDefault = false
|
|
9580
|
+
createDirsDefault = false,
|
|
9581
|
+
policy: policyInput
|
|
9447
9582
|
} = config;
|
|
9583
|
+
const policy = resolveFileSystemPolicy(policyInput);
|
|
9448
9584
|
return [
|
|
9449
|
-
createFileReaderTool(defaultEncoding),
|
|
9450
|
-
createFileWriterTool(defaultEncoding, createDirsDefault),
|
|
9451
|
-
createFileAppendTool(defaultEncoding),
|
|
9452
|
-
createFileDeleteTool(),
|
|
9453
|
-
createFileExistsTool()
|
|
9585
|
+
createFileReaderTool(defaultEncoding, policy),
|
|
9586
|
+
createFileWriterTool(defaultEncoding, createDirsDefault, policy),
|
|
9587
|
+
createFileAppendTool(defaultEncoding, policy),
|
|
9588
|
+
createFileDeleteTool(policy),
|
|
9589
|
+
createFileExistsTool(policy)
|
|
9454
9590
|
];
|
|
9455
9591
|
}
|
|
9456
9592
|
var directoryListSchema = zod.z.object({
|
|
@@ -9473,21 +9609,23 @@ var fileSearchSchema = zod.z.object({
|
|
|
9473
9609
|
recursive: zod.z.boolean().default(true).describe("Search in subdirectories"),
|
|
9474
9610
|
caseSensitive: zod.z.boolean().default(false).describe("Case-sensitive pattern matching")
|
|
9475
9611
|
});
|
|
9476
|
-
function createDirectoryListTool(defaultRecursive = false, defaultIncludeDetails = false) {
|
|
9612
|
+
function createDirectoryListTool(defaultRecursive = false, defaultIncludeDetails = false, policy = DEFAULT_FILE_SYSTEM_POLICY) {
|
|
9477
9613
|
return core.toolBuilder().name("directory-list").description("List all files and directories in a directory. Can optionally include file details and filter by extension.").category(core.ToolCategory.FILE_SYSTEM).tags(["directory", "list", "files", "filesystem"]).schema(directoryListSchema).implementSafe(async (input) => {
|
|
9614
|
+
const safePath = await policy.resolvePath(input.path, "directory listing");
|
|
9615
|
+
const includeDetails = input.includeDetails ?? defaultIncludeDetails;
|
|
9478
9616
|
const listFiles = async (dir, recursive2) => {
|
|
9479
9617
|
const entries = await fs.promises.readdir(dir, { withFileTypes: true });
|
|
9480
9618
|
const files2 = [];
|
|
9481
9619
|
for (const entry of entries) {
|
|
9482
|
-
const fullPath =
|
|
9483
|
-
const relativePath =
|
|
9620
|
+
const fullPath = path__namespace.join(dir, entry.name);
|
|
9621
|
+
const relativePath = path__namespace.relative(safePath, fullPath);
|
|
9484
9622
|
if (input.extension && !entry.name.endsWith(input.extension)) {
|
|
9485
9623
|
if (!entry.isDirectory() || !recursive2) {
|
|
9486
9624
|
continue;
|
|
9487
9625
|
}
|
|
9488
9626
|
}
|
|
9489
|
-
if (
|
|
9490
|
-
const stats = await fs.promises.
|
|
9627
|
+
if (includeDetails) {
|
|
9628
|
+
const stats = await fs.promises.lstat(fullPath);
|
|
9491
9629
|
files2.push({
|
|
9492
9630
|
name: entry.name,
|
|
9493
9631
|
path: relativePath,
|
|
@@ -9513,7 +9651,7 @@ function createDirectoryListTool(defaultRecursive = false, defaultIncludeDetails
|
|
|
9513
9651
|
return files2;
|
|
9514
9652
|
};
|
|
9515
9653
|
const recursive = input.recursive ?? defaultRecursive;
|
|
9516
|
-
const files = await listFiles(
|
|
9654
|
+
const files = await listFiles(safePath, recursive);
|
|
9517
9655
|
return {
|
|
9518
9656
|
path: input.path,
|
|
9519
9657
|
files,
|
|
@@ -9521,37 +9659,40 @@ function createDirectoryListTool(defaultRecursive = false, defaultIncludeDetails
|
|
|
9521
9659
|
};
|
|
9522
9660
|
}).build();
|
|
9523
9661
|
}
|
|
9524
|
-
function createDirectoryCreateTool(defaultRecursive = true) {
|
|
9662
|
+
function createDirectoryCreateTool(defaultRecursive = true, policy = DEFAULT_FILE_SYSTEM_POLICY) {
|
|
9525
9663
|
return core.toolBuilder().name("directory-create").description("Create a new directory. Can optionally create parent directories if they don't exist.").category(core.ToolCategory.FILE_SYSTEM).tags(["directory", "create", "mkdir", "filesystem"]).schema(directoryCreateSchema).implementSafe(async (input) => {
|
|
9526
9664
|
const recursive = input.recursive ?? defaultRecursive;
|
|
9527
|
-
await
|
|
9665
|
+
const safePath = await policy.resolvePath(input.path, "directory creation");
|
|
9666
|
+
await fs.promises.mkdir(safePath, { recursive });
|
|
9528
9667
|
return {
|
|
9529
9668
|
path: input.path,
|
|
9530
9669
|
message: "Directory created successfully"
|
|
9531
9670
|
};
|
|
9532
9671
|
}).build();
|
|
9533
9672
|
}
|
|
9534
|
-
function createDirectoryDeleteTool(defaultRecursive = false) {
|
|
9673
|
+
function createDirectoryDeleteTool(defaultRecursive = false, policy = DEFAULT_FILE_SYSTEM_POLICY) {
|
|
9535
9674
|
return core.toolBuilder().name("directory-delete").description("Delete a directory. Can optionally delete non-empty directories recursively.").category(core.ToolCategory.FILE_SYSTEM).tags(["directory", "delete", "remove", "filesystem"]).schema(directoryDeleteSchema).implementSafe(async (input) => {
|
|
9536
9675
|
const recursive = input.recursive ?? defaultRecursive;
|
|
9537
|
-
await
|
|
9676
|
+
const safePath = await policy.resolveDeletePath(input.path, recursive);
|
|
9677
|
+
await fs.promises.rm(safePath, { recursive, force: false });
|
|
9538
9678
|
return {
|
|
9539
9679
|
path: input.path,
|
|
9540
9680
|
message: "Directory deleted successfully"
|
|
9541
9681
|
};
|
|
9542
9682
|
}).build();
|
|
9543
9683
|
}
|
|
9544
|
-
function createFileSearchTool(defaultRecursive = true, defaultCaseSensitive = false) {
|
|
9684
|
+
function createFileSearchTool(defaultRecursive = true, defaultCaseSensitive = false, policy = DEFAULT_FILE_SYSTEM_POLICY) {
|
|
9545
9685
|
return core.toolBuilder().name("file-search").description("Search for files by name pattern in a directory. Supports wildcards and recursive search.").category(core.ToolCategory.FILE_SYSTEM).tags(["file", "search", "find", "filesystem"]).schema(fileSearchSchema).implementSafe(async (input) => {
|
|
9546
9686
|
const recursive = input.recursive ?? defaultRecursive;
|
|
9547
9687
|
const caseSensitive = input.caseSensitive ?? defaultCaseSensitive;
|
|
9688
|
+
const safeDirectory = await policy.resolvePath(input.directory, "file search");
|
|
9548
9689
|
const searchFiles = async (dir) => {
|
|
9549
9690
|
const entries = await fs.promises.readdir(dir, { withFileTypes: true });
|
|
9550
9691
|
const matches2 = [];
|
|
9551
9692
|
const regexPattern = input.pattern.replace(/\./g, "\\.").replace(/\*/g, ".*");
|
|
9552
9693
|
const regex = new RegExp(`^${regexPattern}$`, caseSensitive ? "" : "i");
|
|
9553
9694
|
for (const entry of entries) {
|
|
9554
|
-
const fullPath =
|
|
9695
|
+
const fullPath = path__namespace.join(dir, entry.name);
|
|
9555
9696
|
if (entry.isFile() && regex.test(entry.name)) {
|
|
9556
9697
|
matches2.push(fullPath);
|
|
9557
9698
|
}
|
|
@@ -9562,7 +9703,7 @@ function createFileSearchTool(defaultRecursive = true, defaultCaseSensitive = fa
|
|
|
9562
9703
|
}
|
|
9563
9704
|
return matches2;
|
|
9564
9705
|
};
|
|
9565
|
-
const matches = await searchFiles(
|
|
9706
|
+
const matches = await searchFiles(safeDirectory);
|
|
9566
9707
|
return {
|
|
9567
9708
|
directory: input.directory,
|
|
9568
9709
|
pattern: input.pattern,
|
|
@@ -9587,15 +9728,17 @@ function createDirectoryOperationTools(config = {}) {
|
|
|
9587
9728
|
const {
|
|
9588
9729
|
defaultRecursive = false,
|
|
9589
9730
|
defaultIncludeDetails = false,
|
|
9590
|
-
defaultCaseSensitive = false
|
|
9731
|
+
defaultCaseSensitive = false,
|
|
9732
|
+
policy: policyInput
|
|
9591
9733
|
} = config;
|
|
9734
|
+
const policy = resolveFileSystemPolicy(policyInput);
|
|
9592
9735
|
return [
|
|
9593
|
-
createDirectoryListTool(defaultRecursive, defaultIncludeDetails),
|
|
9594
|
-
createDirectoryCreateTool(true),
|
|
9736
|
+
createDirectoryListTool(defaultRecursive, defaultIncludeDetails, policy),
|
|
9737
|
+
createDirectoryCreateTool(true, policy),
|
|
9595
9738
|
// Always default to true for create
|
|
9596
|
-
createDirectoryDeleteTool(false),
|
|
9739
|
+
createDirectoryDeleteTool(false, policy),
|
|
9597
9740
|
// Always default to false for delete (safety)
|
|
9598
|
-
createFileSearchTool(defaultRecursive, defaultCaseSensitive)
|
|
9741
|
+
createFileSearchTool(defaultRecursive, defaultCaseSensitive, policy)
|
|
9599
9742
|
];
|
|
9600
9743
|
}
|
|
9601
9744
|
var pathJoinSchema = zod.z.object({
|
|
@@ -9626,7 +9769,7 @@ var pathNormalizeSchema = zod.z.object({
|
|
|
9626
9769
|
});
|
|
9627
9770
|
function createPathJoinTool() {
|
|
9628
9771
|
return core.toolBuilder().name("path-join").description("Join multiple path segments into a single path. Handles platform-specific separators.").category(core.ToolCategory.FILE_SYSTEM).tags(["path", "join", "filesystem"]).schema(pathJoinSchema).implement(async (input) => {
|
|
9629
|
-
const joined =
|
|
9772
|
+
const joined = path__namespace.join(...input.segments);
|
|
9630
9773
|
return {
|
|
9631
9774
|
path: joined,
|
|
9632
9775
|
segments: input.segments
|
|
@@ -9635,59 +9778,59 @@ function createPathJoinTool() {
|
|
|
9635
9778
|
}
|
|
9636
9779
|
function createPathResolveTool() {
|
|
9637
9780
|
return core.toolBuilder().name("path-resolve").description("Resolve a sequence of paths into an absolute path. Resolves relative paths from the current working directory.").category(core.ToolCategory.FILE_SYSTEM).tags(["path", "resolve", "absolute", "filesystem"]).schema(pathResolveSchema).implement(async (input) => {
|
|
9638
|
-
const resolved =
|
|
9781
|
+
const resolved = path__namespace.resolve(...input.paths);
|
|
9639
9782
|
return {
|
|
9640
9783
|
path: resolved,
|
|
9641
|
-
isAbsolute:
|
|
9784
|
+
isAbsolute: path__namespace.isAbsolute(resolved)
|
|
9642
9785
|
};
|
|
9643
9786
|
}).build();
|
|
9644
9787
|
}
|
|
9645
9788
|
function createPathParseTool() {
|
|
9646
9789
|
return core.toolBuilder().name("path-parse").description("Parse a file path into its components (directory, filename, extension, etc.).").category(core.ToolCategory.FILE_SYSTEM).tags(["path", "parse", "filesystem"]).schema(pathParseSchema).implement(async (input) => {
|
|
9647
|
-
const parsed =
|
|
9790
|
+
const parsed = path__namespace.parse(input.path);
|
|
9648
9791
|
return {
|
|
9649
9792
|
root: parsed.root,
|
|
9650
9793
|
dir: parsed.dir,
|
|
9651
9794
|
base: parsed.base,
|
|
9652
9795
|
name: parsed.name,
|
|
9653
9796
|
ext: parsed.ext,
|
|
9654
|
-
isAbsolute:
|
|
9797
|
+
isAbsolute: path__namespace.isAbsolute(input.path)
|
|
9655
9798
|
};
|
|
9656
9799
|
}).build();
|
|
9657
9800
|
}
|
|
9658
9801
|
function createPathBasenameTool() {
|
|
9659
9802
|
return core.toolBuilder().name("path-basename").description("Get the last portion of a path (filename with extension). Optionally remove the extension.").category(core.ToolCategory.FILE_SYSTEM).tags(["path", "basename", "filename", "filesystem"]).schema(pathBasenameSchema).implement(async (input) => {
|
|
9660
|
-
const
|
|
9803
|
+
const basename5 = input.removeExtension ? path__namespace.basename(input.path, path__namespace.extname(input.path)) : path__namespace.basename(input.path);
|
|
9661
9804
|
return {
|
|
9662
|
-
basename:
|
|
9663
|
-
extension:
|
|
9805
|
+
basename: basename5,
|
|
9806
|
+
extension: path__namespace.extname(input.path)
|
|
9664
9807
|
};
|
|
9665
9808
|
}).build();
|
|
9666
9809
|
}
|
|
9667
9810
|
function createPathDirnameTool() {
|
|
9668
9811
|
return core.toolBuilder().name("path-dirname").description("Get the directory name of a path (everything except the last portion).").category(core.ToolCategory.FILE_SYSTEM).tags(["path", "dirname", "directory", "filesystem"]).schema(pathDirnameSchema).implement(async (input) => {
|
|
9669
|
-
const
|
|
9812
|
+
const dirname4 = path__namespace.dirname(input.path);
|
|
9670
9813
|
return {
|
|
9671
|
-
dirname:
|
|
9672
|
-
basename:
|
|
9814
|
+
dirname: dirname4,
|
|
9815
|
+
basename: path__namespace.basename(input.path)
|
|
9673
9816
|
};
|
|
9674
9817
|
}).build();
|
|
9675
9818
|
}
|
|
9676
9819
|
function createPathExtensionTool() {
|
|
9677
9820
|
return core.toolBuilder().name("path-extension").description('Get the file extension from a path (including the dot, e.g., ".txt").').category(core.ToolCategory.FILE_SYSTEM).tags(["path", "extension", "ext", "filesystem"]).schema(pathExtensionSchema).implement(async (input) => {
|
|
9678
|
-
const ext =
|
|
9821
|
+
const ext = path__namespace.extname(input.path);
|
|
9679
9822
|
return {
|
|
9680
9823
|
extension: ext,
|
|
9681
9824
|
hasExtension: ext.length > 0,
|
|
9682
|
-
filename:
|
|
9825
|
+
filename: path__namespace.basename(input.path, ext)
|
|
9683
9826
|
};
|
|
9684
9827
|
}).build();
|
|
9685
9828
|
}
|
|
9686
9829
|
function createPathRelativeTool() {
|
|
9687
9830
|
return core.toolBuilder().name("path-relative").description("Get the relative path from one path to another.").category(core.ToolCategory.FILE_SYSTEM).tags(["path", "relative", "filesystem"]).schema(pathRelativeSchema).implement(async (input) => {
|
|
9688
|
-
const
|
|
9831
|
+
const relative4 = path__namespace.relative(input.from, input.to);
|
|
9689
9832
|
return {
|
|
9690
|
-
relativePath:
|
|
9833
|
+
relativePath: relative4,
|
|
9691
9834
|
from: input.from,
|
|
9692
9835
|
to: input.to
|
|
9693
9836
|
};
|
|
@@ -9695,7 +9838,7 @@ function createPathRelativeTool() {
|
|
|
9695
9838
|
}
|
|
9696
9839
|
function createPathNormalizeTool() {
|
|
9697
9840
|
return core.toolBuilder().name("path-normalize").description('Normalize a path by resolving ".." and "." segments and removing duplicate separators.').category(core.ToolCategory.FILE_SYSTEM).tags(["path", "normalize", "filesystem"]).schema(pathNormalizeSchema).implement(async (input) => {
|
|
9698
|
-
const normalized =
|
|
9841
|
+
const normalized = path__namespace.normalize(input.path);
|
|
9699
9842
|
return {
|
|
9700
9843
|
normalized,
|
|
9701
9844
|
original: input.path
|
|
@@ -10604,6 +10747,7 @@ exports.CurrentDateTimeSchema = CurrentDateTimeSchema;
|
|
|
10604
10747
|
exports.DEFAULT_BATCH_SIZE = DEFAULT_BATCH_SIZE;
|
|
10605
10748
|
exports.DEFAULT_CHUNK_SIZE = DEFAULT_CHUNK_SIZE;
|
|
10606
10749
|
exports.DEFAULT_DESTINATION_POLICY = DEFAULT_DESTINATION_POLICY;
|
|
10750
|
+
exports.DEFAULT_FILE_SYSTEM_POLICY = DEFAULT_FILE_SYSTEM_POLICY;
|
|
10607
10751
|
exports.DEFAULT_RETRY_CONFIG = DEFAULT_RETRY_CONFIG2;
|
|
10608
10752
|
exports.DateArithmeticSchema = DateArithmeticSchema;
|
|
10609
10753
|
exports.DateComparisonSchema = DateComparisonSchema;
|
|
@@ -10613,6 +10757,8 @@ exports.DestinationPolicyError = DestinationPolicyError;
|
|
|
10613
10757
|
exports.DuckDuckGoProvider = DuckDuckGoProvider;
|
|
10614
10758
|
exports.EmailValidatorSchema = EmailValidatorSchema;
|
|
10615
10759
|
exports.EmbeddingManager = EmbeddingManager;
|
|
10760
|
+
exports.FileSystemPolicy = FileSystemPolicy;
|
|
10761
|
+
exports.FileSystemPolicyError = FileSystemPolicyError;
|
|
10616
10762
|
exports.HttpMethod = HttpMethod;
|
|
10617
10763
|
exports.IpValidatorSchema = IpValidatorSchema;
|
|
10618
10764
|
exports.MAX_BATCH_SIZE = MAX_BATCH_SIZE;
|
|
@@ -10686,6 +10832,7 @@ exports.createFileExistsTool = createFileExistsTool;
|
|
|
10686
10832
|
exports.createFileOperationTools = createFileOperationTools;
|
|
10687
10833
|
exports.createFileReaderTool = createFileReaderTool;
|
|
10688
10834
|
exports.createFileSearchTool = createFileSearchTool;
|
|
10835
|
+
exports.createFileSystemPolicy = createFileSystemPolicy;
|
|
10689
10836
|
exports.createFileWriterTool = createFileWriterTool;
|
|
10690
10837
|
exports.createHtmlParserTool = createHtmlParserTool;
|
|
10691
10838
|
exports.createHtmlParserTools = createHtmlParserTools;
|
|
@@ -10894,6 +11041,7 @@ exports.relationalQuery = relationalQuery;
|
|
|
10894
11041
|
exports.relationalSelect = relationalSelect;
|
|
10895
11042
|
exports.relationalUpdate = relationalUpdate;
|
|
10896
11043
|
exports.requestWithDestinationPolicy = requestWithDestinationPolicy;
|
|
11044
|
+
exports.resolveFileSystemPolicy = resolveFileSystemPolicy;
|
|
10897
11045
|
exports.retryWithBackoff = retryWithBackoff2;
|
|
10898
11046
|
exports.scraperTools = scraperTools;
|
|
10899
11047
|
exports.searchConfluence = searchConfluence;
|