FileEditTool 是 Claude Code 中最核心的工具之一,实现了基于 search-and-replace 的文件编辑机制。
设计理念
为什么不用 diff/patch?
传统的 diff/patch 方式存在问题:
AI 难以生成正确的 diff 格式
行号容易过时
对空白字符敏感
search-and-replace 更适合 AI:
语义化的编辑描述
不依赖行号
更容易理解和调试
核心实现
输入 Schema
constFileEditInputSchema=z.object({path:z.string(),oldStr:z.string(),newStr:z.string(),}).refine(data=>data.oldStr!==data.newStr,{message:'oldStr and newStr must be different'});
async function checkStaleness(path: string, originalContent: string) {
const currentContent = await fs.readFile(path, 'utf-8');
if (currentContent !== originalContent) {
throw new Error(
'File has been modified since it was read. Please re-read the file.'
);
}
}
function countOccurrences(content: string, search: string): number {
let count = 0;
let pos = 0;
while ((pos = content.indexOf(search, pos)) !== -1) {
count++;
pos += search.length;
}
return count;
}
// 修改函数实现
await fileEdit.execute({
path: 'src/calculator.ts',
oldStr: `function add(a, b) {
return a + b;
}`,
newStr: `function add(a, b) {
// 添加类型检查
if (typeof a !== 'number' || typeof b !== 'number') {
throw new Error('Arguments must be numbers');
}
return a + b;
}`,
}, context);
try {
await fileEdit.execute(input, context);
} catch (error) {
if (error.code === 'MULTIPLE_MATCHES') {
// 提示 AI 增加上下文
return {
success: false,
error: 'Multiple matches found. Please include more surrounding context in oldStr.',
};
} else if (error.code === 'STALE_CONTENT') {
// 提示 AI 重新读取
return {
success: false,
error: 'File has been modified. Please re-read the file and try again.',
};
}
throw error;
}