sketch: another attempt at chat/diff fixes.

Now, I've moved the chat message property to sketch-chat-input
and out of sketch-app-shell, which means the message for diff
updates goes straight there. The issue was that sketch-chat-input
was mutating this anyway, so clearing the chat message in
app-shell didn't make sense and/or didn't work.
diff --git a/loop/webui/src/web-components/sketch-app-shell.ts b/loop/webui/src/web-components/sketch-app-shell.ts
index 7560bd6..1dd3b6f 100644
--- a/loop/webui/src/web-components/sketch-app-shell.ts
+++ b/loop/webui/src/web-components/sketch-app-shell.ts
@@ -175,9 +175,6 @@
   messages: AgentMessage[] = [];
 
   @property()
-  chatMessageText: string = "";
-
-  @property()
   title: string = "";
 
   private dataManager = new DataManager();
@@ -201,7 +198,6 @@
 
     // Binding methods to this
     this._handleViewModeSelect = this._handleViewModeSelect.bind(this);
-    this._handleDiffComment = this._handleDiffComment.bind(this);
     this._handleShowCommitDiff = this._handleShowCommitDiff.bind(this);
     this._handlePopState = this._handlePopState.bind(this);
   }
@@ -221,7 +217,6 @@
 
     // Add event listeners
     window.addEventListener("view-mode-select", this._handleViewModeSelect);
-    window.addEventListener("diff-comment", this._handleDiffComment);
     window.addEventListener("show-commit-diff", this._handleShowCommitDiff);
 
     // register event listeners
@@ -245,7 +240,6 @@
 
     // Remove event listeners
     window.removeEventListener("view-mode-select", this._handleViewModeSelect);
-    window.removeEventListener("diff-comment", this._handleDiffComment);
     window.removeEventListener("show-commit-diff", this._handleShowCommitDiff);
 
     // unregister data manager event listeners
@@ -317,19 +311,6 @@
   }
 
   /**
-   * Handle diff comment event
-   */
-  private _handleDiffComment(event: CustomEvent) {
-    const { comment } = event.detail;
-    if (!comment) return;
-
-    if (this.chatMessageText.length > 0) {
-      this.chatMessageText += "\n\n";
-    }
-    this.chatMessageText += comment;
-  }
-
-  /**
    * Listen for commit diff event
    * @param commitHash The commit hash to show diff for
    */
@@ -497,9 +478,8 @@
         const errorData = await response.text();
         throw new Error(`Server error: ${response.status} - ${errorData}`);
       }
-      // Clear the input after successfully sending the message.
-      this.chatMessageText = "";
 
+      // TOOD(philip): If the data manager is getting messages out of order, there's a bug?
       // Reset data manager state to force a full refresh after sending a message
       // This ensures we get all messages in the correct order
       // Use private API for now - TODO: add a resetState() method to DataManager
@@ -583,10 +563,7 @@
         </div>
       </div>
 
-      <sketch-chat-input
-        .content=${this.chatMessageText}
-        @send-chat="${this._sendChat}"
-      ></sketch-chat-input>
+      <sketch-chat-input @send-chat="${this._sendChat}"></sketch-chat-input>
     `;
   }
 
diff --git a/loop/webui/src/web-components/sketch-chat-input.ts b/loop/webui/src/web-components/sketch-chat-input.ts
index 74570cc..74e462f 100644
--- a/loop/webui/src/web-components/sketch-chat-input.ts
+++ b/loop/webui/src/web-components/sketch-chat-input.ts
@@ -1,9 +1,9 @@
 import { css, html, LitElement, PropertyValues } from "lit";
-import { customElement, property, query } from "lit/decorators.js";
+import { customElement, property, state, query } from "lit/decorators.js";
 
 @customElement("sketch-chat-input")
 export class SketchChatInput extends LitElement {
-  @property()
+  @state()
   content: string = "";
 
   // See https://lit.dev/docs/components/styles/ for how lit-element handles CSS.
@@ -66,15 +66,29 @@
 
   constructor() {
     super();
+    this._handleDiffComment = this._handleDiffComment.bind(this);
   }
 
   connectedCallback() {
     super.connectedCallback();
+    window.addEventListener("diff-comment", this._handleDiffComment);
+  }
+
+  private _handleDiffComment(event: CustomEvent) {
+    const { comment } = event.detail;
+    if (!comment) return;
+
+    if (this.content != "") {
+      this.content += "\n\n";
+    }
+    this.content += comment;
+    requestAnimationFrame(() => this.adjustChatSpacing());
   }
 
   // See https://lit.dev/docs/components/lifecycle/
   disconnectedCallback() {
     super.disconnectedCallback();
+    window.removeEventListener("diff-comment", this._handleDiffComment);
   }
 
   sendChatMessage() {
@@ -84,6 +98,9 @@
       composed: true,
     });
     this.dispatchEvent(event);
+
+    // TODO(philip?): Ideally we only clear the content if the send is successful.
+    this.content = ""; // Clear content after sending
   }
 
   adjustChatSpacing() {
@@ -99,7 +116,7 @@
     this.chatInput.style.height = `${scrollHeight}px`;
   }
 
-  _sendChatClicked() {
+  async _sendChatClicked() {
     this.sendChatMessage();
     this.chatInput.focus(); // Refocus the input after sending
     // Reset height after sending a message