跳转到主要内容

文件系统应用程序接口参考

AG-Kit 文件系统工具的完整应用程序接口文档,包含方法签名、输入/输出模式及实际使用示例。

应用程序接口概览

文件系统应用程序接口提供跨多种执行后端工作的工具,具有一致的接口和类型安全特性。

可用工具

独立工具

  • ReadTool - 支持编码方式读取文件内容
  • WriteTool - 支持目录创建的文件写入功能
  • EditTool - 对现有文件进行针对性编辑
  • GlobTool - 使用通配符模式查找文件
  • GrepTool - 使用正则表达式搜索文件内容
  • LsTool - 列出目录内容及详细信息

综合工具

  • StrReplaceEditor - 面向AI编码工作流的高级多操作文件编辑器

快速对比

特性本地模式内存模式沙盒模式
性能✅ 最高✅ 高⚠️ 网络开销
安全性⚠️ 完全访问✅ 隔离✅ 沙盒化
持久性✅ 永久❌ 临时✅ 会话级
测试支持⚠️ 副作用✅ 理想⚠️ 复杂配置

配置

本地文件操作器

import { LocalFileOperator } from '@ag-kit/tools/fs';

const context = {
  workingDirectory: process.cwd(),
  fsOperator: new LocalFileOperator()
};

内存文件操作器

import { InMemoryFileOperator } from '@ag-kit/tools/fs';
import { fs } from 'memfs';

const context = {
  workingDirectory: '/virtual',
  fsOperator: new InMemoryFileOperator(fs)
};

沙盒文件操作器

import { SandboxFileOperator } from '@ag-kit/tools/fs';

const context = {
  workingDirectory: '/home/user',
  fsOperator: new SandboxFileOperator({ sandbox })
};

事务支持

事务支持允许您将多个文件操作分组,并在需要时回滚。TransactionFileOperator 可包装任何基础操作器(本地、内存或沙盒)以提供原子操作。

基础用法

import { TransactionFileOperator, TransactionExecutor } from '@ag-kit/tools/fs/transaction';
import { LocalFileOperator } from '@ag-kit/tools/fs';

// 用事务支持包装任何基础操作器
const baseOperator = new LocalFileOperator(); // 或 InMemoryFileOperator, SandboxFileOperator
const transactionOperator = new TransactionFileOperator(baseOperator);

const context = {
  workingDirectory: process.cwd(),
  fsOperator: transactionOperator
};

手动事务控制

await transactionOperator.beginTransaction();

try {
  await writeTool.invoke({
    file_path: 'config.json',
    content: '{"version": "2.0"}'
  });
  
  await editTool.invoke({
    file_path: 'package.json',
    old_string: '"version": "1.0.0"',
    new_string: '"version": "2.0.0"'
  });
  
  await transactionOperator.commitTransaction();
} catch (error) {
  await transactionOperator.rollbackTransaction(); // 所有变更将被回滚
}

执行器模式(推荐)

import { TransactionExecutor, createTransactionExecutor, withTransaction } from '@ag-kit/tools/fs/transaction';

// 方法1:使用 TransactionExecutor 类
const executor = new TransactionExecutor(baseOperator);

const result = await executor.executeInTransaction(async (transactionOperator) => {
  // 所有操作自动具备事务性
  await writeTool.invoke({
    file_path: 'data.json',
    content: JSON.stringify(data)
  });

  await editTool.invoke({
    file_path: 'config.ts',
    old_string: 'DEBUG = false',
    new_string: 'DEBUG = true'
  });

  // 若此处抛出异常,所有操作将自动回滚
  if (!validateData(data)) {
    throw new Error('Validation failed');
  }

  return { filesModified: 2 };
});

// 方法2:使用便捷函数
const result2 = await withTransaction(baseOperator, async (transactionOperator) => {
  // 同上操作
  return { success: true };
});

// 方法3:使用构建器模式
const executor2 = createTransactionExecutor(baseOperator);
const builderResult = await executor2
  .writeFile('config.json', JSON.stringify(config))
  .mkdir('logs', { recursive: true })
  .custom(async (op) => {
    // 自定义操作
    await op.writeFile('logs/app.log', 'Application started');
  })
  .execute();

if (builderResult.success) {
  console.log('All operations completed successfully');
} else {
  console.error('Transaction failed:', builderResult.error);
}

实际示例

安全配置更新

async function updateConfig(newConfig: Config) {
  const executor = new TransactionExecutor(transactionOperator);
  
  return await executor.execute(async () => {
    // 更新主配置
    await writeTool.invoke({
      file_path: 'config.json',
      content: JSON.stringify(newConfig, null, 2)
    });
    
    // 更新 package.json 版本
    await editTool.invoke({
      file_path: 'package.json',
      old_string: `"version": "${oldConfig.version}"`,
      new_string: `"version": "${newConfig.version}"`
    });
    
    // 验证 - 若失败则回滚
    if (!isValidConfig(newConfig)) {
      throw new Error('Invalid configuration');
    }
    
    return { updated: true };
  });
}

批量文件处理

async function processFiles(files: string[]) {
  const executor = new TransactionExecutor(transactionOperator);
  
  return await executor.execute(async () => {
    for (const file of files) {
      const content = await readTool.invoke({ file_path: file });
      const processed = processContent(content);
      
      await writeTool.invoke({
        file_path: file,
        content: processed
      });
    }
    
    return { processed: files.length };
  });
}

独立工具用法

ReadTool

import { createReadTool } from '@ag-kit/tools/fs';

const readTool = createReadTool(context);

// 读取完整文件
const result = await readTool.invoke({
  file_path: 'src/config.json'
});

// 按行范围读取
const partialResult = await readTool.invoke({
  file_path: 'large-file.txt',
  start_line: 100,
  end_line: 200
});

WriteTool

import { createWriteTool } from '@ag-kit/tools/fs';

const writeTool = createWriteTool(context);

const result = await writeTool.invoke({
  file_path: 'output/data.json',
  content: JSON.stringify({ message: 'Hello World' }, null, 2),
  create_directories: true
});

EditTool

import { createEditTool } from '@ag-kit/tools/fs';

const editTool = createEditTool(context);

const result = await editTool.invoke({
  file_path: 'src/config.ts',
  old_string: 'const API_URL = "http://localhost"',
  new_string: 'const API_URL = "https://api.production.com"',
  expected_replacements: 1 // 可选:验证精确替换次数
});

GlobTool

import { createGlobTool } from '@ag-kit/tools/fs';

const globTool = createGlobTool(context);

const result = await globTool.invoke({
  pattern: '**/*.ts',
  exclude_patterns: ['node_modules/**', 'dist/**']
});

GrepTool

import { createGrepTool } from '@ag-kit/tools
});

// 创建新文件
await editor.invoke({
  command: 'create',
  path: 'new-file.ts',
  file_text: 'export const config = {};'
});

应用程序接口参考

通用接口

interface ExecutionContext {
  workingDirectory: string;
  fsOperator: BaseFileOperator;
  messageHandler?: any;
}

interface ToolResponse {
  success: boolean;
  error?: string;
  error_type?: 'validation' | 'security' | 'file_not_found' | 'permission' | 'execution';
  [key: string]: any;
}

文件系统工具包配置

/**
 * FilesystemToolkit的配置选项
 */
interface FilesystemToolkitConfig {
  /**
   * 文件编辑操作模式
   * - 'integrated': 使用str-replace-editor工具(单一工具处理读写编辑操作)
   * - 'atomic': 使用独立的读、写和编辑工具
   * - 'enhanced': 使用原子工具加批量操作的多编辑工具
   */
  mode: "integrated" | "atomic" | "enhanced";
}

interface FilesystemToolkitOptions extends IToolkitOptions {
  context: ExecutionContext;
  config?: FilesystemToolkitConfig;
}

class FilesystemToolkit extends BaseToolkit {
  constructor(options: FilesystemToolkitOptions);

  // 按类别获取工具
  getFileOperationTools(): BaseTool[];
  getUtilityTools(): BaseTool[];

  // 配置管理
  getConfig(): FilesystemToolkitConfig;
  switchMode(mode: "integrated" | "atomic"): void;

  // 统计信息
  getStats(): { mode: string };
}

// 使用示例
const toolkit = new FilesystemToolkit({
  context: {
    workingDirectory: process.cwd(),
    fsOperator: new LocalFileOperator()
  },
  config: {
    mode: "enhanced" // 使用原子工具+多编辑模式
  }
});

// 动态切换模式
toolkit.switchMode("integrated"); // 切换到str-replace-editor
toolkit.switchMode("enhanced");   // 切换回增强模式

工具参数

// ReadTool
interface ReadToolParams {
  file_path: string;
  start_line?: number;
  end_line?: number;
  encoding?: BufferEncoding;
}

// WriteTool
interface WriteToolParams {
  file_path: string;
  content: string;
  create_directories?: boolean;
  encoding?: BufferEncoding;
}

// EditTool
interface EditToolParams {
  file_path: string;
  old_string: string;
  new_string: string;
  expected_replacements?: number;
}

// GlobTool
interface GlobToolParams {
  pattern: string;
  exclude_patterns?: string[];
  include_directories?: boolean;
  max_results?: number;
}

// GrepTool
interface GrepToolParams {
  pattern: string;
  file_pattern?: string;
  case_sensitive?: boolean;
  max_results?: number;
  context_lines?: number;
}

// LsTool
interface LsToolParams {
  directory_path: string;
  recursive?: boolean;
  show_hidden?: boolean;
  include_stats?: boolean;
}

事务接口

// 基础操作器的事务包装器
class TransactionFileOperator extends BaseFileOperator {
  constructor(baseOperator: BaseFileOperator, operatorType?: EOperatorType);

  // 事务管理
  beginTransaction(): Promise<void>;
  commitTransaction(): Promise<void>;
  rollbackTransaction(): Promise<void>;
  resetTransactionState(): void;

  // 状态与配置
  isTransactionActive(): boolean;
  getTransactionOperations(): readonly TransactionOperation[];
  setConfig(config: Partial<ITransactionFileOperatorConfig>): void;
  getConfig(): ITransactionFileOperatorConfig;

  // 所有BaseFileOperator方法均可用
  // (readFile, writeFile, mkdir, unlink等)
}

// 事务执行器,便于操作管理
class TransactionExecutor {
  constructor(baseOperator: BaseFileOperator);

  // 获取底层事务操作器
  getOperator(): TransactionFileOperator;

  // 构建器模式方法
  writeFile(path: string, data: string | Buffer, options?: any): TransactionExecutor;
  mkdir(path: string, options?: any): TransactionExecutor;
  custom(operation: (op: TransactionFileOperator) => Promise<void>): TransactionExecutor;

  // 执行方法
  execute(): Promise<{ success: boolean; error?: Error }>;
  executeInTransaction<T>(operation: (operator: TransactionFileOperator) => Promise<T>): Promise<T>;
  createTransaction(): Promise<TransactionController>;
}

// 手动事务控制
class TransactionController {
  constructor(transactionOperator: TransactionFileOperator);

  getOperator(): TransactionFileOperator;
  commit(): Promise<void>;
  rollback(): Promise<void>;
  isTransactionCompleted(): boolean;
  getOperationHistory(): readonly TransactionOperation[];
}

// 配置接口
interface ITransactionFileOperatorConfig {
  batchSize: number;
  maxConcurrency: number;
  enableLazyLoading: boolean;
}

enum EOperatorType {
  LOCAL = "local",
  MEMORY = "memory",
  SANDBOX = "sandbox"
}

interface TransactionOperation {
  type: "write" | "mkdir" | "unlink" | "rmdir" | "rename";
  path: string;
  oldPath?: string;
  timestamp: number;
}

interface FileState {
  exists: boolean;
  isDirectory: boolean;
  contentLoader?: () => Promise<Buffer>;
}

// 工具函数
function createTransactionExecutor(baseOperator: BaseFileOperator): TransactionExecutor;
function withTransaction<T>(
  baseOperator: BaseFileOperator,
  operation: (operator: TransactionFileOperator) => Promise<T>
): Promise<T>;

高级用法

使用MultiEditTool进行多文件重构

import { createMultieditTool, createGrepTool } from '@ag-kit/tools/fs';

const multieditTool = createMultieditTool(context);
const grepTool = createGrepTool(context);

// 查找所有需要重构的文件
const searchResult = await grepTool.invoke({
  pattern: 'oldApiFunction|OLD_CONSTANT',
  file_pattern: '**/*.{ts,js}',
  case_sensitive: false
});

// 对每个文件应用一致的重构
for (const match of searchResult.data.matches) {
  const refactorResult = await multieditTool.invoke({
    file_path: match.file,
    edits: [
      {
        old_string: 'oldApiFunction',
        new_string: 'newApiFunction',
        expected_replacements: 1
      },
      {
        old_string: 'OLD_CONSTANT',
        new_string: 'NEW_CONSTANT',
        expected_replacements: 1
      },
      {
        old_string: '// TODO: Update this',
        new_string: '// DONE: Updated to new API',
        expected_replacements: 1
      }
    ]
  });

  if (refactorResult.success) {
    console.log(`✓ 已重构 ${match.file}: ${refactorResult.data.total_replacements} 处变更`);
  } else {
    console.log(`✗ 重构 ${match.file} 失败`);
  }
}

事务性文件操作

import { withTransaction, TransactionExecutor } from '@ag-kit/tools/fs/transaction';
import { LocalFileOperator } from '@ag-kit/tools/fs';

const baseOperator = new LocalFileOperator();

// 方法1:简单事务包装器
const result = await withTransaction(baseOperator, async (transactionOp) => {
  // 原子化创建多个关联文件
  await transactionOp.mkdir('project/src', { recursive: true });
  await transactionOp.mkdir('project/tests', { recursive: true });

  await transactionOp.writeFile('project/package.json', JSON.stringify({
    name: 'my-project',
    version: '1.0.0'
  }, null, 2));

  await transactionOp.writeFile('project/src/index.ts', 'export const main = () => console.log("Hello");');
  await transactionOp.writeFile('project/tests/index.test.ts', 'import { main } from "../src/index";');

  // 若任何操作失败,所有变更将被回滚
  return { projectCreated: true };
});

// 方法2:手动事务控制
const executor = new TransactionExecutor(baseOperator);
const transaction = await executor.createTransaction();

try {
  const operator = transaction.getOperator();

  // 执行操作
  await operator.writeFile('config.json', JSON.stringify(config));
  await operator.writeFile('backup.json', JSON.stringify(backup));

  // 提交前验证
  if (await validateConfiguration(config)) {
    await transaction.commit();
    console.log('配置更新成功');
  } else
```typescript
        break;
      default:
        console.log('未知错误:', result.error);
    }
  }
} catch (error) {
  console.error('工具执行失败:', error);
}

安全特性

路径验证

所有工具自动验证路径以防止目录遍历攻击:
// ✅ 安全 - 工作区内的相对路径
{ file_path: 'src/config.ts' }

// ❌ 阻止 - 目录遍历
{ file_path: '../../../etc/passwd' }

生产环境建议

  • 使用沙盒文件操作器处理不可信代码
  • 使用内存文件操作器进行测试
  • 仅限可信环境使用本地文件操作器

示例

开发工作流

// 读取配置
const config = await readTool.invoke({ file_path: 'config.json' });

// 更新配置
await editTool.invoke({
  file_path: 'config.json',
  old_string: '"debug": false',
  new_string: '"debug": true'
});

// 查找所有TypeScript文件
const tsFiles = await globTool.invoke({
  pattern: '**/*.ts',
  exclude_patterns: ['node_modules/**']
});

// 搜索TODOs
const todos = await grepTool.invoke({
  pattern: 'TODO|FIXME',
  file_pattern: '**/*.{ts,js}'
});

安全配置迁移

import { withTransaction } from '@ag-kit/tools/fs/transaction';
import { createMultieditTool, createReadTool, createWriteTool, createGrepTool } from '@ag-kit/tools/fs';

async function migrateConfiguration(oldConfigPath: string, newConfigPath: string) {
  const readTool = createReadTool(context);
  const writeTool = createWriteTool(context);
  const multieditTool = createMultieditTool(context);
  const grepTool = createGrepTool(context);

  return await withTransaction(context.fsOperator, async (transactionOp) => {
    // 读取旧配置
    const oldConfig = await readTool.invoke({ file_path: oldConfigPath });
    const configData = JSON.parse(oldConfig.data.content);

    // 转换配置结构
    const newConfigData = {
      version: '2.0',
      settings: {
        api: {
          baseUrl: configData.apiUrl,
          timeout: configData.timeout || 5000
        },
        features: {
          debug: configData.debug || false,
          logging: configData.enableLogging || true
        }
      }
    };

    // 写入新配置
    await writeTool.invoke({
      file_path: newConfigPath,
      content: JSON.stringify(newConfigData, null, 2),
      create_directories: true
    });

    // 更新所有引用旧配置的文件
    const configReferences = await grepTool.invoke({
      pattern: oldConfigPath.replace(/\./g, '\\.'),
      file_pattern: '**/*.{ts,js,json}'
    });

    for (const ref of configReferences.data.matches) {
      await multieditTool.invoke({
        file_path: ref.file,
        edits: [
          {
            old_string: oldConfigPath,
            new_string: newConfigPath,
            expected_replacements: 1
          }
        ]
      });
    }

    // 归档旧配置
    await transactionOp.rename(oldConfigPath, `${oldConfigPath}.backup`);

    return {
      migrated: true,
      newConfigPath,
      referencesUpdated: configReferences.data.matches.length
    };
  });
}

// 使用示例
const migrationResult = await migrateConfiguration('old-config.json', 'config/app.json');
if (migrationResult.migrated) {
  console.log(`配置已成功迁移至 ${migrationResult.newConfigPath}`);
  console.log(`更新了 ${migrationResult.referencesUpdated} 处文件引用`);
}

带错误恢复的批量文件处理

import { TransactionExecutor } from '@ag-kit/tools/fs/transaction';

async function processFilesWithRecovery(filePatterns: string[]) {
  const executor = new TransactionExecutor(context.fsOperator);
  const results = [];

  for (const pattern of filePatterns) {
    const transaction = await executor.createTransaction();

    try {
      const operator = transaction.getOperator();

      // 查找匹配模式的文件
      const files = await globTool.invoke({ pattern });

      // 处理每个文件
      for (const file of files.data.matches) {
        const content = await readTool.invoke({ file_path: file.path });

        // 应用转换
        const processedContent = await processFileContent(content.data.content);

        // 写回处理后的内容
        await operator.writeFile(file.path, processedContent);
      }

      // 所有文件处理成功后提交
      await transaction.commit();
      results.push({ pattern, success: true, filesProcessed: files.data.matches.length });

    } catch (error) {
      // 出错时回滚
      await transaction.rollback();
      results.push({ pattern, success: false, error: error.message });
    }
  }

  return results;
}

async function processFileContent(content: string): Promise<string> {
  // 示例:移除console.log语句并添加适当日志
  return content
    .replace(/console\.log\([^)]+\);?\n?/g, '')
    .replace(/\/\/ TODO:/g, '// DONE:')
    .replace(/var /g, 'const ');
}

核心特性摘要

本版新增

MultiEditTool

  • 用途:对单个文件执行多次顺序编辑
  • 优势:原子批量操作、一致的错误处理、详细结果
  • 使用场景:配置更新、代码重构、批量替换

事务支持

  • 用途:分组多个文件操作并支持回滚
  • 优势:数据一致性、错误恢复、原子操作
  • 策略:本地(文件备份)、内存(快照)、沙盒(内容追踪)

增强型工具包模式

  • 用途:结合原子工具与多编辑能力
  • 优势:适应不同使用场景的灵活性、最优工具选择
  • 配置:在FilesystemToolkit中设置mode: "enhanced"

最佳实践

  1. 使用MultiEditTool处理同一文件的多次变更
  2. 使用事务确保操作要么全部成功要么全部回滚
  3. 使用增强模式当需要同时进行原子和批量操作时
  4. 验证expected_replacements捕获意外变更
  5. 优雅处理错误配合适当的回滚机制

迁移指南

从EditTool迁移到MultiEditTool

// 之前:多次EditTool调用
await editTool.invoke({ file_path: 'config.ts', old_string: 'A', new_string: 'B' });
await editTool.invoke({ file_path: 'config.ts', old_string: 'C', new_string: 'D' });

// 之后:单次MultiEditTool调用
await multieditTool.invoke({
  file_path: 'config.ts',
  edits: [
    { old_string: 'A', new_string: 'B' },
    { old_string: 'C', new_string: 'D' }
  ]
});

添加事务支持

// 之前:直接操作
await writeTool.invoke({ file_path: 'file1.txt', content: 'data1' });
await writeTool.invoke({ file_path: 'file2.txt', content: 'data2' });

// 之后:事务操作
await withTransaction(baseOperator, async (transactionOp) => {
  await transactionOp.writeFile('file1.txt', 'data1');
  await transactionOp.writeFile('file2.txt', 'data2');
  // 要么全部成功,要么全部回滚
});