From c933504d9c7074104d74ee1e15fa3b09d1afa84e Mon Sep 17 00:00:00 2001 From: Brendan Allan <14191578+Brendonovich@users.noreply.github.com> Date: Mon, 11 May 2026 17:21:59 +0800 Subject: [PATCH] fix(ui): better handle patch file support when rendering patch/edit tools (#26828) --- packages/ui/src/components/message-part.tsx | 46 +++++++++++++++------ packages/ui/src/components/session-diff.ts | 18 +++++--- 2 files changed, 46 insertions(+), 18 deletions(-) diff --git a/packages/ui/src/components/message-part.tsx b/packages/ui/src/components/message-part.tsx index 7a7d5b15fa..35598a170c 100644 --- a/packages/ui/src/components/message-part.tsx +++ b/packages/ui/src/components/message-part.tsx @@ -264,6 +264,7 @@ function getDirectory(path: string | undefined) { } import type { IconProps } from "./icon" +import { normalize } from "./session-diff" export type ToolInfo = { icon: IconProps["name"] @@ -1878,6 +1879,31 @@ ToolRegistry.register({ const path = createMemo(() => props.metadata?.filediff?.file || props.input.filePath || "") const filename = () => getFilename(props.input.filePath ?? "") const pending = () => props.status === "pending" || props.status === "running" + + const fileCompProps = createMemo(() => { + try { + if (props.metadata?.filediff) { + const diff = normalize({ + ...props.metadata?.filediff, + status: "modified", + }) + const fileDiff = diff.fileDiff + if (fileDiff) return { fileDiff, hunkSeparators: fileDiff.isPartial ? "simple" : "line-info-basic" } + } + } catch {} + + return { + before: { + name: props.metadata?.filediff?.file || props.input.filePath, + contents: props.metadata?.filediff?.before || props.input.oldString || "", + }, + after: { + name: props.metadata?.filediff?.file || props.input.filePath, + contents: props.metadata?.filediff?.after || props.input.newString || "", + }, + } + }) + return (
- +
@@ -2111,7 +2126,12 @@ ToolRegistry.register({
- +
diff --git a/packages/ui/src/components/session-diff.ts b/packages/ui/src/components/session-diff.ts index 60dcffd83d..52ef0a4bbc 100644 --- a/packages/ui/src/components/session-diff.ts +++ b/packages/ui/src/components/session-diff.ts @@ -1,4 +1,4 @@ -import { parseDiffFromFile, type FileDiffMetadata } from "@pierre/diffs" +import { parseDiffFromFile, parsePatchFiles, type FileDiffMetadata } from "@pierre/diffs" import { formatPatch, parsePatch, structuredPatch } from "diff" import type { SnapshotFileDiff, VcsFileDiff } from "@opencode-ai/sdk/v2" @@ -34,6 +34,8 @@ function patch(diff: ReviewDiff) { const afterLines: Array<{ text: string; newline: boolean }> = [] let previous: "-" | "+" | " " | undefined + const patchIsPartial = patch.hunks.every((h) => h.oldStart > 1) + for (const hunk of patch.hunks) { for (const line of hunk.lines) { if (line.startsWith("\\")) { @@ -67,9 +69,10 @@ function patch(diff: ReviewDiff) { before: beforeLines.map((line) => line.text + (line.newline ? "\n" : "")).join(""), after: afterLines.map((line) => line.text + (line.newline ? "\n" : "")).join(""), patch: diff.patch, + patchIsPartial, } } catch { - return { before: "", after: "", patch: diff.patch } + return { before: "", after: "", patch: diff.patch, patchIsPartial: false } } } return { @@ -86,27 +89,32 @@ function patch(diff: ReviewDiff) { { context: Number.MAX_SAFE_INTEGER }, ), ), + patchIsPartial: false, } } -function file(file: string, patch: string, before: string, after: string) { +function file(file: string, patch: string, before: string, after: string, partial = false) { const hit = cache.get(patch) if (hit) return hit - const value = parseDiffFromFile({ name: file, contents: before }, { name: file, contents: after }) + let value: FileDiffMetadata | undefined + if (partial) value = parsePatchFiles(patch)[0]?.files[0] + if (value === undefined) value = parseDiffFromFile({ name: file, contents: before }, { name: file, contents: after }) + cache.set(patch, value) return value } export function normalize(diff: ReviewDiff): ViewDiff { const next = patch(diff) + const fileDiff = file(diff.file, next.patch, next.before, next.after, next.patchIsPartial) return { file: diff.file, patch: next.patch, additions: diff.additions, deletions: diff.deletions, status: diff.status, - fileDiff: file(diff.file, next.patch, next.before, next.after), + fileDiff, } }