diff --git a/src/components/diff/unified-diff-preview.tsx b/src/components/diff/unified-diff-preview.tsx
index f25113e..4813de7 100644
--- a/src/components/diff/unified-diff-preview.tsx
+++ b/src/components/diff/unified-diff-preview.tsx
@@ -351,7 +351,18 @@ function parseUnifiedDiff(diffText: string): ParsedDiffFile[] {
continue
}
- const hunk = getActiveHunk()
+ let hunk = getActiveHunk()
+ // Auto-create an implicit hunk for patch formats (e.g. *** Add File)
+ // that emit +/- lines without a preceding @@ header.
+ if (
+ !hunk &&
+ (line.startsWith("+") || line.startsWith("-") || line.startsWith(" "))
+ ) {
+ if (getActiveFile()) {
+ startHunk("@@")
+ hunk = getActiveHunk()
+ }
+ }
if (!hunk) continue
if (line.startsWith("+") && !line.startsWith("+++")) {
@@ -487,6 +498,26 @@ function HunkLines({ rows }: { rows: ParsedDiffRow[] }) {
)
}
+/** Clean file content view for new files (no diff signs or green highlight) */
+function NewFileLines({ rows }: { rows: ParsedDiffRow[] }) {
+ return (
+
+ {rows.map((row, i) => (
+
+
+ {row.newLine ?? i + 1}
+
+ {row.text}
+
+ ))}
+
+ )
+}
+
+function isNewFileOnly(file: ParsedDiffFile): boolean {
+ return file.mode === "added" && file.deletions === 0
+}
+
export function UnifiedDiffPreview({
diffText,
className,
@@ -526,43 +557,52 @@ export function UnifiedDiffPreview({
return (
- {files.map((file) => (
-
-
-
- {t(modeKey(file.mode))}
-
-
- {toDisplayPath(file.path, folder?.path ?? null)}
-
-
-
- +{file.additions}
+ {files.map((file) => {
+ const newFile = isNewFileOnly(file)
+ return (
+
+
+
+ {newFile ? "WRITE" : t(modeKey(file.mode))}
-
- -{file.deletions}
+
+ {toDisplayPath(file.path, folder?.path ?? null)}
-
-
+ {!newFile && (
+
+
+ +{file.additions}
+
+
+ -{file.deletions}
+
+
+ )}
+
-
-
- {file.hunks.map((hunk, hunkIdx) => (
-
- {hunkIdx > 0 && }
-
-
- ))}
+
+
+ {newFile
+ ? file.hunks.map((hunk) => (
+
+ ))
+ : file.hunks.map((hunk, hunkIdx) => (
+
+ {hunkIdx > 0 && }
+
+
+ ))}
+
-
-
- ))}
+
+ )
+ })}
)
diff --git a/src/lib/tool-call-normalization.ts b/src/lib/tool-call-normalization.ts
index c8e89d9..675dc00 100644
--- a/src/lib/tool-call-normalization.ts
+++ b/src/lib/tool-call-normalization.ts
@@ -203,6 +203,17 @@ function inferFromInput(
const hasPath = hasAnyKey(parsed, ["file_path", "notebook_path", "path"])
if (hasPath) {
+ // Check write-specific input keys first — they take priority over
+ // kind/title because ACP ToolKind::Edit ("edit") is a category that
+ // covers both Edit and Write tools. Without this, a Write tool call
+ // (with {content, file_path}) would be classified as "edit" due to
+ // its kind, then rendered with EditToolInput which expects
+ // old_string/new_string and produces blank output for new files.
+ if (
+ hasAnyKey(parsed, ["content", "new_source", "cell_type", "edit_mode"])
+ ) {
+ return "write"
+ }
if (
normalizedKind === "read" ||
normalizedKind === "edit" ||
@@ -219,11 +230,6 @@ function inferFromInput(
) {
return normalizedTitle
}
- if (
- hasAnyKey(parsed, ["content", "new_source", "cell_type", "edit_mode"])
- ) {
- return "write"
- }
return "read"
}