49 lines
1.9 KiB
TypeScript
49 lines
1.9 KiB
TypeScript
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<ToolResult> => {
|
|
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) };
|
|
}
|
|
},
|
|
};
|