Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions packages/runtime/src/tools/built-in/apply-patch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,9 @@ function _applyHunks(
lineIndex = position + hunk.oldLines.length;
}

// Insertion-only hunks target the end of the file regardless of their order
// in the patch, so apply every replacement from the bottom up by position.
replacements.sort((left, right) => left[0] - right[0]);
for (const [position, oldLength, newLines] of replacements.reverse()) {
lines.splice(position, oldLength, ...newLines);
}
Expand Down
19 changes: 19 additions & 0 deletions packages/runtime/tests/tools/built-in/apply-patch.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,25 @@ describe("apply_patch built-in", () => {
expect(await fs.readFile(filePath, "utf8")).toBe("first\nsecond\n");
});

test("keeps insertion-only hunks at the end when a later hunk grows the file", async () => {
const workspace = await createWorkspace();
const filePath = path.join(workspace, "example.txt");
const original = "alpha\nbeta\ngamma\ndelta\n";
const expected = "alpha\nbeta one\nbeta two\ngamma\ndelta\nomega\n";
const insertion = "@@\n+omega";
const edit = "@@\n alpha\n-beta\n+beta one\n+beta two\n gamma";
const patch = (...hunks: string[]) =>
`*** Begin Patch\n*** Update File: example.txt\n${hunks.join("\n")}\n*** End Patch`;

await fs.writeFile(filePath, original, "utf8");
await applyPatch(patch(edit, insertion), workspace);
expect(await fs.readFile(filePath, "utf8")).toBe(expected);

await fs.writeFile(filePath, original, "utf8");
await applyPatch(patch(insertion, edit), workspace);
expect(await fs.readFile(filePath, "utf8")).toBe(expected);
});

test("can remove the complete contents of a file", async () => {
const workspace = await createWorkspace();
const filePath = path.join(workspace, "example.txt");
Expand Down