From f624192e7681e0ddc29647b4c6102b5cfb9aaa7b Mon Sep 17 00:00:00 2001 From: Shivaditya Shivganesh Date: Sat, 11 Jan 2025 05:57:20 +0530 Subject: [PATCH] fix: git operation fails log --- src/handlers/front-controller.ts | 3 + src/tools/write-file/index.ts | 39 ++++++--- tests/write-file.test.ts | 133 +++++++++++++++++++++++++++++++ 3 files changed, 164 insertions(+), 11 deletions(-) create mode 100644 tests/write-file.test.ts diff --git a/src/handlers/front-controller.ts b/src/handlers/front-controller.ts index 0745a494..0fe14e66 100644 --- a/src/handlers/front-controller.ts +++ b/src/handlers/front-controller.ts @@ -72,6 +72,9 @@ export async function delegate(context: Context) { return; } + console.log(JSON.stringify(readResult, null, 2)); + logger.info(`Read content: ${readResult.data?.content}`); + const writeResult = await writeFile.execute({ filename: workingDir + "/output.txt", content: readResult.data?.content || "", diff --git a/src/tools/write-file/index.ts b/src/tools/write-file/index.ts index db85b41f..71a8f9b1 100644 --- a/src/tools/write-file/index.ts +++ b/src/tools/write-file/index.ts @@ -49,15 +49,18 @@ export class WriteFile implements Tool { async execute(args: Record): Promise> { try { - const path = args.filename as string; - const diff = args.content as string; + const filePath = args.filename as string; + const content = args.content as string; - if (!path || !diff) { + if (!filePath || !content) { throw new Error("Filename and content are required"); } // Resolve path (handles both absolute and relative paths) - const resolvedPath = resolve(path); + const resolvedPath = resolve(filePath); + if (!resolvedPath) { + throw new Error(`Failed to resolve path: ${filePath}`); + } // Create directory if it doesn't exist const dir = dirname(resolvedPath); @@ -67,26 +70,40 @@ export class WriteFile implements Tool { let diffBlocksApplied = 0; // Check if content contains diff blocks - const hasDiffBlocks = diff.includes("<<<<<<< SEARCH"); + const hasDiffBlocks = content.includes("<<<<<<< SEARCH"); const isFilePresent = existsSync(resolvedPath); if (hasDiffBlocks) { if (isFilePresent) { // Apply diff blocks to existing file - const content = readFileSync(resolvedPath, "utf-8"); - const blocks = this._parseDiffBlocks(diff); - newContent = this._applyDiff(content, blocks); + const existingContent = readFileSync(resolvedPath, "utf-8"); + const blocks = this._parseDiffBlocks(content); + if (blocks.length === 0) { + throw new Error("No valid diff blocks found in content"); + } + newContent = this._applyDiff(existingContent, blocks); diffBlocksApplied = blocks.length; } else { throw new Error("Cannot apply diff blocks to non-existent file"); } } else { // Direct content write - will create new file if doesn't exist - newContent = diff; + newContent = content; + } + + // Write content and verify + writeFileSync(resolvedPath, newContent, "utf8"); + + // Verify write succeeded + if (!existsSync(resolvedPath)) { + throw new Error("File write failed - file does not exist after write"); + } + + const writtenContent = readFileSync(resolvedPath, "utf-8"); + if (writtenContent !== newContent) { + throw new Error("File write verification failed - content mismatch"); } - // Write content - writeFileSync(resolvedPath, newContent); const bytesWritten = Buffer.from(newContent).length; return { diff --git a/tests/write-file.test.ts b/tests/write-file.test.ts new file mode 100644 index 00000000..23cfe6f0 --- /dev/null +++ b/tests/write-file.test.ts @@ -0,0 +1,133 @@ +import { WriteFile } from "../src/tools/write-file"; +import { mkdirSync, writeFileSync, readFileSync, rmSync, existsSync } from "fs"; +import { join } from "path"; +import { tmpdir } from "os"; + +describe("WriteFile", () => { + let writeFile: WriteFile; + let testDir: string; + + beforeEach(() => { + writeFile = new WriteFile(); + testDir = join(tmpdir(), `write-file-test-${Date.now()}`); + mkdirSync(testDir, { recursive: true }); + }); + + afterEach(() => { + rmSync(testDir, { recursive: true, force: true }); + }); + + it("creates a new file with content", async () => { + const filePath = join(testDir, "new-file.txt"); + const content = "Hello, World!"; + + const result = await writeFile.execute({ + filename: filePath, + content, + }); + + expect(result.success).toBe(true); + expect(result.data?.bytesWritten).toBe(Buffer.from(content).length); + expect(readFileSync(filePath, "utf8")).toBe(content); + expect(result.data?.diffBlocksApplied).toBe(0); + }); + + it("creates nested directories if they don't exist", async () => { + const filePath = join(testDir, "nested", "dirs", "new-file.txt"); + const content = "Hello from nested file!"; + + const result = await writeFile.execute({ + filename: filePath, + content, + }); + + expect(result.success).toBe(true); + expect(existsSync(filePath)).toBe(true); + expect(readFileSync(filePath, "utf8")).toBe(content); + }); + + it("applies diff blocks to existing file", async () => { + const filePath = join(testDir, "existing-file.txt"); + const initialContent = "Line 1\nLine 2\nLine 3"; + writeFileSync(filePath, initialContent); + + const diffContent = `<<<<<<< SEARCH +Line 2 +======= +Updated Line 2 +>>>>>>> REPLACE`; + + const result = await writeFile.execute({ + filename: filePath, + content: diffContent, + }); + + expect(result.success).toBe(true); + expect(result.data?.diffBlocksApplied).toBe(1); + expect(readFileSync(filePath, "utf8")).toBe("Line 1\nUpdated Line 2\nLine 3"); + }); + + it("fails when applying diff blocks to non-existent file", async () => { + const filePath = join(testDir, "non-existent.txt"); + const diffContent = `<<<<<<< SEARCH +some content +======= +new content +>>>>>>> REPLACE`; + + const result = await writeFile.execute({ + filename: filePath, + content: diffContent, + }); + + expect(result.success).toBe(false); + expect(result.error).toContain("Cannot apply diff blocks to non-existent file"); + expect(existsSync(filePath)).toBe(false); + }); + + it("fails when diff blocks are invalid", async () => { + const filePath = join(testDir, "existing-file.txt"); + writeFileSync(filePath, "original content"); + + const invalidDiff = `<<<<<<< SEARCH +non-matching content +======= +new content +>>>>>>> REPLACE`; + + const result = await writeFile.execute({ + filename: filePath, + content: invalidDiff, + }); + + expect(result.success).toBe(false); + expect(readFileSync(filePath, "utf8")).toBe("original content"); + }); + + it("handles multiple diff blocks in order", async () => { + const filePath = join(testDir, "multi-diff.txt"); + const initialContent = "First\nSecond\nThird\nFourth"; + writeFileSync(filePath, initialContent); + + const diffContent = `<<<<<<< SEARCH +Second +======= +Updated Second +>>>>>>> REPLACE + +<<<<<<< SEARCH +Fourth +======= +Updated Fourth +>>>>>>> REPLACE`; + + const result = await writeFile.execute({ + filename: filePath, + content: diffContent, + }); + + expect(result.success).toBe(true); + expect(result.data?.diffBlocksApplied).toBe(2); + expect(readFileSync(filePath, "utf8")).toBe("First\nUpdated Second\nThird\nUpdated Fourth"); + }); +});