From f53768612b1e2268697b5444e502032ef9f3fb3c Mon Sep 17 00:00:00 2001
From: Nate Sesti <sestinj@gmail.com>
Date: Tue, 23 May 2023 23:45:12 -0400
Subject: copying from old repo

---
 extension/react-app/src/main.tsx | 10 ++++++++++
 1 file changed, 10 insertions(+)
 create mode 100644 extension/react-app/src/main.tsx

(limited to 'extension/react-app/src/main.tsx')

diff --git a/extension/react-app/src/main.tsx b/extension/react-app/src/main.tsx
new file mode 100644
index 00000000..791f139e
--- /dev/null
+++ b/extension/react-app/src/main.tsx
@@ -0,0 +1,10 @@
+import React from 'react'
+import ReactDOM from 'react-dom/client'
+import App from './App'
+import './index.css'
+
+ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
+  <React.StrictMode>
+    <App />
+  </React.StrictMode>,
+)
-- 
cgit v1.2.3-70-g09d2


From d3db75ee7e2483f86ba5eb8856dd59aaadfae285 Mon Sep 17 00:00:00 2001
From: Nate Sesti <sestinj@gmail.com>
Date: Sat, 27 May 2023 23:33:47 -0400
Subject: posthog setup in react app

---
 extension/react-app/package-lock.json        | 39 ++++++++++++++++++++++++++++
 extension/react-app/package.json             |  1 +
 extension/react-app/src/main.tsx             | 25 ++++++++++++------
 extension/src/activation/environmentSetup.ts |  4 +--
 4 files changed, 59 insertions(+), 10 deletions(-)

(limited to 'extension/react-app/src/main.tsx')

diff --git a/extension/react-app/package-lock.json b/extension/react-app/package-lock.json
index 1ba8cfe8..dbcbc5cc 100644
--- a/extension/react-app/package-lock.json
+++ b/extension/react-app/package-lock.json
@@ -10,6 +10,7 @@
       "dependencies": {
         "@styled-icons/heroicons-outline": "^10.47.0",
         "@types/vscode-webview": "^1.57.1",
+        "posthog-js": "^1.58.0",
         "react": "^18.2.0",
         "react-dom": "^18.2.0",
         "react-markdown": "^8.0.5",
@@ -1506,6 +1507,11 @@
         "reusify": "^1.0.4"
       }
     },
+    "node_modules/fflate": {
+      "version": "0.4.8",
+      "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.4.8.tgz",
+      "integrity": "sha512-FJqqoDBR00Mdj9ppamLa/Y7vxm+PRmNWA67N846RvsoYVMKB4q3y/de5PA7gUmRMYK/8CMz2GDZQmCRN1wBcWA=="
+    },
     "node_modules/fill-range": {
       "version": "7.0.1",
       "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
@@ -2528,6 +2534,15 @@
       "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
       "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ=="
     },
+    "node_modules/posthog-js": {
+      "version": "1.58.0",
+      "resolved": "https://registry.npmjs.org/posthog-js/-/posthog-js-1.58.0.tgz",
+      "integrity": "sha512-PpH/MwjwV6UHDsv78xFvteEWYgY3O/HTKBnotzmkNCDWgsKzNr978B1AKzgtBU2GzBsnwUfuK+u2O6mxRzFSWw==",
+      "dependencies": {
+        "fflate": "^0.4.1",
+        "rrweb-snapshot": "^1.1.14"
+      }
+    },
     "node_modules/prop-types": {
       "version": "15.8.1",
       "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
@@ -2778,6 +2793,11 @@
         "fsevents": "~2.3.2"
       }
     },
+    "node_modules/rrweb-snapshot": {
+      "version": "1.1.14",
+      "resolved": "https://registry.npmjs.org/rrweb-snapshot/-/rrweb-snapshot-1.1.14.tgz",
+      "integrity": "sha512-eP5pirNjP5+GewQfcOQY4uBiDnpqxNRc65yKPW0eSoU1XamDfc4M8oqpXGMyUyvLyxFDB0q0+DChuxxiU2FXBQ=="
+    },
     "node_modules/run-parallel": {
       "version": "1.2.0",
       "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
@@ -4196,6 +4216,11 @@
         "reusify": "^1.0.4"
       }
     },
+    "fflate": {
+      "version": "0.4.8",
+      "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.4.8.tgz",
+      "integrity": "sha512-FJqqoDBR00Mdj9ppamLa/Y7vxm+PRmNWA67N846RvsoYVMKB4q3y/de5PA7gUmRMYK/8CMz2GDZQmCRN1wBcWA=="
+    },
     "fill-range": {
       "version": "7.0.1",
       "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
@@ -4803,6 +4828,15 @@
       "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
       "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ=="
     },
+    "posthog-js": {
+      "version": "1.58.0",
+      "resolved": "https://registry.npmjs.org/posthog-js/-/posthog-js-1.58.0.tgz",
+      "integrity": "sha512-PpH/MwjwV6UHDsv78xFvteEWYgY3O/HTKBnotzmkNCDWgsKzNr978B1AKzgtBU2GzBsnwUfuK+u2O6mxRzFSWw==",
+      "requires": {
+        "fflate": "^0.4.1",
+        "rrweb-snapshot": "^1.1.14"
+      }
+    },
     "prop-types": {
       "version": "15.8.1",
       "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
@@ -4964,6 +4998,11 @@
         "fsevents": "~2.3.2"
       }
     },
+    "rrweb-snapshot": {
+      "version": "1.1.14",
+      "resolved": "https://registry.npmjs.org/rrweb-snapshot/-/rrweb-snapshot-1.1.14.tgz",
+      "integrity": "sha512-eP5pirNjP5+GewQfcOQY4uBiDnpqxNRc65yKPW0eSoU1XamDfc4M8oqpXGMyUyvLyxFDB0q0+DChuxxiU2FXBQ=="
+    },
     "run-parallel": {
       "version": "1.2.0",
       "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
diff --git a/extension/react-app/package.json b/extension/react-app/package.json
index 3993b030..7d1211de 100644
--- a/extension/react-app/package.json
+++ b/extension/react-app/package.json
@@ -11,6 +11,7 @@
   "dependencies": {
     "@styled-icons/heroicons-outline": "^10.47.0",
     "@types/vscode-webview": "^1.57.1",
+    "posthog-js": "^1.58.0",
     "react": "^18.2.0",
     "react-dom": "^18.2.0",
     "react-markdown": "^8.0.5",
diff --git a/extension/react-app/src/main.tsx b/extension/react-app/src/main.tsx
index 791f139e..1b94dc82 100644
--- a/extension/react-app/src/main.tsx
+++ b/extension/react-app/src/main.tsx
@@ -1,10 +1,19 @@
-import React from 'react'
-import ReactDOM from 'react-dom/client'
-import App from './App'
-import './index.css'
+import React from "react";
+import ReactDOM from "react-dom/client";
+import App from "./App";
+import "./index.css";
 
-ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
+import posthog from "posthog-js";
+import { PostHogProvider } from "posthog-js/react";
+
+posthog.init("phc_JS6XFROuNbhJtVCEdTSYk6gl5ArRrTNMpCcguAXlSPs", {
+  api_host: "https://app.posthog.com",
+});
+
+ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
   <React.StrictMode>
-    <App />
-  </React.StrictMode>,
-)
+    <PostHogProvider client={posthog}>
+      <App />
+    </PostHogProvider>
+  </React.StrictMode>
+);
diff --git a/extension/src/activation/environmentSetup.ts b/extension/src/activation/environmentSetup.ts
index 4816b4b1..1e921c18 100644
--- a/extension/src/activation/environmentSetup.ts
+++ b/extension/src/activation/environmentSetup.ts
@@ -59,7 +59,7 @@ async function setupPythonEnv() {
   }
   let pipCmd = pythonCmd.endsWith("3") ? "pip3" : "pip";
 
-  let activateCmd = "source env/bin/activate";
+  let activateCmd = ". env/bin/activate";
   let pipUpgradeCmd = `${pipCmd} install --upgrade pip`;
   if (process.platform == "win32") {
     activateCmd = ".\\env\\Scripts\\activate";
@@ -147,7 +147,7 @@ export async function startContinuePythonServer() {
     console.log("Error checking for existing server", e);
   }
 
-  let activateCmd = "source env/bin/activate";
+  let activateCmd = ". env/bin/activate";
   let pythonCmd = "python3";
   if (process.platform == "win32") {
     activateCmd = ".\\env\\Scripts\\activate";
-- 
cgit v1.2.3-70-g09d2


From ec408c7654cb74398a78a7348609635760926114 Mon Sep 17 00:00:00 2001
From: Nate Sesti <sestinj@gmail.com>
Date: Wed, 5 Jul 2023 16:28:58 -0700
Subject: setting to show codelens in diff editor

---
 extension/package-lock.json                     |  4 ++--
 extension/package.json                          |  3 ++-
 extension/react-app/src/components/ComboBox.tsx |  2 +-
 extension/react-app/src/main.tsx                |  4 ++++
 extension/src/diffs.ts                          |  6 ++++++
 extension/src/lang-server/codeLens.ts           | 24 ++++++++++++++++++++----
 6 files changed, 35 insertions(+), 8 deletions(-)

(limited to 'extension/react-app/src/main.tsx')

diff --git a/extension/package-lock.json b/extension/package-lock.json
index 169b13b5..6e527583 100644
--- a/extension/package-lock.json
+++ b/extension/package-lock.json
@@ -1,12 +1,12 @@
 {
   "name": "continue",
-  "version": "0.0.111",
+  "version": "0.0.112",
   "lockfileVersion": 2,
   "requires": true,
   "packages": {
     "": {
       "name": "continue",
-      "version": "0.0.111",
+      "version": "0.0.112",
       "license": "Apache-2.0",
       "dependencies": {
         "@electron/rebuild": "^3.2.10",
diff --git a/extension/package.json b/extension/package.json
index 6a0f9eb3..413e5b89 100644
--- a/extension/package.json
+++ b/extension/package.json
@@ -14,7 +14,7 @@
   "displayName": "Continue",
   "pricing": "Free",
   "description": "The open-source coding autopilot",
-  "version": "0.0.111",
+  "version": "0.0.112",
   "publisher": "Continue",
   "engines": {
     "vscode": "^1.67.0"
@@ -39,6 +39,7 @@
     "onView:continueGUIView"
   ],
   "main": "./out/extension.js",
+  "browser": "./out/extension.js",
   "contributes": {
     "configuration": {
       "title": "Continue",
diff --git a/extension/react-app/src/components/ComboBox.tsx b/extension/react-app/src/components/ComboBox.tsx
index 545be32a..61c9ab1e 100644
--- a/extension/react-app/src/components/ComboBox.tsx
+++ b/extension/react-app/src/components/ComboBox.tsx
@@ -198,7 +198,7 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
 
                 // cmd+enter to /edit
                 if (event.metaKey) {
-                  event.currentTarget.value = `/edit ${event.currentTarget}`;
+                  event.currentTarget.value = `/edit ${event.currentTarget.value}`;
                 }
                 if (props.onEnter) props.onEnter(event);
                 setInputValue("");
diff --git a/extension/react-app/src/main.tsx b/extension/react-app/src/main.tsx
index 1b94dc82..0b02575c 100644
--- a/extension/react-app/src/main.tsx
+++ b/extension/react-app/src/main.tsx
@@ -8,6 +8,10 @@ import { PostHogProvider } from "posthog-js/react";
 
 posthog.init("phc_JS6XFROuNbhJtVCEdTSYk6gl5ArRrTNMpCcguAXlSPs", {
   api_host: "https://app.posthog.com",
+  session_recording: {
+    // WARNING: Only enable this if you understand the security implications
+    recordCrossOriginIframes: true,
+  } as any,
 });
 
 ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
diff --git a/extension/src/diffs.ts b/extension/src/diffs.ts
index b70c3b59..178b1a9d 100644
--- a/extension/src/diffs.ts
+++ b/extension/src/diffs.ts
@@ -47,6 +47,12 @@ class DiffManager {
     if (!editor) {
       throw new Error("No active text editor found for Continue Diff");
     }
+
+    // Change the vscode setting to allow codeLens in diff editor
+    vscode.workspace
+      .getConfiguration("diffEditor", editor.document.uri)
+      .update("codeLens", true, vscode.ConfigurationTarget.Global);
+
     return editor;
   }
 
diff --git a/extension/src/lang-server/codeLens.ts b/extension/src/lang-server/codeLens.ts
index 08435a3b..381a0084 100644
--- a/extension/src/lang-server/codeLens.ts
+++ b/extension/src/lang-server/codeLens.ts
@@ -67,11 +67,9 @@ class DiffViewerCodeLensProvider implements vscode.CodeLensProvider {
     document: vscode.TextDocument,
     token: vscode.CancellationToken
   ): vscode.CodeLens[] | Thenable<vscode.CodeLens[]> {
-    if (path.dirname(document.uri.fsPath) !== DIFF_DIRECTORY) {
-      return [];
-    } else {
+    if (path.dirname(document.uri.fsPath) === DIFF_DIRECTORY) {
       const codeLenses: vscode.CodeLens[] = [];
-      const range = new vscode.Range(0, 0, 0, 0);
+      const range = new vscode.Range(0, 0, 1, 0);
       codeLenses.push(
         new vscode.CodeLens(range, {
           title: "Accept ✅",
@@ -85,6 +83,24 @@ class DiffViewerCodeLensProvider implements vscode.CodeLensProvider {
         })
       );
       return codeLenses;
+    } else {
+      return [];
+    }
+  }
+
+  onDidChangeCodeLenses?: vscode.Event<void> | undefined;
+
+  constructor(emitter?: vscode.EventEmitter<void>) {
+    if (emitter) {
+      this.onDidChangeCodeLenses = emitter.event;
+      this.onDidChangeCodeLenses(() => {
+        if (vscode.window.activeTextEditor) {
+          this.provideCodeLenses(
+            vscode.window.activeTextEditor.document,
+            new vscode.CancellationTokenSource().token
+          );
+        }
+      });
     }
   }
 }
-- 
cgit v1.2.3-70-g09d2


From 5c03dd4775845c559a1f6298f7577609ba907bb1 Mon Sep 17 00:00:00 2001
From: Nate Sesti <sestinj@gmail.com>
Date: Wed, 5 Jul 2023 23:49:37 -0700
Subject: ui overhaul

---
 continuedev/src/continuedev/core/autopilot.py      |  47 +++-
 continuedev/src/continuedev/core/main.py           |   9 +-
 .../src/continuedev/models/generate_json_schema.py |   4 +-
 continuedev/src/continuedev/server/gui.py          |  14 +
 .../media/Lexend/Lexend-VariableFont_wght.ttf      | Bin 0 -> 176220 bytes
 extension/media/Lexend/OFL.txt                     |  93 +++++++
 extension/media/Lexend/README.txt                  |  71 +++++
 extension/media/Lexend/static/Lexend-Black.ttf     | Bin 0 -> 78496 bytes
 extension/media/Lexend/static/Lexend-Bold.ttf      | Bin 0 -> 78632 bytes
 extension/media/Lexend/static/Lexend-ExtraBold.ttf | Bin 0 -> 78716 bytes
 .../media/Lexend/static/Lexend-ExtraLight.ttf      | Bin 0 -> 78508 bytes
 extension/media/Lexend/static/Lexend-Light.ttf     | Bin 0 -> 78668 bytes
 extension/media/Lexend/static/Lexend-Medium.ttf    | Bin 0 -> 78696 bytes
 extension/media/Lexend/static/Lexend-Regular.ttf   | Bin 0 -> 78360 bytes
 extension/media/Lexend/static/Lexend-SemiBold.ttf  | Bin 0 -> 78744 bytes
 extension/media/Lexend/static/Lexend-Thin.ttf      | Bin 0 -> 78380 bytes
 extension/react-app/package-lock.json              |  59 ++++
 extension/react-app/package.json                   |   1 +
 extension/react-app/src/App.tsx                    |  39 +--
 extension/react-app/src/components/CodeBlock.tsx   |   4 +-
 extension/react-app/src/components/ComboBox.tsx    | 191 +++++++------
 .../react-app/src/components/ContinueButton.tsx    |   2 +-
 .../src/components/HeaderButtonWithText.tsx        |  44 +--
 extension/react-app/src/components/Loader.tsx      |  40 +++
 extension/react-app/src/components/PillButton.tsx  | 144 +++++++---
 .../react-app/src/components/StepContainer.tsx     |  13 +-
 extension/react-app/src/components/TextDialog.tsx  |   2 +-
 .../src/components/UserInputContainer.tsx          |   6 +-
 extension/react-app/src/components/index.ts        |  22 +-
 .../src/hooks/ContinueGUIClientProtocol.ts         |   4 +
 .../react-app/src/hooks/useContinueGUIProtocol.ts  |   8 +
 extension/react-app/src/index.css                  |   9 +-
 extension/react-app/src/main.tsx                   |   6 +-
 extension/react-app/src/tabs/gui.tsx               |  22 +-
 extension/schema/FullState.d.ts                    | 133 +++++++++
 extension/src/debugPanel.ts                        |   4 +
 schema/json/FullState.json                         | 304 +++++++++++++++++++++
 37 files changed, 1088 insertions(+), 207 deletions(-)
 create mode 100644 extension/media/Lexend/Lexend-VariableFont_wght.ttf
 create mode 100644 extension/media/Lexend/OFL.txt
 create mode 100644 extension/media/Lexend/README.txt
 create mode 100644 extension/media/Lexend/static/Lexend-Black.ttf
 create mode 100644 extension/media/Lexend/static/Lexend-Bold.ttf
 create mode 100644 extension/media/Lexend/static/Lexend-ExtraBold.ttf
 create mode 100644 extension/media/Lexend/static/Lexend-ExtraLight.ttf
 create mode 100644 extension/media/Lexend/static/Lexend-Light.ttf
 create mode 100644 extension/media/Lexend/static/Lexend-Medium.ttf
 create mode 100644 extension/media/Lexend/static/Lexend-Regular.ttf
 create mode 100644 extension/media/Lexend/static/Lexend-SemiBold.ttf
 create mode 100644 extension/media/Lexend/static/Lexend-Thin.ttf
 create mode 100644 extension/react-app/src/components/Loader.tsx
 create mode 100644 extension/schema/FullState.d.ts
 create mode 100644 schema/json/FullState.json

(limited to 'extension/react-app/src/main.tsx')

diff --git a/continuedev/src/continuedev/core/autopilot.py b/continuedev/src/continuedev/core/autopilot.py
index b1c4f471..acdc1f0d 100644
--- a/continuedev/src/continuedev/core/autopilot.py
+++ b/continuedev/src/continuedev/core/autopilot.py
@@ -12,7 +12,7 @@ from .observation import Observation, InternalErrorObservation
 from ..server.ide_protocol import AbstractIdeProtocolServer
 from ..libs.util.queue import AsyncSubscriptionQueue
 from ..models.main import ContinueBaseModel
-from .main import Context, ContinueCustomException, Policy, History, FullState, Step, HistoryNode
+from .main import Context, ContinueCustomException, HighlightedRangeContext, Policy, History, FullState, Step, HistoryNode
 from ..steps.core.core import ReversibleStep, ManualEditStep, UserInputStep
 from ..libs.util.telemetry import capture_event
 from .sdk import ContinueSDK
@@ -140,11 +140,24 @@ class Autopilot(ContinueBaseModel):
                         tb_step.step_name, {"output": output, **tb_step.params})
                     await self._run_singular_step(step)
 
-    _highlighted_ranges: List[RangeInFileWithContents] = []
+    _highlighted_ranges: List[HighlightedRangeContext] = []
     _adding_highlighted_code: bool = False
 
+    def _make_sure_is_editing_range(self):
+        """If none of the highlighted ranges are currently being edited, the first should be selected"""
+        if len(self._highlighted_ranges) == 0:
+            return
+        if not any(map(lambda x: x.editing, self._highlighted_ranges)):
+            self._highlighted_ranges[0].editing = True
+
     async def handle_highlighted_code(self, range_in_files: List[RangeInFileWithContents]):
-        if not self._adding_highlighted_code:
+        if not self._adding_highlighted_code and len(self._highlighted_ranges) > 0:
+            return
+
+        # If un-highlighting, then remove the range
+        if len(self._highlighted_ranges) == 1 and len(range_in_files) == 1 and range_in_files[0].range.start == range_in_files[0].range.end:
+            self._highlighted_ranges = []
+            await self.update_subscribers()
             return
 
         # Filter out rifs from ~/.continue/diffs folder
@@ -160,20 +173,25 @@ class Autopilot(ContinueBaseModel):
         for i, rif in enumerate(self._highlighted_ranges):
             found_overlap = False
             for new_rif in range_in_files:
-                if rif.filepath == new_rif.filepath and rif.range.overlaps_with(new_rif.range):
+                if rif.range.filepath == new_rif.filepath and rif.range.range.overlaps_with(new_rif.range):
                     found_overlap = True
                     break
 
                 # Also don't allow multiple ranges in same file with same content. This is useless to the model, and avoids
                 # the bug where cmd+f causes repeated highlights
-                if rif.filepath == new_rif.filepath and rif.contents == new_rif.contents:
+                if rif.range.filepath == new_rif.filepath and rif.range.contents == new_rif.contents:
                     found_overlap = True
                     break
 
             if not found_overlap:
                 new_ranges.append(rif)
 
-        self._highlighted_ranges = new_ranges + range_in_files
+        self._highlighted_ranges = new_ranges + [HighlightedRangeContext(
+            range=rif, editing=False, pinned=False
+        ) for rif in range_in_files]
+
+        self._make_sure_is_editing_range()
+
         await self.update_subscribers()
 
     _step_depth: int = 0
@@ -193,12 +211,25 @@ class Autopilot(ContinueBaseModel):
             if i not in indices:
                 kept_ranges.append(rif)
         self._highlighted_ranges = kept_ranges
+
+        self._make_sure_is_editing_range()
+
         await self.update_subscribers()
 
     async def toggle_adding_highlighted_code(self):
         self._adding_highlighted_code = not self._adding_highlighted_code
         await self.update_subscribers()
 
+    async def set_editing_at_indices(self, indices: List[int]):
+        for i in range(len(self._highlighted_ranges)):
+            self._highlighted_ranges[i].editing = i in indices
+        await self.update_subscribers()
+
+    async def set_pinned_at_indices(self, indices: List[int]):
+        for i in range(len(self._highlighted_ranges)):
+            self._highlighted_ranges[i].pinned = i in indices
+        await self.update_subscribers()
+
     async def _run_singular_step(self, step: "Step", is_future_step: bool = False) -> Coroutine[Observation, None, None]:
         # Allow config to set disallowed steps
         if step.__class__.__name__ in self.continue_sdk.config.disallowed_steps:
@@ -359,6 +390,10 @@ class Autopilot(ContinueBaseModel):
         if len(self._main_user_input_queue) > 1:
             return
 
+        # Remove context unless pinned
+        self._highlighted_ranges = [
+            hr for hr in self._highlighted_ranges if hr.pinned]
+
         # await self._request_halt()
         # Just run the step that takes user input, and
         # then up to the policy to decide how to deal with it.
diff --git a/continuedev/src/continuedev/core/main.py b/continuedev/src/continuedev/core/main.py
index 28fd964e..62cc4936 100644
--- a/continuedev/src/continuedev/core/main.py
+++ b/continuedev/src/continuedev/core/main.py
@@ -199,13 +199,20 @@ class SlashCommandDescription(ContinueBaseModel):
     description: str
 
 
+class HighlightedRangeContext(ContinueBaseModel):
+    """Context for a highlighted range"""
+    range: RangeInFileWithContents
+    editing: bool
+    pinned: bool
+
+
 class FullState(ContinueBaseModel):
     """A full state of the program, including the history"""
     history: History
     active: bool
     user_input_queue: List[str]
     default_model: str
-    highlighted_ranges: List[RangeInFileWithContents]
+    highlighted_ranges: List[HighlightedRangeContext]
     slash_commands: List[SlashCommandDescription]
     adding_highlighted_code: bool
 
diff --git a/continuedev/src/continuedev/models/generate_json_schema.py b/continuedev/src/continuedev/models/generate_json_schema.py
index 080787a5..6cebf429 100644
--- a/continuedev/src/continuedev/models/generate_json_schema.py
+++ b/continuedev/src/continuedev/models/generate_json_schema.py
@@ -1,7 +1,7 @@
 from .main import *
 from .filesystem import RangeInFile, FileEdit
 from .filesystem_edit import FileEditWithFullContents
-from ..core.main import History, HistoryNode
+from ..core.main import History, HistoryNode, FullState
 from pydantic import schema_json_of
 import os
 
@@ -12,7 +12,7 @@ MODELS_TO_GENERATE = [
 ] + [
     FileEditWithFullContents
 ] + [
-    History, HistoryNode
+    History, HistoryNode, FullState
 ]
 
 RENAMES = {
diff --git a/continuedev/src/continuedev/server/gui.py b/continuedev/src/continuedev/server/gui.py
index fa573b37..8e9b1fb9 100644
--- a/continuedev/src/continuedev/server/gui.py
+++ b/continuedev/src/continuedev/server/gui.py
@@ -87,6 +87,10 @@ class GUIProtocolServer(AbstractGUIProtocolServer):
                 self.on_delete_context_at_indices(data["indices"])
             elif message_type == "toggle_adding_highlighted_code":
                 self.on_toggle_adding_highlighted_code()
+            elif message_type == "set_editing_at_indices":
+                self.on_set_editing_at_indices(data["indices"])
+            elif message_type == "set_pinned_at_indices":
+                self.on_set_pinned_at_indices(data["indices"])
         except Exception as e:
             print(e)
 
@@ -135,6 +139,16 @@ class GUIProtocolServer(AbstractGUIProtocolServer):
             self.session.autopilot.toggle_adding_highlighted_code()
         )
 
+    def on_set_editing_at_indices(self, indices: List[int]):
+        asyncio.create_task(
+            self.session.autopilot.set_editing_at_indices(indices)
+        )
+
+    def on_set_pinned_at_indices(self, indices: List[int]):
+        asyncio.create_task(
+            self.session.autopilot.set_pinned_at_indices(indices)
+        )
+
 
 @router.websocket("/ws")
 async def websocket_endpoint(websocket: WebSocket, session: Session = Depends(websocket_session)):
diff --git a/extension/media/Lexend/Lexend-VariableFont_wght.ttf b/extension/media/Lexend/Lexend-VariableFont_wght.ttf
new file mode 100644
index 00000000..b294dc84
Binary files /dev/null and b/extension/media/Lexend/Lexend-VariableFont_wght.ttf differ
diff --git a/extension/media/Lexend/OFL.txt b/extension/media/Lexend/OFL.txt
new file mode 100644
index 00000000..6b679248
--- /dev/null
+++ b/extension/media/Lexend/OFL.txt
@@ -0,0 +1,93 @@
+Copyright 2018 The Lexend Project Authors (https://github.com/googlefonts/lexend), with Reserved Font Name “RevReading Lexend”.
+
+This Font Software is licensed under the SIL Open Font License, Version 1.1.
+This license is copied below, and is also available with a FAQ at:
+http://scripts.sil.org/OFL
+
+
+-----------------------------------------------------------
+SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
+-----------------------------------------------------------
+
+PREAMBLE
+The goals of the Open Font License (OFL) are to stimulate worldwide
+development of collaborative font projects, to support the font creation
+efforts of academic and linguistic communities, and to provide a free and
+open framework in which fonts may be shared and improved in partnership
+with others.
+
+The OFL allows the licensed fonts to be used, studied, modified and
+redistributed freely as long as they are not sold by themselves. The
+fonts, including any derivative works, can be bundled, embedded, 
+redistributed and/or sold with any software provided that any reserved
+names are not used by derivative works. The fonts and derivatives,
+however, cannot be released under any other type of license. The
+requirement for fonts to remain under this license does not apply
+to any document created using the fonts or their derivatives.
+
+DEFINITIONS
+"Font Software" refers to the set of files released by the Copyright
+Holder(s) under this license and clearly marked as such. This may
+include source files, build scripts and documentation.
+
+"Reserved Font Name" refers to any names specified as such after the
+copyright statement(s).
+
+"Original Version" refers to the collection of Font Software components as
+distributed by the Copyright Holder(s).
+
+"Modified Version" refers to any derivative made by adding to, deleting,
+or substituting -- in part or in whole -- any of the components of the
+Original Version, by changing formats or by porting the Font Software to a
+new environment.
+
+"Author" refers to any designer, engineer, programmer, technical
+writer or other person who contributed to the Font Software.
+
+PERMISSION & CONDITIONS
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of the Font Software, to use, study, copy, merge, embed, modify,
+redistribute, and sell modified and unmodified copies of the Font
+Software, subject to the following conditions:
+
+1) Neither the Font Software nor any of its individual components,
+in Original or Modified Versions, may be sold by itself.
+
+2) Original or Modified Versions of the Font Software may be bundled,
+redistributed and/or sold with any software, provided that each copy
+contains the above copyright notice and this license. These can be
+included either as stand-alone text files, human-readable headers or
+in the appropriate machine-readable metadata fields within text or
+binary files as long as those fields can be easily viewed by the user.
+
+3) No Modified Version of the Font Software may use the Reserved Font
+Name(s) unless explicit written permission is granted by the corresponding
+Copyright Holder. This restriction only applies to the primary font name as
+presented to the users.
+
+4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
+Software shall not be used to promote, endorse or advertise any
+Modified Version, except to acknowledge the contribution(s) of the
+Copyright Holder(s) and the Author(s) or with their explicit written
+permission.
+
+5) The Font Software, modified or unmodified, in part or in whole,
+must be distributed entirely under this license, and must not be
+distributed under any other license. The requirement for fonts to
+remain under this license does not apply to any document created
+using the Font Software.
+
+TERMINATION
+This license becomes null and void if any of the above conditions are
+not met.
+
+DISCLAIMER
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
+COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
+DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
+OTHER DEALINGS IN THE FONT SOFTWARE.
diff --git a/extension/media/Lexend/README.txt b/extension/media/Lexend/README.txt
new file mode 100644
index 00000000..f2966dfe
--- /dev/null
+++ b/extension/media/Lexend/README.txt
@@ -0,0 +1,71 @@
+Lexend Variable Font
+====================
+
+This download contains Lexend as both a variable font and static fonts.
+
+Lexend is a variable font with this axis:
+  wght
+
+This means all the styles are contained in a single file:
+  Lexend-VariableFont_wght.ttf
+
+If your app fully supports variable fonts, you can now pick intermediate styles
+that aren’t available as static fonts. Not all apps support variable fonts, and
+in those cases you can use the static font files for Lexend:
+  static/Lexend-Thin.ttf
+  static/Lexend-ExtraLight.ttf
+  static/Lexend-Light.ttf
+  static/Lexend-Regular.ttf
+  static/Lexend-Medium.ttf
+  static/Lexend-SemiBold.ttf
+  static/Lexend-Bold.ttf
+  static/Lexend-ExtraBold.ttf
+  static/Lexend-Black.ttf
+
+Get started
+-----------
+
+1. Install the font files you want to use
+
+2. Use your app's font picker to view the font family and all the
+available styles
+
+Learn more about variable fonts
+-------------------------------
+
+  https://developers.google.com/web/fundamentals/design-and-ux/typography/variable-fonts
+  https://variablefonts.typenetwork.com
+  https://medium.com/variable-fonts
+
+In desktop apps
+
+  https://theblog.adobe.com/can-variable-fonts-illustrator-cc
+  https://helpx.adobe.com/nz/photoshop/using/fonts.html#variable_fonts
+
+Online
+
+  https://developers.google.com/fonts/docs/getting_started
+  https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Fonts/Variable_Fonts_Guide
+  https://developer.microsoft.com/en-us/microsoft-edge/testdrive/demos/variable-fonts
+
+Installing fonts
+
+  MacOS: https://support.apple.com/en-us/HT201749
+  Linux: https://www.google.com/search?q=how+to+install+a+font+on+gnu%2Blinux
+  Windows: https://support.microsoft.com/en-us/help/314960/how-to-install-or-remove-a-font-in-windows
+
+Android Apps
+
+  https://developers.google.com/fonts/docs/android
+  https://developer.android.com/guide/topics/ui/look-and-feel/downloadable-fonts
+
+License
+-------
+Please read the full license text (OFL.txt) to understand the permissions,
+restrictions and requirements for usage, redistribution, and modification.
+
+You can use them in your products & projects – print or digital,
+commercial or otherwise.
+
+This isn't legal advice, please consider consulting a lawyer and see the full
+license for all details.
diff --git a/extension/media/Lexend/static/Lexend-Black.ttf b/extension/media/Lexend/static/Lexend-Black.ttf
new file mode 100644
index 00000000..2fea087c
Binary files /dev/null and b/extension/media/Lexend/static/Lexend-Black.ttf differ
diff --git a/extension/media/Lexend/static/Lexend-Bold.ttf b/extension/media/Lexend/static/Lexend-Bold.ttf
new file mode 100644
index 00000000..95884f6e
Binary files /dev/null and b/extension/media/Lexend/static/Lexend-Bold.ttf differ
diff --git a/extension/media/Lexend/static/Lexend-ExtraBold.ttf b/extension/media/Lexend/static/Lexend-ExtraBold.ttf
new file mode 100644
index 00000000..02f84ed3
Binary files /dev/null and b/extension/media/Lexend/static/Lexend-ExtraBold.ttf differ
diff --git a/extension/media/Lexend/static/Lexend-ExtraLight.ttf b/extension/media/Lexend/static/Lexend-ExtraLight.ttf
new file mode 100644
index 00000000..20e7068d
Binary files /dev/null and b/extension/media/Lexend/static/Lexend-ExtraLight.ttf differ
diff --git a/extension/media/Lexend/static/Lexend-Light.ttf b/extension/media/Lexend/static/Lexend-Light.ttf
new file mode 100644
index 00000000..fb6d097c
Binary files /dev/null and b/extension/media/Lexend/static/Lexend-Light.ttf differ
diff --git a/extension/media/Lexend/static/Lexend-Medium.ttf b/extension/media/Lexend/static/Lexend-Medium.ttf
new file mode 100644
index 00000000..d91a8673
Binary files /dev/null and b/extension/media/Lexend/static/Lexend-Medium.ttf differ
diff --git a/extension/media/Lexend/static/Lexend-Regular.ttf b/extension/media/Lexend/static/Lexend-Regular.ttf
new file mode 100644
index 00000000..b423d3ab
Binary files /dev/null and b/extension/media/Lexend/static/Lexend-Regular.ttf differ
diff --git a/extension/media/Lexend/static/Lexend-SemiBold.ttf b/extension/media/Lexend/static/Lexend-SemiBold.ttf
new file mode 100644
index 00000000..9dcb8214
Binary files /dev/null and b/extension/media/Lexend/static/Lexend-SemiBold.ttf differ
diff --git a/extension/media/Lexend/static/Lexend-Thin.ttf b/extension/media/Lexend/static/Lexend-Thin.ttf
new file mode 100644
index 00000000..0d7df881
Binary files /dev/null and b/extension/media/Lexend/static/Lexend-Thin.ttf differ
diff --git a/extension/react-app/package-lock.json b/extension/react-app/package-lock.json
index fb13dffd..7316581d 100644
--- a/extension/react-app/package-lock.json
+++ b/extension/react-app/package-lock.json
@@ -20,6 +20,7 @@
         "react-redux": "^8.0.5",
         "react-switch": "^7.0.0",
         "react-syntax-highlighter": "^15.5.0",
+        "react-tooltip": "^5.18.0",
         "styled-components": "^5.3.6",
         "vscode-webview": "^1.0.1-beta.1"
       },
@@ -597,6 +598,19 @@
         "node": ">=12"
       }
     },
+    "node_modules/@floating-ui/core": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.3.1.tgz",
+      "integrity": "sha512-Bu+AMaXNjrpjh41znzHqaz3r2Nr8hHuHZT6V2LBKMhyMl0FgKA62PNYbqnfgmzOhoWZj70Zecisbo4H1rotP5g=="
+    },
+    "node_modules/@floating-ui/dom": {
+      "version": "1.4.4",
+      "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.4.4.tgz",
+      "integrity": "sha512-21hhDEPOiWkGp0Ys4Wi6Neriah7HweToKra626CIK712B5m9qkdz54OP9gVldUg+URnBTpv/j/bi/skmGdstXQ==",
+      "dependencies": {
+        "@floating-ui/core": "^1.3.1"
+      }
+    },
     "node_modules/@jridgewell/gen-mapping": {
       "version": "0.3.2",
       "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz",
@@ -1310,6 +1324,11 @@
         "node": ">= 6"
       }
     },
+    "node_modules/classnames": {
+      "version": "2.3.2",
+      "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.2.tgz",
+      "integrity": "sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw=="
+    },
     "node_modules/color-convert": {
       "version": "1.9.3",
       "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
@@ -2967,6 +2986,19 @@
         "react": ">= 0.14.0"
       }
     },
+    "node_modules/react-tooltip": {
+      "version": "5.18.0",
+      "resolved": "https://registry.npmjs.org/react-tooltip/-/react-tooltip-5.18.0.tgz",
+      "integrity": "sha512-qjDK/skUJJ27sc9lTWeNxp2rLzmenBTskSsRiDOCPnupGSz2GhL5IZxDizK/sOsk0hn5iSCywt+3jKxUJ3Y4Sw==",
+      "dependencies": {
+        "@floating-ui/dom": "^1.0.0",
+        "classnames": "^2.3.0"
+      },
+      "peerDependencies": {
+        "react": ">=16.14.0",
+        "react-dom": ">=16.14.0"
+      }
+    },
     "node_modules/read-cache": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
@@ -3886,6 +3918,19 @@
       "dev": true,
       "optional": true
     },
+    "@floating-ui/core": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.3.1.tgz",
+      "integrity": "sha512-Bu+AMaXNjrpjh41znzHqaz3r2Nr8hHuHZT6V2LBKMhyMl0FgKA62PNYbqnfgmzOhoWZj70Zecisbo4H1rotP5g=="
+    },
+    "@floating-ui/dom": {
+      "version": "1.4.4",
+      "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.4.4.tgz",
+      "integrity": "sha512-21hhDEPOiWkGp0Ys4Wi6Neriah7HweToKra626CIK712B5m9qkdz54OP9gVldUg+URnBTpv/j/bi/skmGdstXQ==",
+      "requires": {
+        "@floating-ui/core": "^1.3.1"
+      }
+    },
     "@jridgewell/gen-mapping": {
       "version": "0.3.2",
       "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz",
@@ -4350,6 +4395,11 @@
         }
       }
     },
+    "classnames": {
+      "version": "2.3.2",
+      "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.2.tgz",
+      "integrity": "sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw=="
+    },
     "color-convert": {
       "version": "1.9.3",
       "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
@@ -5411,6 +5461,15 @@
         "refractor": "^3.6.0"
       }
     },
+    "react-tooltip": {
+      "version": "5.18.0",
+      "resolved": "https://registry.npmjs.org/react-tooltip/-/react-tooltip-5.18.0.tgz",
+      "integrity": "sha512-qjDK/skUJJ27sc9lTWeNxp2rLzmenBTskSsRiDOCPnupGSz2GhL5IZxDizK/sOsk0hn5iSCywt+3jKxUJ3Y4Sw==",
+      "requires": {
+        "@floating-ui/dom": "^1.0.0",
+        "classnames": "^2.3.0"
+      }
+    },
     "read-cache": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
diff --git a/extension/react-app/package.json b/extension/react-app/package.json
index 12701906..4bedb813 100644
--- a/extension/react-app/package.json
+++ b/extension/react-app/package.json
@@ -21,6 +21,7 @@
     "react-redux": "^8.0.5",
     "react-switch": "^7.0.0",
     "react-syntax-highlighter": "^15.5.0",
+    "react-tooltip": "^5.18.0",
     "styled-components": "^5.3.6",
     "vscode-webview": "^1.0.1-beta.1"
   },
diff --git a/extension/react-app/src/App.tsx b/extension/react-app/src/App.tsx
index a51541d0..8785f88f 100644
--- a/extension/react-app/src/App.tsx
+++ b/extension/react-app/src/App.tsx
@@ -1,28 +1,33 @@
 import DebugPanel from "./components/DebugPanel";
 import MainTab from "./tabs/main";
-import { Provider } from "react-redux";
-import store from "./redux/store";
 import WelcomeTab from "./tabs/welcome";
 import ChatTab from "./tabs/chat";
 import GUI from "./tabs/gui";
+import { createContext } from "react";
+import useContinueGUIProtocol from "./hooks/useWebsocket";
+import ContinueGUIClientProtocol from "./hooks/useContinueGUIProtocol";
+
+export const GUIClientContext = createContext<
+  ContinueGUIClientProtocol | undefined
+>(undefined);
 
 function App() {
+  const client = useContinueGUIProtocol();
+
   return (
-    <>
-      <Provider store={store}>
-        <DebugPanel
-          tabs={[
-            {
-              element: <GUI />,
-              title: "GUI",
-            },
-            // { element: <MainTab />, title: "Debug Panel" },
-            // { element: <WelcomeTab />, title: "Welcome" },
-            // { element: <ChatTab />, title: "Chat" },
-          ]}
-        ></DebugPanel>
-      </Provider>
-    </>
+    <GUIClientContext.Provider value={client}>
+      <DebugPanel
+        tabs={[
+          {
+            element: <GUI />,
+            title: "GUI",
+          },
+          // { element: <MainTab />, title: "Debug Panel" },
+          // { element: <WelcomeTab />, title: "Welcome" },
+          // { element: <ChatTab />, title: "Chat" },
+        ]}
+      />
+    </GUIClientContext.Provider>
   );
 }
 
diff --git a/extension/react-app/src/components/CodeBlock.tsx b/extension/react-app/src/components/CodeBlock.tsx
index 17f5626b..fe9b3a95 100644
--- a/extension/react-app/src/components/CodeBlock.tsx
+++ b/extension/react-app/src/components/CodeBlock.tsx
@@ -52,9 +52,9 @@ function CopyButton(props: { textToCopy: string; visible: boolean }) {
         }}
       >
         {clicked ? (
-          <CheckCircle color="#00ff00" size="1.4em" />
+          <CheckCircle color="#00ff00" size="1.5em" />
         ) : (
-          <Clipboard color={hovered ? "#00ff00" : "white"} size="1.4em" />
+          <Clipboard color={hovered ? "#00ff00" : "white"} size="1.5em" />
         )}
       </StyledCopyButton>
     </>
diff --git a/extension/react-app/src/components/ComboBox.tsx b/extension/react-app/src/components/ComboBox.tsx
index 81b148b9..7ee5dc24 100644
--- a/extension/react-app/src/components/ComboBox.tsx
+++ b/extension/react-app/src/components/ComboBox.tsx
@@ -4,6 +4,7 @@ import styled from "styled-components";
 import {
   buttonColor,
   defaultBorderRadius,
+  lightGray,
   secondaryDark,
   vscBackground,
 } from ".";
@@ -16,11 +17,32 @@ import {
   LockClosed,
   LockOpen,
   Plus,
+  DocumentPlus,
 } from "@styled-icons/heroicons-outline";
+import { HighlightedRangeContext } from "../../../schema/FullState";
 
 // #region styled components
 const mainInputFontSize = 16;
 
+const EmptyPillDiv = styled.div`
+  padding: 8px;
+  border-radius: ${defaultBorderRadius};
+  border: 1px dashed ${lightGray};
+  color: ${lightGray};
+  background-color: ${vscBackground};
+  overflow: hidden;
+  display: flex;
+  align-items: center;
+  text-align: center;
+  cursor: pointer;
+  font-size: 13px;
+
+  &:hover {
+    background-color: ${lightGray};
+    color: ${vscBackground};
+  }
+`;
+
 const ContextDropdown = styled.div`
   position: absolute;
   padding: 4px;
@@ -41,17 +63,19 @@ const MainTextInput = styled.textarea`
 
   padding: 8px;
   font-size: ${mainInputFontSize}px;
+  font-family: inherit;
+  border: 1px solid transparent;
   border-radius: ${defaultBorderRadius};
-  border: 1px solid white;
   margin: 8px auto;
+  height: auto;
   width: 100%;
-  background-color: ${vscBackground};
+  background-color: ${secondaryDark};
   color: white;
   z-index: 1;
 
   &:focus {
+    outline: 1px solid #ff000066;
     border: 1px solid transparent;
-    outline: 1px solid orange;
   }
 `;
 
@@ -69,7 +93,6 @@ const Ul = styled.ul<{
   background: ${vscBackground};
   background-color: ${secondaryDark};
   color: white;
-  font-family: "Fira Code", monospace;
   max-height: ${UlMaxHeight}px;
   overflow: scroll;
   padding: 0;
@@ -102,7 +125,7 @@ interface ComboBoxProps {
   onInputValueChange: (inputValue: string) => void;
   disabled?: boolean;
   onEnter: (e: React.KeyboardEvent<HTMLInputElement>) => void;
-  highlightedCodeSections: (RangeInFile & { contents: string })[];
+  highlightedCodeSections: HighlightedRangeContext[];
   deleteContextItems: (indices: number[]) => void;
   onTogglePin: () => void;
   onToggleAddContext: () => void;
@@ -119,16 +142,7 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
     React.useState(false);
   const [pinned, setPinned] = useState(false);
   const [highlightedCodeSections, setHighlightedCodeSections] = React.useState(
-    props.highlightedCodeSections || [
-      {
-        filepath: "test.ts",
-        range: {
-          start: { line: 0, character: 0 },
-          end: { line: 0, character: 0 },
-        },
-        contents: "import * as a from 'a';",
-      },
-    ]
+    props.highlightedCodeSections || []
   );
 
   useEffect(() => {
@@ -169,6 +183,71 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
 
   return (
     <>
+      <div className="px-2 flex gap-2 items-center flex-wrap mt-2">
+        {highlightedCodeSections.length > 1 && (
+          <>
+            <HeaderButtonWithText
+              text="Clear Context"
+              onClick={() => {
+                props.deleteContextItems(
+                  highlightedCodeSections.map((_, idx) => idx)
+                );
+              }}
+            >
+              <Trash size="1.6em" />
+            </HeaderButtonWithText>
+          </>
+        )}
+        {highlightedCodeSections.map((section, idx) => (
+          <PillButton
+            editing={section.editing}
+            pinned={section.pinned}
+            index={idx}
+            key={`${section.filepath}${idx}`}
+            title={`${section.range.filepath} (${
+              section.range.range.start.line + 1
+            }-${section.range.range.end.line + 1})`}
+            onDelete={() => {
+              if (props.deleteContextItems) {
+                props.deleteContextItems([idx]);
+              }
+              setHighlightedCodeSections((prev) => {
+                const newSections = [...prev];
+                newSections.splice(idx, 1);
+                return newSections;
+              });
+            }}
+            onHover={(val: boolean) => {
+              if (val) {
+                setHoveringButton(val);
+              } else {
+                setTimeout(() => {
+                  setHoveringButton(val);
+                }, 100);
+              }
+            }}
+          />
+        ))}
+        {props.highlightedCodeSections.length > 0 &&
+          (props.addingHighlightedCode ? (
+            <EmptyPillDiv
+              onClick={() => {
+                props.onToggleAddContext();
+              }}
+            >
+              Highlight to Add Context
+            </EmptyPillDiv>
+          ) : (
+            <HeaderButtonWithText
+              text="Add to Context"
+              onClick={() => {
+                props.onToggleAddContext();
+              }}
+            >
+              <DocumentPlus width="1.6em"></DocumentPlus>
+            </HeaderButtonWithText>
+          ))}
+      </div>
       <div className="flex px-2" ref={divRef} hidden={!isOpen}>
         <MainTextInput
           disabled={props.disabled}
@@ -260,80 +339,10 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
             ))}
         </Ul>
       </div>
-      <div className="px-2 flex gap-2 items-center flex-wrap">
-        {highlightedCodeSections.length === 0 && (
-          <HeaderButtonWithText
-            text={
-              props.addingHighlightedCode ? "Adding Context" : "Add Context"
-            }
-            onClick={() => {
-              props.onToggleAddContext();
-            }}
-            inverted={props.addingHighlightedCode}
-          >
-            <Plus size="1.6em" />
-          </HeaderButtonWithText>
-        )}
-        {highlightedCodeSections.length > 0 && (
-          <>
-            <HeaderButtonWithText
-              text="Clear Context"
-              onClick={() => {
-                props.deleteContextItems(
-                  highlightedCodeSections.map((_, idx) => idx)
-                );
-              }}
-            >
-              <Trash size="1.6em" />
-            </HeaderButtonWithText>
-            <HeaderButtonWithText
-              text={pinned ? "Unpin Context" : "Pin Context"}
-              inverted={pinned}
-              onClick={() => {
-                setPinned((prev) => !prev);
-                props.onTogglePin();
-              }}
-            >
-              {pinned ? (
-                <LockClosed size="1.6em"></LockClosed>
-              ) : (
-                <LockOpen size="1.6em"></LockOpen>
-              )}
-            </HeaderButtonWithText>
-          </>
-        )}
-        {highlightedCodeSections.map((section, idx) => (
-          <PillButton
-            title={`${section.filepath} (${section.range.start.line + 1}-${
-              section.range.end.line + 1
-            })`}
-            onDelete={() => {
-              if (props.deleteContextItems) {
-                props.deleteContextItems([idx]);
-              }
-              setHighlightedCodeSections((prev) => {
-                const newSections = [...prev];
-                newSections.splice(idx, 1);
-                return newSections;
-              });
-            }}
-            onHover={(val: boolean) => {
-              if (val) {
-                setHoveringButton(val);
-              } else {
-                setTimeout(() => {
-                  setHoveringButton(val);
-                }, 100);
-              }
-            }}
-          />
-        ))}
-
-        <span className="text-trueGray-400 ml-auto mr-4 text-xs text-right">
-          Highlight code to include as context. Currently open file included by
-          default. {highlightedCodeSections.length === 0 && ""}
-        </span>
-      </div>
+      {/* <span className="text-trueGray-400 ml-auto m-auto text-xs text-right">
+        Highlight code to include as context. Currently open file included by
+        default. {highlightedCodeSections.length === 0 && ""}
+      </span> */}
       <ContextDropdown
         onMouseEnter={() => {
           setHoveringContextDropdown(true);
@@ -345,9 +354,9 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
       >
         {highlightedCodeSections.map((section, idx) => (
           <>
-            <p>{section.filepath}</p>
+            <p>{section.range.filepath}</p>
             <CodeBlock showCopy={false} key={idx}>
-              {section.contents}
+              {section.range.contents}
             </CodeBlock>
           </>
         ))}
diff --git a/extension/react-app/src/components/ContinueButton.tsx b/extension/react-app/src/components/ContinueButton.tsx
index 5295799a..462f2b46 100644
--- a/extension/react-app/src/components/ContinueButton.tsx
+++ b/extension/react-app/src/components/ContinueButton.tsx
@@ -18,7 +18,7 @@ let StyledButton = styled(Button)`
 
   &:hover {
     transition-delay: 0.5s;
-    transition-property: background;
+    transition-property: "background";
     background: linear-gradient(
       45deg,
       #be1a55 14.44%,
diff --git a/extension/react-app/src/components/HeaderButtonWithText.tsx b/extension/react-app/src/components/HeaderButtonWithText.tsx
index 72a653c5..de8e3c98 100644
--- a/extension/react-app/src/components/HeaderButtonWithText.tsx
+++ b/extension/react-app/src/components/HeaderButtonWithText.tsx
@@ -1,6 +1,7 @@
 import React, { useState } from "react";
-
-import { HeaderButton } from ".";
+import { Tooltip } from "react-tooltip";
+import styled from "styled-components";
+import { HeaderButton, StyledTooltip, defaultBorderRadius } from ".";
 
 interface HeaderButtonWithTextProps {
   text: string;
@@ -13,25 +14,28 @@ interface HeaderButtonWithTextProps {
 
 const HeaderButtonWithText = (props: HeaderButtonWithTextProps) => {
   const [hover, setHover] = useState(false);
-  const paddingLeft = (props.disabled ? (props.active ?  "3px" : "1px"): (hover ? "4px" : "1px"));
   return (
-    <HeaderButton
-      inverted={props.inverted}
-      disabled={props.disabled}
-      style={{ padding: (props.active ?  "3px" : "1px"), paddingLeft, borderRadius: (props.active ?  "50%" : undefined) }}
-      onMouseEnter={() => {
-        if (!props.disabled) {
-          setHover(true);
-        }
-      }}
-      onMouseLeave={() => {
-        setHover(false);
-      }}
-      onClick={props.onClick}
-    >
-      <span hidden={!hover}>{props.text}</span>
-      {props.children}
-    </HeaderButton>
+    <>
+      <HeaderButton
+        data-tooltip-id={`header_button_${props.text}`}
+        inverted={props.inverted}
+        disabled={props.disabled}
+        onMouseEnter={() => {
+          if (!props.disabled) {
+            setHover(true);
+          }
+        }}
+        onMouseLeave={() => {
+          setHover(false);
+        }}
+        onClick={props.onClick}
+      >
+        {props.children}
+      </HeaderButton>
+      <StyledTooltip id={`header_button_${props.text}`} place="bottom">
+        {props.text}
+      </StyledTooltip>
+    </>
   );
 };
 
diff --git a/extension/react-app/src/components/Loader.tsx b/extension/react-app/src/components/Loader.tsx
new file mode 100644
index 00000000..90eff793
--- /dev/null
+++ b/extension/react-app/src/components/Loader.tsx
@@ -0,0 +1,40 @@
+import { Play } from "@styled-icons/heroicons-outline";
+import { useSelector } from "react-redux";
+import styled from "styled-components";
+import { RootStore } from "../redux/store";
+
+const DEFAULT_SIZE = "28px";
+
+const FlashingDiv = styled.div`
+  margin: auto;
+  width: ${DEFAULT_SIZE};
+  animation: flash 1.2s infinite ease-in-out;
+  @keyframes flash {
+    0% {
+      opacity: 0.4;
+    }
+    50% {
+      opacity: 1;
+    }
+    100% {
+      opacity: 0.4;
+    }
+  }
+`;
+
+function Loader(props: { size?: string }) {
+  const vscMediaUrl = useSelector(
+    (state: RootStore) => state.config.vscMediaUrl
+  );
+  return (
+    <FlashingDiv>
+      {vscMediaUrl ? (
+        <img src={`${vscMediaUrl}/play_button.png`} width="22px" />
+      ) : (
+        <Play width={props.size || DEFAULT_SIZE} />
+      )}
+    </FlashingDiv>
+  );
+}
+
+export default Loader;
diff --git a/extension/react-app/src/components/PillButton.tsx b/extension/react-app/src/components/PillButton.tsx
index 5a02c6b2..a384832e 100644
--- a/extension/react-app/src/components/PillButton.tsx
+++ b/extension/react-app/src/components/PillButton.tsx
@@ -1,54 +1,136 @@
-import { useState } from "react";
+import { useContext, useState } from "react";
 import styled from "styled-components";
-import { defaultBorderRadius } from ".";
-import { XMark } from "@styled-icons/heroicons-outline";
+import {
+  StyledTooltip,
+  defaultBorderRadius,
+  lightGray,
+  secondaryDark,
+} from ".";
+import { Trash, PaintBrush, MapPin } from "@styled-icons/heroicons-outline";
+import { GUIClientContext } from "../App";
 
 const Button = styled.button`
   border: none;
   color: white;
-  background-color: transparent;
-  border: 1px solid white;
+  background-color: ${secondaryDark};
   border-radius: ${defaultBorderRadius};
-  padding: 3px 6px;
+  padding: 8px;
+  overflow: hidden;
+
+  cursor: pointer;
+`;
+
+const GridDiv = styled.div`
+  position: absolute;
+  left: 0px;
+  top: 0px;
+  width: 100%;
+  height: 100%;
+  display: grid;
+  grid-gap: 0;
+  grid-template-columns: 1fr 1fr;
+  align-items: center;
+  border-radius: ${defaultBorderRadius};
+  overflow: hidden;
+
+  background-color: ${secondaryDark};
+`;
+
+const ButtonDiv = styled.div<{ backgroundColor: string }>`
+  background-color: ${secondaryDark};
+  padding: 3px;
+  height: 100%;
+  display: flex;
+  align-items: center;
 
   &:hover {
-    background-color: white;
-    color: black;
+    background-color: ${(props) => props.backgroundColor};
   }
-
-  cursor: pointer;
 `;
 
 interface PillButtonProps {
   onHover?: (arg0: boolean) => void;
   onDelete?: () => void;
   title: string;
+  index: number;
+  editing: boolean;
+  pinned: boolean;
 }
 
 const PillButton = (props: PillButtonProps) => {
   const [isHovered, setIsHovered] = useState(false);
+  const client = useContext(GUIClientContext);
+
   return (
-    <Button
-      onMouseEnter={() => {
-        setIsHovered(true);
-        if (props.onHover) {
-          props.onHover(true);
-        }
-      }}
-      onMouseLeave={() => {
-        setIsHovered(false);
-        if (props.onHover) {
-          props.onHover(false);
-        }
-      }}
-      onClick={() => {
-        if (props.onDelete) {
-          props.onDelete();
-        }
-      }}
-    >
-      {props.title}
-    </Button>
+    <>
+      <Button
+        style={{
+          position: "relative",
+          borderColor: props.editing
+            ? "#8800aa"
+            : props.pinned
+            ? "#ffff0099"
+            : "transparent",
+          borderWidth: "1px",
+          borderStyle: "solid",
+        }}
+        onMouseEnter={() => {
+          setIsHovered(true);
+          if (props.onHover) {
+            props.onHover(true);
+          }
+        }}
+        onMouseLeave={() => {
+          setIsHovered(false);
+          if (props.onHover) {
+            props.onHover(false);
+          }
+        }}
+      >
+        {isHovered && (
+          <GridDiv>
+            <ButtonDiv
+              data-tooltip-id={`edit-${props.index}`}
+              backgroundColor={"#8800aa55"}
+              onClick={() => {
+                client?.setEditingAtIndices([props.index]);
+              }}
+            >
+              <PaintBrush style={{ margin: "auto" }} width="1.6em"></PaintBrush>
+            </ButtonDiv>
+
+            {/* <ButtonDiv
+            data-tooltip-id={`pin-${props.index}`}
+            backgroundColor={"#ffff0055"}
+            onClick={() => {
+              client?.setPinnedAtIndices([props.index]);
+            }}
+          >
+            <MapPin style={{ margin: "auto" }} width="1.6em"></MapPin>
+          </ButtonDiv> */}
+            <StyledTooltip id={`pin-${props.index}`}>
+              Edit this range
+            </StyledTooltip>
+            <ButtonDiv
+              data-tooltip-id={`delete-${props.index}`}
+              backgroundColor={"#cc000055"}
+              onClick={() => {
+                if (props.onDelete) {
+                  props.onDelete();
+                }
+              }}
+            >
+              <Trash style={{ margin: "auto" }} width="1.6em"></Trash>
+            </ButtonDiv>
+          </GridDiv>
+        )}
+        {props.title}
+      </Button>
+      <StyledTooltip id={`edit-${props.index}`}>
+        {props.editing ? "Editing this range" : "Edit this range"}
+      </StyledTooltip>
+      <StyledTooltip id={`delete-${props.index}`}>Delete</StyledTooltip>
+    </>
   );
 };
 
diff --git a/extension/react-app/src/components/StepContainer.tsx b/extension/react-app/src/components/StepContainer.tsx
index 2aed2e72..91d7b8ef 100644
--- a/extension/react-app/src/components/StepContainer.tsx
+++ b/extension/react-app/src/components/StepContainer.tsx
@@ -13,7 +13,7 @@ import {
   ArrowPath,
   XMark,
 } from "@styled-icons/heroicons-outline";
-import { Stop } from "@styled-icons/heroicons-solid";
+import { StopCircle } from "@styled-icons/heroicons-solid";
 import { HistoryNode } from "../../../schema/HistoryNode";
 import ReactMarkdown from "react-markdown";
 import HeaderButtonWithText from "./HeaderButtonWithText";
@@ -67,7 +67,6 @@ const HeaderDiv = styled.div<{ error: boolean; loading: boolean }>`
 
 const ContentDiv = styled.div<{ isUserInput: boolean }>`
   padding: 8px;
-  padding-left: 16px;
   background-color: ${(props) =>
     props.isUserInput ? secondaryDark : vscBackground};
   font-size: 13px;
@@ -167,7 +166,7 @@ function StepContainer(props: StepContainerProps) {
               ? "#f00"
               : props.historyNode.active
               ? undefined
-              : "white"
+              : "transparent"
           }
           className="overflow-hidden cursor-pointer"
           onClick={(e) => {
@@ -182,7 +181,7 @@ function StepContainer(props: StepContainerProps) {
             loading={props.historyNode.active as boolean | false}
             error={props.historyNode.observation?.error ? true : false}
           >
-            <h4 className="m-2">
+            <div className="m-2">
               {!isUserInput &&
                 (props.open ? (
                   <ChevronDown size="1.4em" />
@@ -191,7 +190,7 @@ function StepContainer(props: StepContainerProps) {
                 ))}
               {props.historyNode.observation?.title ||
                 (props.historyNode.step.name as any)}
-            </h4>
+            </div>
             {/* <HeaderButton
               onClick={(e) => {
                 e.stopPropagation();
@@ -203,16 +202,14 @@ function StepContainer(props: StepContainerProps) {
 
             <>
               <HeaderButtonWithText
-                disabled={props.historyNode.active as boolean}
                 onClick={(e) => {
                   e.stopPropagation();
                   props.onDelete();
                 }}
                 text={props.historyNode.active ? "Stop" : "Delete"}
-                active={props.historyNode.active}
               >
                 {props.historyNode.active ? (
-                  <Stop size="1.2em" onClick={props.onDelete} />
+                  <StopCircle size="1.6em" onClick={props.onDelete} />
                 ) : (
                   <XMark size="1.6em" onClick={props.onDelete} />
                 )}
diff --git a/extension/react-app/src/components/TextDialog.tsx b/extension/react-app/src/components/TextDialog.tsx
index a564f884..ea5727f0 100644
--- a/extension/react-app/src/components/TextDialog.tsx
+++ b/extension/react-app/src/components/TextDialog.tsx
@@ -8,6 +8,7 @@ const ScreenCover = styled.div`
   width: 100%;
   height: 100%;
   background-color: rgba(168, 168, 168, 0.5);
+  z-index: 100;
 `;
 
 const DialogContainer = styled.div`
@@ -35,7 +36,6 @@ const TextArea = styled.textarea`
   border-radius: 8px;
   padding: 8px;
   outline: 1px solid black;
-  font-family: Arial, Helvetica, sans-serif;
   resize: none;
 
   &:focus {
diff --git a/extension/react-app/src/components/UserInputContainer.tsx b/extension/react-app/src/components/UserInputContainer.tsx
index 28437d35..f51f0cb5 100644
--- a/extension/react-app/src/components/UserInputContainer.tsx
+++ b/extension/react-app/src/components/UserInputContainer.tsx
@@ -15,12 +15,10 @@ interface UserInputContainerProps {
 }
 
 const StyledDiv = styled.div`
-  background-color: rgb(45 45 45);
+  background-color: ${secondaryDark};
   padding: 8px;
   padding-left: 16px;
   padding-right: 16px;
-  border-bottom: 1px solid white;
-  border-top: 1px solid white;
   font-size: 13px;
   display: flex;
   align-items: center;
@@ -29,7 +27,7 @@ const StyledDiv = styled.div`
 const UserInputContainer = (props: UserInputContainerProps) => {
   return (
     <StyledDiv>
-      <b>{props.children}</b>
+      {props.children}
       <div style={{ marginLeft: "auto" }}>
         <HeaderButtonWithText
           onClick={(e) => {
diff --git a/extension/react-app/src/components/index.ts b/extension/react-app/src/components/index.ts
index db1925ed..9ae0f097 100644
--- a/extension/react-app/src/components/index.ts
+++ b/extension/react-app/src/components/index.ts
@@ -1,7 +1,9 @@
+import { Tooltip } from "react-tooltip";
 import styled, { keyframes } from "styled-components";
 
 export const defaultBorderRadius = "5px";
-export const secondaryDark = "rgb(42 42 42)";
+export const lightGray = "rgb(100 100 100)";
+export const secondaryDark = "rgb(45 45 45)";
 export const vscBackground = "rgb(30 30 30)";
 export const vscBackgroundTransparent = "#1e1e1ede";
 export const buttonColor = "rgb(113 28 59)";
@@ -26,6 +28,16 @@ export const Button = styled.button`
   }
 `;
 
+export const StyledTooltip = styled(Tooltip)`
+  font-size: 12px;
+  background-color: rgb(60 60 60);
+  border-radius: ${defaultBorderRadius};
+  padding: 6px;
+  padding-left: 12px;
+  padding-right: 12px;
+  z-index: 100;
+`;
+
 export const TextArea = styled.textarea`
   width: 100%;
   border-radius: ${defaultBorderRadius};
@@ -128,19 +140,17 @@ export const HeaderButton = styled.button<{ inverted: boolean | undefined }>`
   background-color: ${({ inverted }) => (inverted ? "white" : "transparent")};
   color: ${({ inverted }) => (inverted ? "black" : "white")};
 
-  border: 1px solid white;
+  border: none;
   border-radius: ${defaultBorderRadius};
   cursor: pointer;
 
   &:hover {
     background-color: ${({ inverted }) =>
-      typeof inverted === "undefined" || inverted ? "white" : "transparent"};
-    color: ${({ inverted }) =>
-      typeof inverted === "undefined" || inverted ? "black" : "white"};
+      typeof inverted === "undefined" || inverted ? lightGray : "transparent"};
   }
   display: flex;
   align-items: center;
   justify-content: center;
   gap: 4px;
-  padding: 1px;
+  padding: 2px;
 `;
diff --git a/extension/react-app/src/hooks/ContinueGUIClientProtocol.ts b/extension/react-app/src/hooks/ContinueGUIClientProtocol.ts
index f123bb2b..a179c2bf 100644
--- a/extension/react-app/src/hooks/ContinueGUIClientProtocol.ts
+++ b/extension/react-app/src/hooks/ContinueGUIClientProtocol.ts
@@ -23,6 +23,10 @@ abstract class AbstractContinueGUIClientProtocol {
 
   abstract deleteContextAtIndices(indices: number[]): void;
 
+  abstract setEditingAtIndices(indices: number[]): void;
+
+  abstract setPinnedAtIndices(indices: number[]): void;
+
   abstract toggleAddingHighlightedCode(): void;
 }
 
diff --git a/extension/react-app/src/hooks/useContinueGUIProtocol.ts b/extension/react-app/src/hooks/useContinueGUIProtocol.ts
index 49f200ae..2060dd7f 100644
--- a/extension/react-app/src/hooks/useContinueGUIProtocol.ts
+++ b/extension/react-app/src/hooks/useContinueGUIProtocol.ts
@@ -75,6 +75,14 @@ class ContinueGUIClientProtocol extends AbstractContinueGUIClientProtocol {
     this.messenger.send("delete_context_at_indices", { indices });
   }
 
+  setEditingAtIndices(indices: number[]) {
+    this.messenger.send("set_editing_at_indices", { indices });
+  }
+
+  setPinnedAtIndices(indices: number[]) {
+    this.messenger.send("set_pinned_at_indices", { indices });
+  }
+
   toggleAddingHighlightedCode(): void {
     this.messenger.send("toggle_adding_highlighted_code", {});
   }
diff --git a/extension/react-app/src/index.css b/extension/react-app/src/index.css
index 6dc514ec..682551f8 100644
--- a/extension/react-app/src/index.css
+++ b/extension/react-app/src/index.css
@@ -10,19 +10,12 @@
   --def-border-radius: 5px;
 }
 
-@font-face {
-  font-family: "Mona Sans";
-  src: url("assets/Mona-Sans.woff2") format("woff2 supports variations"),
-    url("assets/Mona-Sans.woff2") format("woff2-variations");
-  font-weight: 200 900;
-  font-stretch: 75% 85%;
-}
-
 html,
 body,
 #root {
   height: 100%;
   background-color: var(--vsc-background);
+  font-family: "Lexend", sans-serif;
 }
 
 body {
diff --git a/extension/react-app/src/main.tsx b/extension/react-app/src/main.tsx
index 0b02575c..a76bced6 100644
--- a/extension/react-app/src/main.tsx
+++ b/extension/react-app/src/main.tsx
@@ -1,6 +1,8 @@
 import React from "react";
 import ReactDOM from "react-dom/client";
 import App from "./App";
+import { Provider } from "react-redux";
+import store from "./redux/store";
 import "./index.css";
 
 import posthog from "posthog-js";
@@ -17,7 +19,9 @@ posthog.init("phc_JS6XFROuNbhJtVCEdTSYk6gl5ArRrTNMpCcguAXlSPs", {
 ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
   <React.StrictMode>
     <PostHogProvider client={posthog}>
-      <App />
+      <Provider store={store}>
+        <App />
+      </Provider>
     </PostHogProvider>
   </React.StrictMode>
 );
diff --git a/extension/react-app/src/tabs/gui.tsx b/extension/react-app/src/tabs/gui.tsx
index e5320c6a..3cce30de 100644
--- a/extension/react-app/src/tabs/gui.tsx
+++ b/extension/react-app/src/tabs/gui.tsx
@@ -1,11 +1,13 @@
 import styled from "styled-components";
-import { defaultBorderRadius, Loader } from "../components";
+import { defaultBorderRadius } from "../components";
+import Loader from "../components/Loader";
 import ContinueButton from "../components/ContinueButton";
-import { useCallback, useEffect, useRef, useState } from "react";
+import { FullState, HighlightedRangeContext } from "../../../schema/FullState";
+import { useCallback, useEffect, useRef, useState, useContext } from "react";
 import { History } from "../../../schema/History";
 import { HistoryNode } from "../../../schema/HistoryNode";
 import StepContainer from "../components/StepContainer";
-import useContinueGUIProtocol from "../hooks/useWebsocket";
+import { GUIClientContext } from "../App";
 import {
   BookOpen,
   ChatBubbleOvalLeftEllipsis,
@@ -52,6 +54,7 @@ interface GUIProps {
 }
 
 function GUI(props: GUIProps) {
+  const client = useContext(GUIClientContext);
   const posthog = usePostHog();
   const vscMachineId = useSelector(
     (state: RootStore) => state.config.vscMachineId
@@ -70,7 +73,9 @@ function GUI(props: GUIProps) {
   const [usingFastModel, setUsingFastModel] = useState(false);
   const [waitingForSteps, setWaitingForSteps] = useState(false);
   const [userInputQueue, setUserInputQueue] = useState<string[]>([]);
-  const [highlightedRanges, setHighlightedRanges] = useState([]);
+  const [highlightedRanges, setHighlightedRanges] = useState<
+    HighlightedRangeContext[]
+  >([]);
   const [addingHighlightedCode, setAddingHighlightedCode] = useState(false);
   const [availableSlashCommands, setAvailableSlashCommands] = useState<
     { name: string; description: string }[]
@@ -112,7 +117,6 @@ function GUI(props: GUIProps) {
   const [feedbackDialogMessage, setFeedbackDialogMessage] = useState("");
 
   const topGuiDivRef = useRef<HTMLDivElement>(null);
-  const client = useContinueGUIProtocol();
 
   const [scrollTimeout, setScrollTimeout] = useState<NodeJS.Timeout | null>(
     null
@@ -148,7 +152,7 @@ function GUI(props: GUIProps) {
   }, []);
 
   useEffect(() => {
-    client?.onStateUpdate((state) => {
+    client?.onStateUpdate((state: FullState) => {
       // Scroll only if user is at very bottom of the window.
       setUsingFastModel(state.default_model === "gpt-3.5-turbo");
       const shouldScrollToBottom =
@@ -289,7 +293,7 @@ function GUI(props: GUIProps) {
       >
         {typeof client === "undefined" && (
           <>
-            <Loader></Loader>
+            <Loader />
             <p style={{ textAlign: "center" }}>Loading Continue server...</p>
           </>
         )}
@@ -316,7 +320,8 @@ function GUI(props: GUIProps) {
                 setStepsOpen(nextStepsOpen);
               }}
               onToggleAll={() => {
-                setStepsOpen((prev) => prev.map((_, index) => !prev[index]));
+                const shouldOpen = !stepsOpen[index];
+                setStepsOpen((prev) => prev.map(() => shouldOpen));
               }}
               key={index}
               onUserInput={(input: string) => {
@@ -381,6 +386,7 @@ function GUI(props: GUIProps) {
           borderRadius: defaultBorderRadius,
           padding: "16px",
           margin: "16px",
+          zIndex: 100,
         }}
         hidden={!showDataSharingInfo}
       >
diff --git a/extension/schema/FullState.d.ts b/extension/schema/FullState.d.ts
new file mode 100644
index 00000000..981e772e
--- /dev/null
+++ b/extension/schema/FullState.d.ts
@@ -0,0 +1,133 @@
+/* eslint-disable */
+/**
+ * This file was automatically generated by json-schema-to-typescript.
+ * DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file,
+ * and run json-schema-to-typescript to regenerate this file.
+ */
+
+export type FullState = FullState1;
+export type Name = string;
+export type Hide = boolean;
+export type Description = string;
+export type SystemMessage = string;
+export type Role = "assistant" | "user" | "system" | "function";
+export type Content = string;
+export type Name1 = string;
+export type Summary = string;
+export type Name2 = string;
+export type Arguments = string;
+export type ChatContext = ChatMessage[];
+export type ManageOwnChatContext = boolean;
+export type Depth = number;
+export type Deleted = boolean;
+export type Active = boolean;
+export type Timeline = HistoryNode[];
+export type CurrentIndex = number;
+export type Active1 = boolean;
+export type UserInputQueue = string[];
+export type DefaultModel = string;
+export type Filepath = string;
+export type Line = number;
+export type Character = number;
+export type Contents = string;
+export type Editing = boolean;
+export type Pinned = boolean;
+export type HighlightedRanges = HighlightedRangeContext[];
+export type Name3 = string;
+export type Description1 = string;
+export type SlashCommands = SlashCommandDescription[];
+export type AddingHighlightedCode = boolean;
+
+/**
+ * A full state of the program, including the history
+ */
+export interface FullState1 {
+  history: History;
+  active: Active1;
+  user_input_queue: UserInputQueue;
+  default_model: DefaultModel;
+  highlighted_ranges: HighlightedRanges;
+  slash_commands: SlashCommands;
+  adding_highlighted_code: AddingHighlightedCode;
+  [k: string]: unknown;
+}
+/**
+ * A history of steps taken and their results
+ */
+export interface History {
+  timeline: Timeline;
+  current_index: CurrentIndex;
+  [k: string]: unknown;
+}
+/**
+ * A point in history, a list of which make up History
+ */
+export interface HistoryNode {
+  step: Step;
+  observation?: Observation;
+  depth: Depth;
+  deleted?: Deleted;
+  active?: Active;
+  [k: string]: unknown;
+}
+export interface Step {
+  name?: Name;
+  hide?: Hide;
+  description?: Description;
+  system_message?: SystemMessage;
+  chat_context?: ChatContext;
+  manage_own_chat_context?: ManageOwnChatContext;
+  [k: string]: unknown;
+}
+export interface ChatMessage {
+  role: Role;
+  content?: Content;
+  name?: Name1;
+  summary: Summary;
+  function_call?: FunctionCall;
+  [k: string]: unknown;
+}
+export interface FunctionCall {
+  name: Name2;
+  arguments: Arguments;
+  [k: string]: unknown;
+}
+export interface Observation {
+  [k: string]: unknown;
+}
+/**
+ * Context for a highlighted range
+ */
+export interface HighlightedRangeContext {
+  range: RangeInFileWithContents;
+  editing: Editing;
+  pinned: Pinned;
+  [k: string]: unknown;
+}
+/**
+ * A range in a file with the contents of the range.
+ */
+export interface RangeInFileWithContents {
+  filepath: Filepath;
+  range: Range;
+  contents: Contents;
+  [k: string]: unknown;
+}
+/**
+ * A range in a file. 0-indexed.
+ */
+export interface Range {
+  start: Position;
+  end: Position;
+  [k: string]: unknown;
+}
+export interface Position {
+  line: Line;
+  character: Character;
+  [k: string]: unknown;
+}
+export interface SlashCommandDescription {
+  name: Name3;
+  description: Description1;
+  [k: string]: unknown;
+}
diff --git a/extension/src/debugPanel.ts b/extension/src/debugPanel.ts
index b88c86f3..487bbedf 100644
--- a/extension/src/debugPanel.ts
+++ b/extension/src/debugPanel.ts
@@ -341,6 +341,10 @@ export function setupDebugPanel(
         <meta name="viewport" content="width=device-width, initial-scale=1.0">
         <script>const vscode = acquireVsCodeApi();</script>
         <link href="${styleMainUri}" rel="stylesheet">
+
+        <link rel="preconnect" href="https://fonts.googleapis.com">
+        <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
+        <link href="https://fonts.googleapis.com/css2?family=Lexend:wght@300&display=swap" rel="stylesheet">
         
         <title>Continue</title>
       </head>
diff --git a/schema/json/FullState.json b/schema/json/FullState.json
new file mode 100644
index 00000000..af0f25e1
--- /dev/null
+++ b/schema/json/FullState.json
@@ -0,0 +1,304 @@
+{
+  "title": "FullState",
+  "$ref": "#/definitions/src__continuedev__core__main__FullState",
+  "definitions": {
+    "FunctionCall": {
+      "title": "FunctionCall",
+      "type": "object",
+      "properties": {
+        "name": {
+          "title": "Name",
+          "type": "string"
+        },
+        "arguments": {
+          "title": "Arguments",
+          "type": "string"
+        }
+      },
+      "required": [
+        "name",
+        "arguments"
+      ]
+    },
+    "ChatMessage": {
+      "title": "ChatMessage",
+      "type": "object",
+      "properties": {
+        "role": {
+          "title": "Role",
+          "enum": [
+            "assistant",
+            "user",
+            "system",
+            "function"
+          ],
+          "type": "string"
+        },
+        "content": {
+          "title": "Content",
+          "type": "string"
+        },
+        "name": {
+          "title": "Name",
+          "type": "string"
+        },
+        "summary": {
+          "title": "Summary",
+          "type": "string"
+        },
+        "function_call": {
+          "$ref": "#/definitions/FunctionCall"
+        }
+      },
+      "required": [
+        "role",
+        "summary"
+      ]
+    },
+    "Step": {
+      "title": "Step",
+      "type": "object",
+      "properties": {
+        "name": {
+          "title": "Name",
+          "type": "string"
+        },
+        "hide": {
+          "title": "Hide",
+          "default": false,
+          "type": "boolean"
+        },
+        "description": {
+          "title": "Description",
+          "type": "string"
+        },
+        "system_message": {
+          "title": "System Message",
+          "type": "string"
+        },
+        "chat_context": {
+          "title": "Chat Context",
+          "default": [],
+          "type": "array",
+          "items": {
+            "$ref": "#/definitions/ChatMessage"
+          }
+        },
+        "manage_own_chat_context": {
+          "title": "Manage Own Chat Context",
+          "default": false,
+          "type": "boolean"
+        }
+      }
+    },
+    "Observation": {
+      "title": "Observation",
+      "type": "object",
+      "properties": {}
+    },
+    "HistoryNode": {
+      "title": "HistoryNode",
+      "description": "A point in history, a list of which make up History",
+      "type": "object",
+      "properties": {
+        "step": {
+          "$ref": "#/definitions/Step"
+        },
+        "observation": {
+          "$ref": "#/definitions/Observation"
+        },
+        "depth": {
+          "title": "Depth",
+          "type": "integer"
+        },
+        "deleted": {
+          "title": "Deleted",
+          "default": false,
+          "type": "boolean"
+        },
+        "active": {
+          "title": "Active",
+          "default": true,
+          "type": "boolean"
+        }
+      },
+      "required": [
+        "step",
+        "depth"
+      ]
+    },
+    "History": {
+      "title": "History",
+      "description": "A history of steps taken and their results",
+      "type": "object",
+      "properties": {
+        "timeline": {
+          "title": "Timeline",
+          "type": "array",
+          "items": {
+            "$ref": "#/definitions/HistoryNode"
+          }
+        },
+        "current_index": {
+          "title": "Current Index",
+          "type": "integer"
+        }
+      },
+      "required": [
+        "timeline",
+        "current_index"
+      ]
+    },
+    "Position": {
+      "title": "Position",
+      "type": "object",
+      "properties": {
+        "line": {
+          "title": "Line",
+          "type": "integer"
+        },
+        "character": {
+          "title": "Character",
+          "type": "integer"
+        }
+      },
+      "required": [
+        "line",
+        "character"
+      ]
+    },
+    "Range": {
+      "title": "Range",
+      "description": "A range in a file. 0-indexed.",
+      "type": "object",
+      "properties": {
+        "start": {
+          "$ref": "#/definitions/Position"
+        },
+        "end": {
+          "$ref": "#/definitions/Position"
+        }
+      },
+      "required": [
+        "start",
+        "end"
+      ]
+    },
+    "RangeInFileWithContents": {
+      "title": "RangeInFileWithContents",
+      "description": "A range in a file with the contents of the range.",
+      "type": "object",
+      "properties": {
+        "filepath": {
+          "title": "Filepath",
+          "type": "string"
+        },
+        "range": {
+          "$ref": "#/definitions/Range"
+        },
+        "contents": {
+          "title": "Contents",
+          "type": "string"
+        }
+      },
+      "required": [
+        "filepath",
+        "range",
+        "contents"
+      ]
+    },
+    "HighlightedRangeContext": {
+      "title": "HighlightedRangeContext",
+      "description": "Context for a highlighted range",
+      "type": "object",
+      "properties": {
+        "range": {
+          "$ref": "#/definitions/RangeInFileWithContents"
+        },
+        "editing": {
+          "title": "Editing",
+          "type": "boolean"
+        },
+        "pinned": {
+          "title": "Pinned",
+          "type": "boolean"
+        }
+      },
+      "required": [
+        "range",
+        "editing",
+        "pinned"
+      ]
+    },
+    "SlashCommandDescription": {
+      "title": "SlashCommandDescription",
+      "type": "object",
+      "properties": {
+        "name": {
+          "title": "Name",
+          "type": "string"
+        },
+        "description": {
+          "title": "Description",
+          "type": "string"
+        }
+      },
+      "required": [
+        "name",
+        "description"
+      ]
+    },
+    "src__continuedev__core__main__FullState": {
+      "title": "FullState",
+      "description": "A full state of the program, including the history",
+      "type": "object",
+      "properties": {
+        "history": {
+          "$ref": "#/definitions/History"
+        },
+        "active": {
+          "title": "Active",
+          "type": "boolean"
+        },
+        "user_input_queue": {
+          "title": "User Input Queue",
+          "type": "array",
+          "items": {
+            "type": "string"
+          }
+        },
+        "default_model": {
+          "title": "Default Model",
+          "type": "string"
+        },
+        "highlighted_ranges": {
+          "title": "Highlighted Ranges",
+          "type": "array",
+          "items": {
+            "$ref": "#/definitions/HighlightedRangeContext"
+          }
+        },
+        "slash_commands": {
+          "title": "Slash Commands",
+          "type": "array",
+          "items": {
+            "$ref": "#/definitions/SlashCommandDescription"
+          }
+        },
+        "adding_highlighted_code": {
+          "title": "Adding Highlighted Code",
+          "type": "boolean"
+        }
+      },
+      "required": [
+        "history",
+        "active",
+        "user_input_queue",
+        "default_model",
+        "highlighted_ranges",
+        "slash_commands",
+        "adding_highlighted_code"
+      ]
+    }
+  }
+}
\ No newline at end of file
-- 
cgit v1.2.3-70-g09d2


From 861a873f7ecf455b9c7833040b2a8163e369e062 Mon Sep 17 00:00:00 2001
From: Nate Sesti <sestinj@gmail.com>
Date: Tue, 25 Jul 2023 22:26:09 -0700
Subject: checkpoint. Somewhat working, just a bit slow, probably some blocking
 meilisearch calls still happening

---
 continuedev/poetry.lock                   | 105 +++++-------------------------
 continuedev/pyproject.toml                |   1 +
 continuedev/src/continuedev/server/gui.py |   4 +-
 continuedev/src/continuedev/server/ide.py |   6 +-
 extension/react-app/src/main.tsx          |   7 +-
 extension/src/activation/activate.ts      |   3 +-
 extension/src/continueIdeClient.ts        |   3 +-
 extension/src/debugPanel.ts               |   2 +
 extension/src/util/messenger.ts           |   9 ++-
 9 files changed, 40 insertions(+), 100 deletions(-)

(limited to 'extension/react-app/src/main.tsx')

diff --git a/continuedev/poetry.lock b/continuedev/poetry.lock
index b67128fd..6644bf6f 100644
--- a/continuedev/poetry.lock
+++ b/continuedev/poetry.lock
@@ -1,10 +1,9 @@
-# This file is automatically @generated by Poetry 1.4.1 and should not be changed by hand.
+# This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand.
 
 [[package]]
 name = "aiohttp"
 version = "3.8.4"
 description = "Async http client/server framework (asyncio)"
-category = "main"
 optional = false
 python-versions = ">=3.6"
 files = [
@@ -113,7 +112,6 @@ speedups = ["Brotli", "aiodns", "cchardet"]
 name = "aiosignal"
 version = "1.3.1"
 description = "aiosignal: a list of registered asynchronous callbacks"
-category = "main"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -128,7 +126,6 @@ frozenlist = ">=1.1.0"
 name = "anthropic"
 version = "0.3.4"
 description = "Client library for the anthropic API"
-category = "main"
 optional = false
 python-versions = ">=3.7,<4.0"
 files = [
@@ -148,7 +145,6 @@ typing-extensions = ">=4.1.1,<5"
 name = "anyio"
 version = "3.6.2"
 description = "High level compatibility layer for multiple asynchronous event loop implementations"
-category = "main"
 optional = false
 python-versions = ">=3.6.2"
 files = [
@@ -169,7 +165,6 @@ trio = ["trio (>=0.16,<0.22)"]
 name = "async-timeout"
 version = "4.0.2"
 description = "Timeout context manager for asyncio programs"
-category = "main"
 optional = false
 python-versions = ">=3.6"
 files = [
@@ -181,7 +176,6 @@ files = [
 name = "attrs"
 version = "23.1.0"
 description = "Classes Without Boilerplate"
-category = "main"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -200,7 +194,6 @@ tests-no-zope = ["cloudpickle", "hypothesis", "mypy (>=1.1.1)", "pympler", "pyte
 name = "backoff"
 version = "2.2.1"
 description = "Function decoration for backoff and retry"
-category = "main"
 optional = false
 python-versions = ">=3.7,<4.0"
 files = [
@@ -212,7 +205,6 @@ files = [
 name = "boltons"
 version = "23.0.0"
 description = "When they're not builtins, they're boltons."
-category = "main"
 optional = false
 python-versions = "*"
 files = [
@@ -224,7 +216,6 @@ files = [
 name = "camel-converter"
 version = "3.0.2"
 description = "Converts a string from snake case to camel case or camel case to snake case"
-category = "main"
 optional = false
 python-versions = ">=3.8,<4.0"
 files = [
@@ -242,7 +233,6 @@ pydantic = ["pydantic (>=1.8.2)"]
 name = "certifi"
 version = "2022.12.7"
 description = "Python package for providing Mozilla's CA Bundle."
-category = "main"
 optional = false
 python-versions = ">=3.6"
 files = [
@@ -254,7 +244,6 @@ files = [
 name = "cffi"
 version = "1.15.1"
 description = "Foreign Function Interface for Python calling C code."
-category = "main"
 optional = false
 python-versions = "*"
 files = [
@@ -331,7 +320,6 @@ pycparser = "*"
 name = "charset-normalizer"
 version = "3.1.0"
 description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet."
-category = "main"
 optional = false
 python-versions = ">=3.7.0"
 files = [
@@ -416,7 +404,6 @@ files = [
 name = "chevron"
 version = "0.14.0"
 description = "Mustache templating language renderer"
-category = "main"
 optional = false
 python-versions = "*"
 files = [
@@ -428,7 +415,6 @@ files = [
 name = "click"
 version = "8.1.3"
 description = "Composable command line interface toolkit"
-category = "main"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -443,7 +429,6 @@ colorama = {version = "*", markers = "platform_system == \"Windows\""}
 name = "colorama"
 version = "0.4.6"
 description = "Cross-platform colored terminal text."
-category = "main"
 optional = false
 python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
 files = [
@@ -455,7 +440,6 @@ files = [
 name = "cryptography"
 version = "41.0.2"
 description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers."
-category = "main"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -501,7 +485,6 @@ test-randomorder = ["pytest-randomly"]
 name = "dataclasses-json"
 version = "0.5.7"
 description = "Easily serialize dataclasses to and from JSON"
-category = "main"
 optional = false
 python-versions = ">=3.6"
 files = [
@@ -521,7 +504,6 @@ dev = ["flake8", "hypothesis", "ipython", "mypy (>=0.710)", "portray", "pytest (
 name = "deprecated"
 version = "1.2.14"
 description = "Python @deprecated decorator to deprecate old python classes, functions or methods."
-category = "main"
 optional = false
 python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
 files = [
@@ -539,7 +521,6 @@ dev = ["PyTest", "PyTest-Cov", "bump2version (<1)", "sphinx (<2)", "tox"]
 name = "diff-match-patch"
 version = "20230430"
 description = "Diff Match and Patch"
-category = "main"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -554,7 +535,6 @@ dev = ["attribution (==1.6.2)", "black (==23.3.0)", "flit (==3.8.0)", "mypy (==1
 name = "directory-tree"
 version = "0.0.3.1"
 description = "Utility Package that Displays out the Tree Structure of a Particular Directory."
-category = "main"
 optional = false
 python-versions = "*"
 files = [
@@ -569,7 +549,6 @@ dev = ["pytest (>=3.7)"]
 name = "distro"
 version = "1.8.0"
 description = "Distro - an OS platform information API"
-category = "main"
 optional = false
 python-versions = ">=3.6"
 files = [
@@ -581,7 +560,6 @@ files = [
 name = "fastapi"
 version = "0.95.1"
 description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production"
-category = "main"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -603,7 +581,6 @@ test = ["anyio[trio] (>=3.2.1,<4.0.0)", "black (==23.1.0)", "coverage[toml] (>=6
 name = "frozenlist"
 version = "1.3.3"
 description = "A list-like structure which implements collections.abc.MutableSequence"
-category = "main"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -683,11 +660,20 @@ files = [
     {file = "frozenlist-1.3.3.tar.gz", hash = "sha256:58bcc55721e8a90b88332d6cd441261ebb22342e238296bb330968952fbb3a6a"},
 ]
 
+[[package]]
+name = "func-timeout"
+version = "4.3.5"
+description = "Python module which allows you to specify timeouts when calling any existing function. Also provides support for stoppable-threads"
+optional = false
+python-versions = "*"
+files = [
+    {file = "func_timeout-4.3.5.tar.gz", hash = "sha256:74cd3c428ec94f4edfba81f9b2f14904846d5ffccc27c92433b8b5939b5575dd"},
+]
+
 [[package]]
 name = "gpt-index"
 version = "0.6.8"
 description = "Interface between LLMs and your data"
-category = "main"
 optional = false
 python-versions = "*"
 files = [
@@ -709,7 +695,6 @@ tiktoken = "*"
 name = "greenlet"
 version = "2.0.2"
 description = "Lightweight in-process concurrent programming"
-category = "main"
 optional = false
 python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*"
 files = [
@@ -783,7 +768,6 @@ test = ["objgraph", "psutil"]
 name = "h11"
 version = "0.14.0"
 description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1"
-category = "main"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -795,7 +779,6 @@ files = [
 name = "httpcore"
 version = "0.17.3"
 description = "A minimal low-level HTTP client."
-category = "main"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -807,17 +790,16 @@ files = [
 anyio = ">=3.0,<5.0"
 certifi = "*"
 h11 = ">=0.13,<0.15"
-sniffio = ">=1.0.0,<2.0.0"
+sniffio = "==1.*"
 
 [package.extras]
 http2 = ["h2 (>=3,<5)"]
-socks = ["socksio (>=1.0.0,<2.0.0)"]
+socks = ["socksio (==1.*)"]
 
 [[package]]
 name = "httpx"
 version = "0.24.1"
 description = "The next generation HTTP client."
-category = "main"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -833,15 +815,14 @@ sniffio = "*"
 
 [package.extras]
 brotli = ["brotli", "brotlicffi"]
-cli = ["click (>=8.0.0,<9.0.0)", "pygments (>=2.0.0,<3.0.0)", "rich (>=10,<14)"]
+cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"]
 http2 = ["h2 (>=3,<5)"]
-socks = ["socksio (>=1.0.0,<2.0.0)"]
+socks = ["socksio (==1.*)"]
 
 [[package]]
 name = "idna"
 version = "3.4"
 description = "Internationalized Domain Names in Applications (IDNA)"
-category = "main"
 optional = false
 python-versions = ">=3.5"
 files = [
@@ -853,7 +834,6 @@ files = [
 name = "importlib-resources"
 version = "6.0.0"
 description = "Read resources from Python packages"
-category = "main"
 optional = false
 python-versions = ">=3.8"
 files = [
@@ -872,7 +852,6 @@ testing = ["pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)",
 name = "jsonref"
 version = "1.1.0"
 description = "jsonref is a library for automatic dereferencing of JSON Reference objects for Python."
-category = "main"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -884,7 +863,6 @@ files = [
 name = "jsonschema"
 version = "4.17.3"
 description = "An implementation of JSON Schema validation for Python"
-category = "main"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -906,7 +884,6 @@ format-nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-
 name = "langchain"
 version = "0.0.171"
 description = "Building applications with LLMs through composability"
-category = "main"
 optional = false
 python-versions = ">=3.8.1,<4.0"
 files = [
@@ -943,7 +920,6 @@ qdrant = ["qdrant-client (>=1.1.2,<2.0.0)"]
 name = "marshmallow"
 version = "3.19.0"
 description = "A lightweight library for converting complex datatypes to and from native Python datatypes."
-category = "main"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -964,7 +940,6 @@ tests = ["pytest", "pytz", "simplejson"]
 name = "marshmallow-enum"
 version = "1.5.1"
 description = "Enum field for Marshmallow"
-category = "main"
 optional = false
 python-versions = "*"
 files = [
@@ -979,7 +954,6 @@ marshmallow = ">=2.0.0"
 name = "meilisearch"
 version = "0.28.1"
 description = "The python client for Meilisearch API."
-category = "main"
 optional = false
 python-versions = ">=3.8"
 files = [
@@ -995,7 +969,6 @@ requests = "*"
 name = "monotonic"
 version = "1.6"
 description = "An implementation of time.monotonic() for Python 2 & < 3.3"
-category = "main"
 optional = false
 python-versions = "*"
 files = [
@@ -1007,7 +980,6 @@ files = [
 name = "multidict"
 version = "6.0.4"
 description = "multidict implementation"
-category = "main"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -1091,7 +1063,6 @@ files = [
 name = "mypy-extensions"
 version = "1.0.0"
 description = "Type system extensions for programs checked with the mypy type checker."
-category = "main"
 optional = false
 python-versions = ">=3.5"
 files = [
@@ -1103,7 +1074,6 @@ files = [
 name = "nest-asyncio"
 version = "1.5.6"
 description = "Patch asyncio to allow nested event loops"
-category = "main"
 optional = false
 python-versions = ">=3.5"
 files = [
@@ -1115,7 +1085,6 @@ files = [
 name = "numexpr"
 version = "2.8.4"
 description = "Fast numerical expression evaluator for NumPy"
-category = "main"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -1158,7 +1127,6 @@ numpy = ">=1.13.3"
 name = "numpy"
 version = "1.24.3"
 description = "Fundamental package for array computing in Python"
-category = "main"
 optional = false
 python-versions = ">=3.8"
 files = [
@@ -1196,7 +1164,6 @@ files = [
 name = "openai"
 version = "0.27.6"
 description = "Python client library for the OpenAI API"
-category = "main"
 optional = false
 python-versions = ">=3.7.1"
 files = [
@@ -1211,7 +1178,7 @@ tqdm = "*"
 
 [package.extras]
 datalib = ["numpy", "openpyxl (>=3.0.7)", "pandas (>=1.2.3)", "pandas-stubs (>=1.1.0.11)"]
-dev = ["black (>=21.6b0,<22.0)", "pytest (>=6.0.0,<7.0.0)", "pytest-asyncio", "pytest-mock"]
+dev = ["black (>=21.6b0,<22.0)", "pytest (==6.*)", "pytest-asyncio", "pytest-mock"]
 embeddings = ["matplotlib", "numpy", "openpyxl (>=3.0.7)", "pandas (>=1.2.3)", "pandas-stubs (>=1.1.0.11)", "plotly", "scikit-learn (>=1.0.2)", "scipy", "tenacity (>=8.0.1)"]
 wandb = ["numpy", "openpyxl (>=3.0.7)", "pandas (>=1.2.3)", "pandas-stubs (>=1.1.0.11)", "wandb"]
 
@@ -1219,7 +1186,6 @@ wandb = ["numpy", "openpyxl (>=3.0.7)", "pandas (>=1.2.3)", "pandas-stubs (>=1.1
 name = "openapi-schema-pydantic"
 version = "1.2.4"
 description = "OpenAPI (v3) specification schema as pydantic class"
-category = "main"
 optional = false
 python-versions = ">=3.6.1"
 files = [
@@ -1234,7 +1200,6 @@ pydantic = ">=1.8.2"
 name = "packaging"
 version = "23.1"
 description = "Core utilities for Python packages"
-category = "main"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -1246,7 +1211,6 @@ files = [
 name = "pandas"
 version = "2.0.1"
 description = "Powerful data structures for data analysis, time series, and statistics"
-category = "main"
 optional = false
 python-versions = ">=3.8"
 files = [
@@ -1314,7 +1278,6 @@ xml = ["lxml (>=4.6.3)"]
 name = "pkgutil-resolve-name"
 version = "1.3.10"
 description = "Resolve a name to an object."
-category = "main"
 optional = false
 python-versions = ">=3.6"
 files = [
@@ -1326,7 +1289,6 @@ files = [
 name = "posthog"
 version = "3.0.1"
 description = "Integrate PostHog into any python application."
-category = "main"
 optional = false
 python-versions = "*"
 files = [
@@ -1350,7 +1312,6 @@ test = ["coverage", "flake8", "freezegun (==0.3.15)", "mock (>=2.0.0)", "pylint"
 name = "psutil"
 version = "5.9.5"
 description = "Cross-platform lib for process and system monitoring in Python."
-category = "main"
 optional = false
 python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
 files = [
@@ -1377,7 +1338,6 @@ test = ["enum34", "ipaddress", "mock", "pywin32", "wmi"]
 name = "pycparser"
 version = "2.21"
 description = "C parser in Python"
-category = "main"
 optional = false
 python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
 files = [
@@ -1389,7 +1349,6 @@ files = [
 name = "pydantic"
 version = "1.10.7"
 description = "Data validation and settings management using python type hints"
-category = "main"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -1442,7 +1401,6 @@ email = ["email-validator (>=1.0.3)"]
 name = "pygithub"
 version = "1.59.0"
 description = "Use the full Github API v3"
-category = "main"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -1460,7 +1418,6 @@ requests = ">=2.14.0"
 name = "pyjwt"
 version = "2.8.0"
 description = "JSON Web Token implementation in Python"
-category = "main"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -1481,7 +1438,6 @@ tests = ["coverage[toml] (==5.0.4)", "pytest (>=6.0.0,<7.0.0)"]
 name = "pynacl"
 version = "1.5.0"
 description = "Python binding to the Networking and Cryptography (NaCl) library"
-category = "main"
 optional = false
 python-versions = ">=3.6"
 files = [
@@ -1508,7 +1464,6 @@ tests = ["hypothesis (>=3.27.0)", "pytest (>=3.2.1,!=3.3.0)"]
 name = "pyrsistent"
 version = "0.19.3"
 description = "Persistent/Functional/Immutable data structures"
-category = "main"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -1545,7 +1500,6 @@ files = [
 name = "python-dateutil"
 version = "2.8.2"
 description = "Extensions to the standard Python datetime module"
-category = "main"
 optional = false
 python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7"
 files = [
@@ -1560,7 +1514,6 @@ six = ">=1.5"
 name = "python-dotenv"
 version = "1.0.0"
 description = "Read key-value pairs from a .env file and set them as environment variables"
-category = "main"
 optional = false
 python-versions = ">=3.8"
 files = [
@@ -1575,7 +1528,6 @@ cli = ["click (>=5.0)"]
 name = "pytz"
 version = "2023.3"
 description = "World timezone definitions, modern and historical"
-category = "main"
 optional = false
 python-versions = "*"
 files = [
@@ -1587,7 +1539,6 @@ files = [
 name = "pyyaml"
 version = "6.0"
 description = "YAML parser and emitter for Python"
-category = "main"
 optional = false
 python-versions = ">=3.6"
 files = [
@@ -1637,7 +1588,6 @@ files = [
 name = "regex"
 version = "2023.5.5"
 description = "Alternative regular expression module, to replace re."
-category = "main"
 optional = false
 python-versions = ">=3.6"
 files = [
@@ -1735,7 +1685,6 @@ files = [
 name = "requests"
 version = "2.29.0"
 description = "Python HTTP for Humans."
-category = "main"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -1757,7 +1706,6 @@ use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"]
 name = "six"
 version = "1.16.0"
 description = "Python 2 and 3 compatibility utilities"
-category = "main"
 optional = false
 python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
 files = [
@@ -1769,7 +1717,6 @@ files = [
 name = "sniffio"
 version = "1.3.0"
 description = "Sniff out which async library your code is running under"
-category = "main"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -1781,7 +1728,6 @@ files = [
 name = "sqlalchemy"
 version = "2.0.13"
 description = "Database Abstraction Library"
-category = "main"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -1829,7 +1775,7 @@ files = [
 ]
 
 [package.dependencies]
-greenlet = {version = "!=0.4.17", markers = "platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\""}
+greenlet = {version = "!=0.4.17", markers = "platform_machine == \"win32\" or platform_machine == \"WIN32\" or platform_machine == \"AMD64\" or platform_machine == \"amd64\" or platform_machine == \"x86_64\" or platform_machine == \"ppc64le\" or platform_machine == \"aarch64\""}
 typing-extensions = ">=4.2.0"
 
 [package.extras]
@@ -1859,7 +1805,6 @@ sqlcipher = ["sqlcipher3-binary"]
 name = "starlette"
 version = "0.26.1"
 description = "The little ASGI library that shines."
-category = "main"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -1878,7 +1823,6 @@ full = ["httpx (>=0.22.0)", "itsdangerous", "jinja2", "python-multipart", "pyyam
 name = "tenacity"
 version = "8.2.2"
 description = "Retry code until it succeeds"
-category = "main"
 optional = false
 python-versions = ">=3.6"
 files = [
@@ -1893,7 +1837,6 @@ doc = ["reno", "sphinx", "tornado (>=4.5)"]
 name = "tiktoken"
 version = "0.4.0"
 description = "tiktoken is a fast BPE tokeniser for use with OpenAI's models"
-category = "main"
 optional = false
 python-versions = ">=3.8"
 files = [
@@ -1939,7 +1882,6 @@ blobfile = ["blobfile (>=2)"]
 name = "tokenizers"
 version = "0.13.3"
 description = "Fast and Customizable Tokenizers"
-category = "main"
 optional = false
 python-versions = "*"
 files = [
@@ -1994,7 +1936,6 @@ testing = ["black (==22.3)", "datasets", "numpy", "pytest", "requests"]
 name = "tqdm"
 version = "4.65.0"
 description = "Fast, Extensible Progress Meter"
-category = "main"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -2015,7 +1956,6 @@ telegram = ["requests"]
 name = "typer"
 version = "0.7.0"
 description = "Typer, build great CLIs. Easy to code. Based on Python type hints."
-category = "main"
 optional = false
 python-versions = ">=3.6"
 files = [
@@ -2036,7 +1976,6 @@ test = ["black (>=22.3.0,<23.0.0)", "coverage (>=6.2,<7.0)", "isort (>=5.0.6,<6.
 name = "typing-extensions"
 version = "4.5.0"
 description = "Backported and Experimental Type Hints for Python 3.7+"
-category = "main"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -2048,7 +1987,6 @@ files = [
 name = "typing-inspect"
 version = "0.8.0"
 description = "Runtime inspection utilities for typing module."
-category = "main"
 optional = false
 python-versions = "*"
 files = [
@@ -2064,7 +2002,6 @@ typing-extensions = ">=3.7.4"
 name = "tzdata"
 version = "2023.3"
 description = "Provider of IANA time zone data"
-category = "main"
 optional = false
 python-versions = ">=2"
 files = [
@@ -2076,7 +2013,6 @@ files = [
 name = "urllib3"
 version = "1.26.15"
 description = "HTTP library with thread-safe connection pooling, file post, and more."
-category = "main"
 optional = false
 python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*"
 files = [
@@ -2093,7 +2029,6 @@ socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"]
 name = "uvicorn"
 version = "0.21.1"
 description = "The lightning-fast ASGI server."
-category = "main"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -2112,7 +2047,6 @@ standard = ["colorama (>=0.4)", "httptools (>=0.5.0)", "python-dotenv (>=0.13)",
 name = "websockets"
 version = "11.0.2"
 description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)"
-category = "main"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -2192,7 +2126,6 @@ files = [
 name = "wrapt"
 version = "1.15.0"
 description = "Module for decorators, wrappers and monkey patching."
-category = "main"
 optional = false
 python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"
 files = [
@@ -2277,7 +2210,6 @@ files = [
 name = "yarl"
 version = "1.9.2"
 description = "Yet another URL library"
-category = "main"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -2365,7 +2297,6 @@ multidict = ">=4.0"
 name = "zipp"
 version = "3.16.2"
 description = "Backport of pathlib-compatible object wrapper for zip files"
-category = "main"
 optional = false
 python-versions = ">=3.8"
 files = [
@@ -2380,4 +2311,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p
 [metadata]
 lock-version = "2.0"
 python-versions = "^3.8.1"
-content-hash = "83880c8de27a4094fa8e695bd8db5d4053fc2d61ffc028f09cfa097f315c35f2"
+content-hash = "53ad0b6fa45f00fe53fbd2a90845ae1647e0be22b0b52dfe55996f2c9a6faa38"
diff --git a/continuedev/pyproject.toml b/continuedev/pyproject.toml
index 64d5e90c..ad5657b1 100644
--- a/continuedev/pyproject.toml
+++ b/continuedev/pyproject.toml
@@ -29,6 +29,7 @@ chevron = "^0.14.0"
 psutil = "^5.9.5"
 meilisearch = "^0.28.1"
 pygithub = "^1.59.0"
+func-timeout = "^4.3.5"
 
 [tool.poetry.scripts]
 typegen = "src.continuedev.models.generate_json_schema:main" 
diff --git a/continuedev/src/continuedev/server/gui.py b/continuedev/src/continuedev/server/gui.py
index fa203c28..c0957395 100644
--- a/continuedev/src/continuedev/server/gui.py
+++ b/continuedev/src/continuedev/server/gui.py
@@ -61,12 +61,12 @@ class GUIProtocolServer(AbstractGUIProtocolServer):
             "data": data
         })
 
-    async def _receive_json(self, message_type: str, timeout: int = 5) -> Any:
+    async def _receive_json(self, message_type: str, timeout: int = 20) -> Any:
         try:
             return await asyncio.wait_for(self.sub_queue.get(message_type), timeout=timeout)
         except asyncio.TimeoutError:
             raise Exception(
-                "GUI Protocol _receive_json timed out after 5 seconds")
+                "GUI Protocol _receive_json timed out after 20 seconds")
 
     async def _send_and_receive_json(self, data: Any, resp_model: Type[T], message_type: str) -> T:
         await self._send_json(message_type, data)
diff --git a/continuedev/src/continuedev/server/ide.py b/continuedev/src/continuedev/server/ide.py
index d6a28c92..3401cbac 100644
--- a/continuedev/src/continuedev/server/ide.py
+++ b/continuedev/src/continuedev/server/ide.py
@@ -139,6 +139,7 @@ class IdeProtocolServer(AbstractIdeProtocolServer):
                 continue
             message_type = message["messageType"]
             data = message["data"]
+            print("Received message while initializing", message_type)
             if message_type == "workspaceDirectory":
                 self.workspace_directory = data["workspaceDirectory"]
             elif message_type == "uniqueId":
@@ -153,17 +154,18 @@ class IdeProtocolServer(AbstractIdeProtocolServer):
     async def _send_json(self, message_type: str, data: Any):
         if self.websocket.application_state == WebSocketState.DISCONNECTED:
             return
+        print("Sending IDE message: ", message_type)
         await self.websocket.send_json({
             "messageType": message_type,
             "data": data
         })
 
-    async def _receive_json(self, message_type: str, timeout: int = 5) -> Any:
+    async def _receive_json(self, message_type: str, timeout: int = 20) -> Any:
         try:
             return await asyncio.wait_for(self.sub_queue.get(message_type), timeout=timeout)
         except asyncio.TimeoutError:
             raise Exception(
-                "IDE Protocol _receive_json timed out after 5 seconds")
+                "IDE Protocol _receive_json timed out after 20 seconds", message_type)
 
     async def _send_and_receive_json(self, data: Any, resp_model: Type[T], message_type: str) -> T:
         await self._send_json(message_type, data)
diff --git a/extension/react-app/src/main.tsx b/extension/react-app/src/main.tsx
index a76bced6..1776490c 100644
--- a/extension/react-app/src/main.tsx
+++ b/extension/react-app/src/main.tsx
@@ -8,12 +8,11 @@ import "./index.css";
 import posthog from "posthog-js";
 import { PostHogProvider } from "posthog-js/react";
 
+console.log("Starting React");
+
 posthog.init("phc_JS6XFROuNbhJtVCEdTSYk6gl5ArRrTNMpCcguAXlSPs", {
   api_host: "https://app.posthog.com",
-  session_recording: {
-    // WARNING: Only enable this if you understand the security implications
-    recordCrossOriginIframes: true,
-  } as any,
+  disable_session_recording: true,
 });
 
 ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
diff --git a/extension/src/activation/activate.ts b/extension/src/activation/activate.ts
index a1d88a31..356d0256 100644
--- a/extension/src/activation/activate.ts
+++ b/extension/src/activation/activate.ts
@@ -17,7 +17,7 @@ export let ideProtocolClient: IdeProtocolClient;
 
 export async function activateExtension(context: vscode.ExtensionContext) {
   extensionContext = context;
-
+  console.log("Using Continue version: ", getExtensionVersion());
   // Before anything else, check whether this is an out-of-date version of the extension
   // Do so by grabbing the package.json off of the GitHub respository for now.
   fetch(PACKAGE_JSON_RAW_GITHUB_URL)
@@ -67,6 +67,7 @@ export async function activateExtension(context: vscode.ExtensionContext) {
       }, 2000);
     });
 
+    console.log("Continue server started");
     // Initialize IDE Protocol Client
     const serverUrl = getContinueServerUrl();
     ideProtocolClient = new IdeProtocolClient(
diff --git a/extension/src/continueIdeClient.ts b/extension/src/continueIdeClient.ts
index 802afc1d..d92a829d 100644
--- a/extension/src/continueIdeClient.ts
+++ b/extension/src/continueIdeClient.ts
@@ -399,8 +399,9 @@ class IdeProtocolClient {
         }
       }, 1000);
     });
+    console.log("Getting session ID");
     const resp = await this.messenger?.sendAndReceive("getSessionId", {});
-    // console.log("New Continue session with ID: ", sessionId);
+    console.log("New Continue session with ID: ", resp.sessionId);
     this._sessionId = resp.sessionId;
     return resp.sessionId;
   }
diff --git a/extension/src/debugPanel.ts b/extension/src/debugPanel.ts
index 6da79cdc..6dcb588a 100644
--- a/extension/src/debugPanel.ts
+++ b/extension/src/debugPanel.ts
@@ -166,11 +166,13 @@ export function setupDebugPanel(
     switch (data.type) {
       case "onLoad": {
         let sessionId: string;
+        console.log("Running onLoad");
         if (typeof sessionIdPromise === "string") {
           sessionId = sessionIdPromise;
         } else {
           sessionId = await sessionIdPromise;
         }
+        console.log("Done with onLoad: ", sessionId);
         panel.webview.postMessage({
           type: "onLoad",
           vscMachineId: vscode.env.machineId,
diff --git a/extension/src/util/messenger.ts b/extension/src/util/messenger.ts
index 3044898e..e28040f5 100644
--- a/extension/src/util/messenger.ts
+++ b/extension/src/util/messenger.ts
@@ -39,6 +39,7 @@ export class WebsocketMessenger extends Messenger {
     //   var WebSocket = require("ws");
     // }
 
+    console.log("Creating websocket at: ", this.serverUrl);
     const newWebsocket = new WebSocket(this.serverUrl);
     for (const listener of this.onOpenListeners) {
       this.onOpen(listener);
@@ -105,12 +106,14 @@ export class WebsocketMessenger extends Messenger {
   send(messageType: string, data: object) {
     const payload = JSON.stringify({ messageType, data });
     if (this.websocket.readyState === this.websocket.OPEN) {
+      console.log("websocket is open, sending message: ", messageType);
       this.websocket.send(payload);
     } else {
-      if (this.websocket.readyState !== this.websocket.CONNECTING) {
-        this.websocket = this._newWebsocket();
-      }
+      console.log("websocket is not open, creating new websocket", messageType);
+      this.websocket = this._newWebsocket();
+
       this.websocket.addEventListener("open", () => {
+        console.log("websocket is open, resending message: ", messageType);
         this.websocket.send(payload);
       });
     }
-- 
cgit v1.2.3-70-g09d2

