import { readFileSync, writeFileSync } from 'fs'; import type { Tool, ToolResult } from '../types.js'; interface FileEditArgs { path: string; old_string: string; new_string: string; replace_all?: boolean; } export const fileEditTool: Tool = { name: 'file.edit', description: 'Edit a file by replacing an exact string match. Fails if old_string is not found or matches multiple times (unless replace_all is true).', inputSchema: { type: 'object', properties: { path: { type: 'string', description: 'Absolute path to the file' }, old_string: { type: 'string', description: 'Exact string to find' }, new_string: { type: 'string', description: 'Replacement string' }, replace_all: { type: 'boolean', description: 'Replace all occurrences (default false)' }, }, required: ['path', 'old_string', 'new_string'], }, execute: async (rawArgs: unknown): Promise => { const args = rawArgs as FileEditArgs; try { const content = readFileSync(args.path, 'utf-8'); if (!content.includes(args.old_string)) { return { success: false, output: '', error: `old_string not found in ${args.path}` }; } const count = content.split(args.old_string).length - 1; if (count > 1 && !args.replace_all) { return { success: false, output: '', error: `old_string found multiple times (${count}). Use replace_all or provide more context.` }; } const newContent = args.replace_all ? content.replaceAll(args.old_string, args.new_string) : content.replace(args.old_string, args.new_string); writeFileSync(args.path, newContent, 'utf-8'); return { success: true, output: `Edited ${args.path} (${count} replacement${count > 1 ? 's' : ''})` }; } catch (error) { return { success: false, output: '', error: error instanceof Error ? error.message : String(error) }; } }, };