|
|
@@ -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 })
|
|
|
}
|
|
|
}
|