diff --git a/packages/agent/src/tools/io/textEditor.test.ts b/packages/agent/src/tools/io/textEditor.test.ts index 4b7f974..0ebe83d 100644 --- a/packages/agent/src/tools/io/textEditor.test.ts +++ b/packages/agent/src/tools/io/textEditor.test.ts @@ -303,4 +303,94 @@ describe('textEditor', () => { ); }).rejects.toThrow(/Found 2 occurrences/); }); + + it('should overwrite an existing file with create command', async () => { + const initialContent = 'Initial content'; + const newContent = 'New content that overwrites the file'; + const testPath = join(testDir, `${randomUUID()}.txt`); + + // Create initial file + await textEditorTool.execute( + { + command: 'create', + path: testPath, + file_text: initialContent, + description: 'test', + }, + toolContext, + ); + + // Verify initial content + let content = await readFile(testPath, 'utf8'); + expect(content).toBe(initialContent); + + // Overwrite the file using create command + const result = await textEditorTool.execute( + { + command: 'create', + path: testPath, + file_text: newContent, + description: 'test', + }, + toolContext, + ); + + // Verify return value + expect(result.success).toBe(true); + expect(result.message).toContain('File overwritten'); + + // Verify content has been updated + content = await readFile(testPath, 'utf8'); + expect(content).toBe(newContent); + }); + + it('should be able to undo file overwrite', async () => { + const initialContent = 'Initial content that will be restored'; + const overwrittenContent = 'This content will be undone'; + const testPath = join(testDir, `${randomUUID()}.txt`); + + // Create initial file + await textEditorTool.execute( + { + command: 'create', + path: testPath, + file_text: initialContent, + description: 'test', + }, + toolContext, + ); + + // Overwrite the file + await textEditorTool.execute( + { + command: 'create', + path: testPath, + file_text: overwrittenContent, + description: 'test', + }, + toolContext, + ); + + // Verify overwritten content + let content = await readFile(testPath, 'utf8'); + expect(content).toBe(overwrittenContent); + + // Undo the overwrite + const result = await textEditorTool.execute( + { + command: 'undo_edit', + path: testPath, + description: 'test', + }, + toolContext, + ); + + // Verify return value + expect(result.success).toBe(true); + expect(result.message).toContain('Successfully reverted'); + + // Verify content is back to initial + content = await readFile(testPath, 'utf8'); + expect(content).toBe(initialContent); + }); }); diff --git a/packages/agent/src/tools/io/textEditor.ts b/packages/agent/src/tools/io/textEditor.ts index ce31909..1147468 100644 --- a/packages/agent/src/tools/io/textEditor.ts +++ b/packages/agent/src/tools/io/textEditor.ts @@ -160,13 +160,6 @@ export const textEditorTool: Tool = { } case 'create': { - // Check if file already exists - if (fsSync.existsSync(absolutePath)) { - throw new Error( - `File already exists: ${filePath}. Use str_replace to modify it.`, - ); - } - if (!file_text) { throw new Error('file_text parameter is required for create command'); } @@ -174,15 +167,29 @@ export const textEditorTool: Tool = { // Create parent directories if they don't exist await fs.mkdir(path.dirname(absolutePath), { recursive: true }); - // Create the file - await fs.writeFile(absolutePath, file_text, 'utf8'); + // Check if file already exists + const fileExists = fsSync.existsSync(absolutePath); - // Store initial state for undo - fileStateHistory[absolutePath] = [file_text]; + if (fileExists) { + // Save current state for undo if file exists + const currentContent = await fs.readFile(absolutePath, 'utf8'); + if (!fileStateHistory[absolutePath]) { + fileStateHistory[absolutePath] = []; + } + fileStateHistory[absolutePath].push(currentContent); + } else { + // Initialize history for new files + fileStateHistory[absolutePath] = []; + } + + // Create or overwrite the file + await fs.writeFile(absolutePath, file_text, 'utf8'); return { success: true, - message: `File created: ${filePath}`, + message: fileExists + ? `File overwritten: ${filePath}` + : `File created: ${filePath}`, }; }