feat(tools): add file read/write/edit/list builtin tools

This commit is contained in:
William Valentin
2026-02-05 17:39:20 -08:00
parent b913941e4f
commit 32dd3ad728
7 changed files with 391 additions and 0 deletions
+48
View File
@@ -0,0 +1,48 @@
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) };
}
},
};