fix: preserve BOM in text tool round-trips (#23797)
This commit is contained in:
@@ -14,6 +14,7 @@ import { AppFileSystem } from "@opencode-ai/shared/filesystem"
|
||||
import DESCRIPTION from "./apply_patch.txt"
|
||||
import { File } from "../file"
|
||||
import { Format } from "../format"
|
||||
import * as Bom from "@/util/bom"
|
||||
|
||||
const PatchParams = z.object({
|
||||
patchText: z.string().describe("The full patch text that describes all changes to be made"),
|
||||
@@ -59,6 +60,7 @@ export const ApplyPatchTool = Tool.define(
|
||||
diff: string
|
||||
additions: number
|
||||
deletions: number
|
||||
bom: boolean
|
||||
}> = []
|
||||
|
||||
let totalDiff = ""
|
||||
@@ -72,11 +74,12 @@ export const ApplyPatchTool = Tool.define(
|
||||
const oldContent = ""
|
||||
const newContent =
|
||||
hunk.contents.length === 0 || hunk.contents.endsWith("\n") ? hunk.contents : `${hunk.contents}\n`
|
||||
const diff = trimDiff(createTwoFilesPatch(filePath, filePath, oldContent, newContent))
|
||||
const next = Bom.split(newContent)
|
||||
const diff = trimDiff(createTwoFilesPatch(filePath, filePath, oldContent, next.text))
|
||||
|
||||
let additions = 0
|
||||
let deletions = 0
|
||||
for (const change of diffLines(oldContent, newContent)) {
|
||||
for (const change of diffLines(oldContent, next.text)) {
|
||||
if (change.added) additions += change.count || 0
|
||||
if (change.removed) deletions += change.count || 0
|
||||
}
|
||||
@@ -84,11 +87,12 @@ export const ApplyPatchTool = Tool.define(
|
||||
fileChanges.push({
|
||||
filePath,
|
||||
oldContent,
|
||||
newContent,
|
||||
newContent: next.text,
|
||||
type: "add",
|
||||
diff,
|
||||
additions,
|
||||
deletions,
|
||||
bom: next.bom,
|
||||
})
|
||||
|
||||
totalDiff += diff + "\n"
|
||||
@@ -104,13 +108,16 @@ export const ApplyPatchTool = Tool.define(
|
||||
)
|
||||
}
|
||||
|
||||
const oldContent = yield* afs.readFileString(filePath)
|
||||
const source = yield* Bom.readFile(afs, filePath)
|
||||
const oldContent = source.text
|
||||
let newContent = oldContent
|
||||
let bom = source.bom
|
||||
|
||||
// Apply the update chunks to get new content
|
||||
try {
|
||||
const fileUpdate = Patch.deriveNewContentsFromChunks(filePath, hunk.chunks)
|
||||
newContent = fileUpdate.content
|
||||
bom = fileUpdate.bom
|
||||
} catch (error) {
|
||||
return yield* Effect.fail(new Error(`apply_patch verification failed: ${error}`))
|
||||
}
|
||||
@@ -136,6 +143,7 @@ export const ApplyPatchTool = Tool.define(
|
||||
diff,
|
||||
additions,
|
||||
deletions,
|
||||
bom,
|
||||
})
|
||||
|
||||
totalDiff += diff + "\n"
|
||||
@@ -143,8 +151,8 @@ export const ApplyPatchTool = Tool.define(
|
||||
}
|
||||
|
||||
case "delete": {
|
||||
const contentToDelete = yield* afs
|
||||
.readFileString(filePath)
|
||||
const source = yield* Bom
|
||||
.readFile(afs, filePath)
|
||||
.pipe(
|
||||
Effect.catch((error) =>
|
||||
Effect.fail(
|
||||
@@ -154,6 +162,7 @@ export const ApplyPatchTool = Tool.define(
|
||||
),
|
||||
),
|
||||
)
|
||||
const contentToDelete = source.text
|
||||
const deleteDiff = trimDiff(createTwoFilesPatch(filePath, filePath, contentToDelete, ""))
|
||||
|
||||
const deletions = contentToDelete.split("\n").length
|
||||
@@ -166,6 +175,7 @@ export const ApplyPatchTool = Tool.define(
|
||||
diff: deleteDiff,
|
||||
additions: 0,
|
||||
deletions,
|
||||
bom: source.bom,
|
||||
})
|
||||
|
||||
totalDiff += deleteDiff + "\n"
|
||||
@@ -207,12 +217,12 @@ export const ApplyPatchTool = Tool.define(
|
||||
case "add":
|
||||
// Create parent directories (recursive: true is safe on existing/root dirs)
|
||||
|
||||
yield* afs.writeWithDirs(change.filePath, change.newContent)
|
||||
yield* afs.writeWithDirs(change.filePath, Bom.join(change.newContent, change.bom))
|
||||
updates.push({ file: change.filePath, event: "add" })
|
||||
break
|
||||
|
||||
case "update":
|
||||
yield* afs.writeWithDirs(change.filePath, change.newContent)
|
||||
yield* afs.writeWithDirs(change.filePath, Bom.join(change.newContent, change.bom))
|
||||
updates.push({ file: change.filePath, event: "change" })
|
||||
break
|
||||
|
||||
@@ -220,7 +230,7 @@ export const ApplyPatchTool = Tool.define(
|
||||
if (change.movePath) {
|
||||
// Create parent directories (recursive: true is safe on existing/root dirs)
|
||||
|
||||
yield* afs.writeWithDirs(change.movePath!, change.newContent)
|
||||
yield* afs.writeWithDirs(change.movePath!, Bom.join(change.newContent, change.bom))
|
||||
yield* afs.remove(change.filePath)
|
||||
updates.push({ file: change.filePath, event: "unlink" })
|
||||
updates.push({ file: change.movePath, event: "add" })
|
||||
@@ -234,7 +244,9 @@ export const ApplyPatchTool = Tool.define(
|
||||
}
|
||||
|
||||
if (edited) {
|
||||
yield* format.file(edited)
|
||||
if (yield* format.file(edited)) {
|
||||
yield* Bom.syncFile(afs, edited, change.bom)
|
||||
}
|
||||
yield* bus.publish(File.Event.Edited, { file: edited })
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user