webui: add diff display for patches

Co-Authored-By: sketch <hello@sketch.dev>
Change-ID: s2e9bdfb014ddec3ck
diff --git a/webui/src/types.ts b/webui/src/types.ts
index a4f2154..217afe2 100644
--- a/webui/src/types.ts
+++ b/webui/src/types.ts
@@ -47,6 +47,7 @@
 	turnDuration?: Duration | null;
 	hide_output?: boolean;
 	todo_content?: string | null;
+	display?: any;
 	idx: number;
 }
 
diff --git a/webui/src/web-components/demo/sketch-tool-card.demo.ts b/webui/src/web-components/demo/sketch-tool-card.demo.ts
index 6b499f1..625e555 100644
--- a/webui/src/web-components/demo/sketch-tool-card.demo.ts
+++ b/webui/src/web-components/demo/sketch-tool-card.demo.ts
@@ -142,6 +142,8 @@
         result_message: {
           type: "tool",
           tool_result: "- Applied all patches\n",
+          display:
+            "@@ -1,3 +1,3 @@\n # Web Components\n \n-This directory contains the old components.\n+This directory contains custom web components...",
           tool_call_id: "toolu_01TNhLX2AWkZwsu2KCLKrpju",
         },
       },
diff --git a/webui/src/web-components/sketch-tool-card-base.ts b/webui/src/web-components/sketch-tool-card-base.ts
index 8dcc887..9018275 100644
--- a/webui/src/web-components/sketch-tool-card-base.ts
+++ b/webui/src/web-components/sketch-tool-card-base.ts
@@ -118,7 +118,9 @@
             ? html`<div class="mb-2">${this.inputContent}</div>`
             : ""}
           ${this.resultContent
-            ? html`<div class="mt-2">${this.resultContent}</div>`
+            ? html`<div class="${this.inputContent ? "mt-2" : ""}">
+                ${this.resultContent}
+              </div>`
             : ""}
         </div>
       </div>
diff --git a/webui/src/web-components/sketch-tool-card.ts b/webui/src/web-components/sketch-tool-card.ts
index 8016fbc..9c1ae62 100644
--- a/webui/src/web-components/sketch-tool-card.ts
+++ b/webui/src/web-components/sketch-tool-card.ts
@@ -1,7 +1,7 @@
 import { html } from "lit";
 import { unsafeHTML } from "lit/directives/unsafe-html.js";
 import { customElement, property } from "lit/decorators.js";
-import { ToolCall, State } from "../types";
+import { State, ToolCall } from "../types";
 import { marked } from "marked";
 import DOMPurify from "dompurify";
 import { SketchTailwindElement } from "./sketch-tailwind-element";
@@ -199,6 +199,37 @@
   @property() toolCall: ToolCall;
   @property() open: boolean;
 
+  // Render a diff with syntax highlighting
+  renderDiff(diff: string) {
+    // Remove ---/+++ header lines and trim leading/trailing blank lines
+    const lines = diff
+      .split("\n")
+      .filter((line) => !line.startsWith("---") && !line.startsWith("+++"))
+      .join("\n")
+      .trim()
+      .split("\n");
+
+    const coloredLines = lines.map((line) => {
+      if (line.startsWith("+")) {
+        return html`<div class="text-green-600 bg-green-50">${line}</div>`;
+      } else if (line.startsWith("-")) {
+        return html`<div class="text-red-600 bg-red-50">${line}</div>`;
+      } else if (line.startsWith("@@")) {
+        // prettier-ignore
+        return html`<div class="text-cyan-600 bg-cyan-50 font-semibold">${line}</div>`;
+      } else {
+        return html`<div class="text-gray-800">${line}</div>`;
+      }
+    });
+
+    return html`<pre
+      class="bg-gray-100 text-xs p-2 rounded whitespace-pre-wrap break-words max-w-full w-full box-border overflow-x-auto font-mono"
+    >
+      ${coloredLines}
+    </pre
+    >`;
+  }
+
   render() {
     const patchInput = JSON.parse(this.toolCall?.input);
 
@@ -209,18 +240,25 @@
       edit${patchInput.patches.length > 1 ? "s" : ""}
     </span>`;
 
-    const inputContent = html`<div>
-      ${patchInput.patches.map((patch) => {
-        return html`<div class="mb-2">
-          Patch operation: <b>${patch.operation}</b>
-          ${createPreElement(patch.newText)}
-        </div>`;
-      })}
-    </div>`;
+    const inputContent = html``;
 
-    const resultContent = this.toolCall?.result_message?.tool_result
-      ? createPreElement(this.toolCall.result_message.tool_result)
-      : "";
+    // Show diff if available, otherwise show the regular result
+    let resultContent;
+    if (
+      this.toolCall?.result_message?.display &&
+      typeof this.toolCall.result_message.display === "string"
+    ) {
+      // Render the diff with syntax highlighting
+      resultContent = html`<div class="w-full relative">
+        ${this.renderDiff(this.toolCall.result_message.display)}
+      </div>`;
+    } else if (this.toolCall?.result_message?.tool_result) {
+      resultContent = createPreElement(
+        this.toolCall.result_message.tool_result,
+      );
+    } else {
+      resultContent = "";
+    }
 
     return html`<sketch-tool-card-base
       .open=${this.open}