sketch: "git push" button

Ultimately, we want to allow users to push their changes to github, and
thereby do a good chunk of work without resorting to the terminal (and
figuring out how to move the git references around, which requires a
bunch of esotiric and annoying expertise).

This commit introduces:

1. For outtie's HTTP server (which is now comically Go HTTP ->
   CGI-effing-bin -> git -> shell script -> git in this case), there's a
   custom git hook that forwards changes to refs/remotes/origin/foo to
   origin/foo. This is a git proxy of sorts. By forwarding the
   SSH_AUTH_SOCK, we can use outtie's auth options without giving innie
   the actual credentials. This works by creating a temporary directory
   for git hooks (for outtie).

2. Innie sets up a new remote, "upstream" when a "passthrough-upstream"
   flag is pasksed. This remote kind of looks like the real upstream (so
   upstream/foo) is fetched. This will let the agent handle rebases
   better.

3. Innie exposes a /pushinfo handler that returns the list of remotes
   and the current commit and such. These have nice display names for
   the outtie's machine and github if useful.

   There's also a /push handler. This is the thing that knows about the
   refs/remotes/origin/foo thing. There's no magic git push refspec that
   makes this all work without that, I think. (Maybe there is? I don't
   think there is.)

   Note that there's been some changes about what the remotes look like,
   and when we use the remotes and when we use agent.GitOrigin().
   We may be able to simplify this by using git's insteadof
   configurations, but I think it's fine.

4. The web UI exposes a button to push, choose the remote and branch,
   and such. If it can't do the push, you'll get a button to try to get
   the agent to rebase.

   We don't allow force pushes in the UI. We're treating those
   as an advanced feature, and, if you need to do that, you can
   figure it out.

This was collaboration with a gazillion sketch sessions.
diff --git a/webui/src/web-components/sketch-app-shell-base.ts b/webui/src/web-components/sketch-app-shell-base.ts
index 3e3dbe3..3ddc183 100644
--- a/webui/src/web-components/sketch-app-shell-base.ts
+++ b/webui/src/web-components/sketch-app-shell-base.ts
@@ -15,6 +15,7 @@
 import "./sketch-monaco-view";
 import "./sketch-network-status";
 import "./sketch-call-status";
+import "./sketch-push-button";
 import "./sketch-terminal";
 import "./sketch-timeline";
 import "./sketch-view-mode-select";
@@ -156,6 +157,7 @@
     this._handleShowCommitDiff = this._handleShowCommitDiff.bind(this);
     this._handleMutlipleChoiceSelected =
       this._handleMutlipleChoiceSelected.bind(this);
+    this._handlePushRebaseRequest = this._handlePushRebaseRequest.bind(this);
     this._handleStopClick = this._handleStopClick.bind(this);
     this._handleEndClick = this._handleEndClick.bind(this);
     this._handleNotificationsToggle =
@@ -203,6 +205,10 @@
       "multiple-choice-selected",
       this._handleMutlipleChoiceSelected,
     );
+    window.addEventListener(
+      "push-rebase-request",
+      this._handlePushRebaseRequest,
+    );
 
     // register event listeners
     this.dataManager.addEventListener(
@@ -251,6 +257,10 @@
       "multiple-choice-selected",
       this._handleMutlipleChoiceSelected,
     );
+    window.removeEventListener(
+      "push-rebase-request",
+      this._handlePushRebaseRequest,
+    );
 
     // unregister data manager event listeners
     this.dataManager.removeEventListener(
@@ -770,6 +780,25 @@
     }
   }
 
+  async _handlePushRebaseRequest(e: CustomEvent) {
+    const chatInput = this.querySelector(
+      "sketch-chat-input",
+    ) as SketchChatInput;
+    if (chatInput) {
+      if (chatInput.content && chatInput.content.trim() !== "") {
+        chatInput.content += "\n\n";
+      }
+      chatInput.content += e.detail.message;
+      chatInput.focus();
+      // Adjust textarea height to accommodate new content
+      requestAnimationFrame(() => {
+        if (chatInput.adjustChatSpacing) {
+          chatInput.adjustChatSpacing();
+        }
+      });
+    }
+  }
+
   async _sendChat(e: CustomEvent) {
     console.log("app shell: _sendChat", e);
     e.preventDefault();