@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 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 path7 = require('path');
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 path7__namespace = /*#__PURE__*/_interopNamespace(path7);
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((resolve2) => setTimeout(resolve2, ms));
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, path12) {
2211
- return path12.split(".").reduce((current, key) => {
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((resolve2) => setTimeout(resolve2, ms));
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(path12) {
3500
+ function formatPath(path13) {
3501
3501
  return {
3502
- start: formatNode(path12.start),
3503
- end: formatNode(path12.end),
3504
- segments: path12.segments.map((segment) => ({
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: path12.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((resolve2) => {
5687
- setTimeout(resolve2, ms);
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((resolve2, reject) => {
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
- resolve2(result);
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
- function createFileReaderTool(defaultEncoding = "utf8") {
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 content = await fs.promises.readFile(input.path, encoding);
9362
- const stats = await fs.promises.stat(input.path);
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 = path7__namespace.dirname(input.path);
9501
+ const dir = path__namespace.dirname(safePath);
9377
9502
  await fs.promises.mkdir(dir, { recursive: true });
9378
9503
  }
9379
- await fs.promises.writeFile(input.path, input.content, encoding);
9380
- const stats = await fs.promises.stat(input.path);
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 fs.promises.appendFile(input.path, input.content, encoding);
9392
- const stats = await fs.promises.stat(input.path);
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 fs.promises.unlink(input.path);
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 fs.promises.access(input.path);
9412
- const stats = await fs.promises.stat(input.path);
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 = path7__namespace.join(dir, entry.name);
9483
- const relativePath = path7__namespace.relative(input.path, fullPath);
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 (input.includeDetails) {
9490
- const stats = await fs.promises.stat(fullPath);
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(input.path, recursive);
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 fs.promises.mkdir(input.path, { recursive });
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 fs.promises.rm(input.path, { recursive, force: false });
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 = path7__namespace.join(dir, entry.name);
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(input.directory);
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 = path7__namespace.join(...input.segments);
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 = path7__namespace.resolve(...input.paths);
9781
+ const resolved = path__namespace.resolve(...input.paths);
9639
9782
  return {
9640
9783
  path: resolved,
9641
- isAbsolute: path7__namespace.isAbsolute(resolved)
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 = path7__namespace.parse(input.path);
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: path7__namespace.isAbsolute(input.path)
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 basename4 = input.removeExtension ? path7__namespace.basename(input.path, path7__namespace.extname(input.path)) : path7__namespace.basename(input.path);
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: basename4,
9663
- extension: path7__namespace.extname(input.path)
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 dirname3 = path7__namespace.dirname(input.path);
9812
+ const dirname4 = path__namespace.dirname(input.path);
9670
9813
  return {
9671
- dirname: dirname3,
9672
- basename: path7__namespace.basename(input.path)
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 = path7__namespace.extname(input.path);
9821
+ const ext = path__namespace.extname(input.path);
9679
9822
  return {
9680
9823
  extension: ext,
9681
9824
  hasExtension: ext.length > 0,
9682
- filename: path7__namespace.basename(input.path, ext)
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 relative3 = path7__namespace.relative(input.from, input.to);
9831
+ const relative4 = path__namespace.relative(input.from, input.to);
9689
9832
  return {
9690
- relativePath: relative3,
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 = path7__namespace.normalize(input.path);
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;