batch_operations
Perform batch file operations including rename, move, copy, and delete, with support for dry-run and continue-on-error modes.
Instructions
Execute multiple file operations in batch
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| operations | Yes | ||
| dryRun | No | ||
| continueOnError | No |
Implementation Reference
- Primary handler — the executeCommand method that runs the batch_operations tool logic via BatchService.executeBatch().
protected async executeCommand(context: CommandContext): Promise<CommandResult> { try { const batchService = context.container.getService<BatchService>('batchService'); const result = await batchService.executeBatch( context.args.operations, { dryRun: context.args.dryRun, continueOnError: context.args.continueOnError } ); return this.formatResult(JSON.stringify({ message: context.args.dryRun ? 'Dry run completed' : 'Batch operations completed', totalOperations: result.totalOperations, successful: result.successful, failed: result.failed, operations: result.operations, errors: result.errors }, null, 2)); } catch (error) { return this.formatError(error); } } - Input schema for batch_operations defines operations array (op: rename/move/copy/delete, files with from/to/pattern/replacement), dryRun and continueOnError options.
readonly inputSchema = { type: 'object' as const, properties: { operations: { type: 'array' as const, items: { type: 'object' as const, properties: { op: { type: 'string' as const, enum: ['rename', 'move', 'copy', 'delete'] }, files: { type: 'array' as const, items: { type: 'object' as const, properties: { from: { type: 'string' as const }, to: { type: 'string' as const }, pattern: { type: 'string' as const }, replacement: { type: 'string' as const } }, required: ['from'] } } }, required: ['op', 'files'] } }, dryRun: { type: 'boolean' as const, default: false }, continueOnError: { type: 'boolean' as const, default: true } }, required: ['operations'] }; - Core execution engine — BatchService.executeBatch() iterates operations, expands glob patterns, handles dry-run, pattern-based renaming, and executes rename/move/copy/delete.
export class BatchService { async executeBatch( operations: BatchOperation[], options?: { dryRun?: boolean; continueOnError?: boolean; } ): Promise<BatchResult> { const result: BatchResult = { totalOperations: 0, successful: 0, failed: 0, skipped: 0, operations: [], errors: [] }; for (const batch of operations) { for (const fileOp of batch.files) { result.totalOperations++; try { // Expand glob patterns const files = await glob(fileOp.from) as string[]; if (files.length === 0) { result.skipped++; result.operations.push({ operation: batch.op, from: fileOp.from, status: 'skipped', error: 'No files matched pattern' }); continue; } for (const file of files) { try { let targetPath = fileOp.to; // Handle pattern-based renaming if (batch.op === 'rename' && fileOp.pattern && fileOp.replacement) { const basename = path.basename(file); const newName = basename.replace(new RegExp(fileOp.pattern), fileOp.replacement); targetPath = path.join(path.dirname(file), newName); } if (!options?.dryRun) { await this.executeOperation(batch.op, file, targetPath); } result.successful++; result.operations.push({ operation: batch.op, from: file, to: targetPath, status: 'success' }); } catch (error) { result.failed++; const errorMsg = error instanceof Error ? error.message : String(error); result.errors.push(errorMsg); result.operations.push({ operation: batch.op, from: file, to: fileOp.to, status: 'failed', error: errorMsg }); if (!options?.continueOnError) { throw error; } } } } catch (error) { if (!options?.continueOnError) { throw error; } } } } return result; } private async executeOperation(op: string, from: string, to?: string): Promise<void> { switch (op) { case 'rename': case 'move': if (!to) throw new Error('Target path required for move/rename operation'); await fs.rename(from, to); break; case 'copy': if (!to) throw new Error('Target path required for copy operation'); await fs.copyFile(from, to); break; case 'delete': const stats = await fs.stat(from); if (stats.isDirectory()) { await fs.rmdir(from, { recursive: true }); } else { await fs.unlink(from); } break; default: throw new Error(`Unknown operation: ${op}`); } } } - src/commands/registry/CommandLoader.ts:86-156 (registration)Registration in CommandLoader — imports BatchOperationsCommand and registers it at line 156.
const batchModule = await import('../implementations/batch/index.js'); if (this.enableDebugLogs) { console.log('Batch commands available:', Object.keys(batchModule)); } const { BatchOperationsCommand, TransactionCommand } = batchModule; // Monitoring commands const monitoringModule = await import('../implementations/monitoring/index.js'); if (this.enableDebugLogs) { console.log('Monitoring commands available:', Object.keys(monitoringModule)); } const { FileWatcherCommand } = monitoringModule; // Git commands const gitModule = await import('../implementations/git/index.js'); if (this.enableDebugLogs) { console.log('Git commands available:', Object.keys(gitModule)); } const { GitInitCommand, GitAddCommand, GitCommitCommand, GitPushCommand, GitPullCommand, GitBranchCommand, GitCheckoutCommand, GitLogCommand, GitCloneCommand, GitHubCreatePRCommand, GitStatusCommand } = gitModule; // Search commands const searchModule = await import('../implementations/search/index.js'); if (this.enableDebugLogs) { console.log('Search commands available:', Object.keys(searchModule)); } const { SearchFilesCommand, SearchContentCommand, FuzzySearchCommand, SemanticSearchCommand } = searchModule; // Code commands const codeModule = await import('../implementations/code/index.js'); if (this.enableDebugLogs) { console.log('Code commands available:', Object.keys(codeModule)); } const { AnalyzeCodeCommand, ModifyCodeCommand, SuggestRefactoringCommand, FormatCodeCommand } = codeModule; // Register git commands this.registry.register(new GitInitCommand()); this.registry.register(new GitAddCommand()); this.registry.register(new GitCommitCommand()); this.registry.register(new GitPushCommand()); this.registry.register(new GitPullCommand()); this.registry.register(new GitBranchCommand()); this.registry.register(new GitCheckoutCommand()); this.registry.register(new GitLogCommand()); this.registry.register(new GitCloneCommand()); this.registry.register(new GitHubCreatePRCommand()); this.registry.register(new GitStatusCommand()); // Register search commands this.registry.register(new SearchFilesCommand()); this.registry.register(new SearchContentCommand()); this.registry.register(new FuzzySearchCommand()); this.registry.register(new SemanticSearchCommand()); // Register code commands this.registry.register(new AnalyzeCodeCommand()); this.registry.register(new ModifyCodeCommand()); this.registry.register(new SuggestRefactoringCommand()); this.registry.register(new FormatCodeCommand()); // Register utils commands this.registry.register(new DiffFilesCommand()); this.registry.register(new CompressFilesCommand()); this.registry.register(new ExtractArchiveCommand()); this.registry.register(new GetFileMetadataCommand()); this.registry.register(new ChangePermissionsCommand()); // Register batch commands this.registry.register(new BatchOperationsCommand()); - src/core/commands/index.ts:102-234 (registration)Alternative registration in core/commands/index.ts — imports BatchOperationsCommand at line 103 and registers at line 234.
import { BatchOperationsCommand } from './batch/BatchCommands.js'; // Refactoring commands import { SuggestRefactoringCommand, AutoFormatProjectCommand, AnalyzeCodeQualityCommand } from './refactoring/RefactoringCommands.js'; // Cloud commands import { SyncWithCloudCommand } from './cloud/CloudCommands.js'; // Security commands import { ChangePermissionsCommand, EncryptFileCommand, DecryptFileCommand, ScanSecretsCommand, SecurityAuditCommand } from './security/SecurityCommands.js'; // Metadata commands import { AnalyzeProjectCommand, GetFileMetadataCommand, GetDirectoryTreeCommand, CompareFilesCommand, FindDuplicateFilesCommand, CreateSymlinkCommand, DiffFilesCommand } from './metadata/MetadataCommands.js'; /** * 모든 명령어를 등록한 CommandRegistry를 생성합니다. */ export function createCommandRegistry(): CommandRegistry { const registry = new CommandRegistry(); // File commands registry.registerMany([ new ReadFileCommand(), new ReadFilesCommand(), new WriteFileCommand(), new UpdateFileCommand(), new MoveFileCommand() ]); // Directory commands registry.registerMany([ new CreateDirectoryCommand(), new RemoveDirectoryCommand(), new ListDirectoryCommand(), new CopyDirectoryCommand(), new MoveDirectoryCommand() ]); // Search commands registry.registerMany([ new SearchFilesCommand(), new SearchContentCommand(), new SearchByDateCommand(), new SearchBySizeCommand(), new FuzzySearchCommand(), new SemanticSearchCommand() ]); // Git commands registry.registerMany([ new GitStatusCommand(), new GitCommitCommand(), new GitInitCommand(), new GitAddCommand(), new GitPushCommand(), new GitPullCommand(), new GitBranchCommand(), new GitLogCommand(), new GitHubCreatePRCommand(), new GitCloneCommand() ]); // Git Advanced commands registry.registerMany([ new GitRemoteCommand(), new GitStashCommand(), new GitTagCommand(), new GitMergeCommand(), new GitRebaseCommand(), new GitDiffCommand(), new GitResetCommand(), new GitCherryPickCommand() ]); // Utility commands registry.registerMany([ new TouchCommand(), new CopyFileCommand(), new DeleteFilesCommand(), new GetWorkingDirectoryCommand(), new DiskUsageCommand(), new WatchDirectoryCommand() ]); // Code Analysis commands registry.registerMany([ new AnalyzeCodeCommand(), new ModifyCodeCommand() ]); // Transaction commands registry.register(new CreateTransactionCommand()); // File Watcher commands registry.registerMany([ new StartWatchingCommand(), new StopWatchingCommand(), new GetWatcherStatsCommand() ]); // Archive commands registry.registerMany([ new CompressFilesCommand(), new ExtractArchiveCommand() ]); // System commands registry.register(new GetFileSystemStatsCommand()); // Batch commands registry.register(new BatchOperationsCommand());