From cc0d73c2c1351a08c95654f7792f56c1d3d0ab54 Mon Sep 17 00:00:00 2001
From: Nate Sesti <sestinj@gmail.com>
Date: Mon, 12 Jun 2023 21:30:49 -0700
Subject: slash commands dropdown!

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

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

diff --git a/extension/react-app/src/components/ComboBox.tsx b/extension/react-app/src/components/ComboBox.tsx
new file mode 100644
index 00000000..1b7c60e6
--- /dev/null
+++ b/extension/react-app/src/components/ComboBox.tsx
@@ -0,0 +1,146 @@
+import React, { useCallback } from "react";
+import { useCombobox } from "downshift";
+import styled from "styled-components";
+import {
+  buttonColor,
+  defaultBorderRadius,
+  secondaryDark,
+  vscBackground,
+} from ".";
+
+const mainInputFontSize = 16;
+const MainTextInput = styled.input`
+  padding: 8px;
+  font-size: ${mainInputFontSize}px;
+  border-radius: ${defaultBorderRadius};
+  border: 1px solid #ccc;
+  margin: 8px auto;
+  width: 100%;
+  background-color: ${vscBackground};
+  color: white;
+  outline: 1px solid orange;
+`;
+
+const UlMaxHeight = 200;
+const Ul = styled.ul<{
+  hidden: boolean;
+  showAbove: boolean;
+  ulHeightPixels: number;
+}>`
+  ${(props) =>
+    props.showAbove
+      ? `transform: translateY(-${props.ulHeightPixels + 8}px);`
+      : `transform: translateY(${2 * mainInputFontSize}px);`}
+  position: absolute;
+  background: ${vscBackground};
+  background-color: ${secondaryDark};
+  color: white;
+  font-family: "Fira Code", monospace;
+  max-height: ${UlMaxHeight}px;
+  overflow: scroll;
+  padding: 0;
+  ${({ hidden }) => hidden && "display: none;"}
+  border-radius: ${defaultBorderRadius};
+  overflow: hidden;
+  border: 0.5px solid gray;
+`;
+
+const Li = styled.li<{
+  highlighted: boolean;
+  selected: boolean;
+  isLastItem: boolean;
+}>`
+  ${({ highlighted }) => highlighted && "background: #aa0000;"}
+  ${({ selected }) => selected && "font-weight: bold;"}
+    padding: 0.5rem 0.75rem;
+  display: flex;
+  flex-direction: column;
+  ${({ isLastItem }) => isLastItem && "border-bottom: 1px solid gray;"}
+  border-top: 1px solid gray;
+  cursor: pointer;
+`;
+
+interface ComboBoxProps {
+  items: { name: string; description: string }[];
+  onInputValueChange: (inputValue: string) => void;
+  disabled?: boolean;
+  onEnter?: (e: React.KeyboardEvent<HTMLInputElement>) => void;
+}
+
+const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
+  const [items, setItems] = React.useState(props.items);
+  const {
+    isOpen,
+    getToggleButtonProps,
+    getLabelProps,
+    getMenuProps,
+    getInputProps,
+    highlightedIndex,
+    getItemProps,
+    selectedItem,
+    setInputValue,
+  } = useCombobox({
+    onInputValueChange({ inputValue }) {
+      if (!inputValue) return;
+      props.onInputValueChange(inputValue);
+      setItems(
+        props.items.filter((item) =>
+          item.name.toLowerCase().startsWith(inputValue.toLowerCase())
+        )
+      );
+    },
+    items,
+    itemToString(item) {
+      return item ? item.name : "";
+    },
+  });
+
+  const divRef = React.useRef<HTMLDivElement>(null);
+  const ulRef = React.useRef<HTMLUListElement>(null);
+  const showAbove = () => {
+    return (divRef.current?.getBoundingClientRect().top || 0) > UlMaxHeight;
+  };
+
+  return (
+    <div className="flex px-2" ref={divRef} hidden={!isOpen}>
+      <MainTextInput
+        disabled={props.disabled}
+        placeholder="Ask anything:"
+        {...getInputProps({
+          onKeyDown: (event) => {
+            if (event.key === "Enter" && (!isOpen || items.length === 0)) {
+              // Prevent Downshift's default 'Enter' behavior.
+              (event.nativeEvent as any).preventDownshiftDefault = true;
+              if (props.onEnter) props.onEnter(event);
+              setInputValue("");
+            }
+          },
+          ref: ref as any,
+        })}
+      />
+      <Ul
+        {...getMenuProps({
+          ref: ulRef,
+        })}
+        showAbove={showAbove()}
+        ulHeightPixels={ulRef.current?.getBoundingClientRect().height || 0}
+      >
+        {isOpen &&
+          items.map((item, index) => (
+            <Li
+              key={`${item.name}${index}`}
+              {...getItemProps({ item, index })}
+              highlighted={highlightedIndex === index}
+              selected={selectedItem === item}
+            >
+              <span>
+                {item.name}: {item.description}
+              </span>
+            </Li>
+          ))}
+      </Ul>
+    </div>
+  );
+});
+
+export default ComboBox;
-- 
cgit v1.2.3-70-g09d2


From 276a7ab42a6cbeea931b6eeb7a27f56f60b3fb86 Mon Sep 17 00:00:00 2001
From: Nate Sesti <sestinj@gmail.com>
Date: Tue, 13 Jun 2023 12:00:35 -0700
Subject: env to .env to be caught by .gitignore

---
 continuedev/src/continuedev/core/policy.py           |  2 +-
 .../continuedev/recipes/AddTransformRecipe/steps.py  |  8 ++++----
 .../recipes/CreatePipelineRecipe/steps.py            | 10 +++++-----
 .../src/continuedev/recipes/DDtoBQRecipe/steps.py    | 10 +++++-----
 .../recipes/DeployPipelineAirflowRecipe/steps.py     |  8 ++++----
 .../continuedev/recipes/WritePytestsRecipe/main.py   |  3 +++
 docs/docs/walkthroughs/create-a-recipe.md            |  2 +-
 extension/react-app/src/components/ComboBox.tsx      |  2 +-
 extension/react-app/src/components/StepContainer.tsx | 20 +++++++++++---------
 9 files changed, 35 insertions(+), 30 deletions(-)

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

diff --git a/continuedev/src/continuedev/core/policy.py b/continuedev/src/continuedev/core/policy.py
index 51135f70..2b50307a 100644
--- a/continuedev/src/continuedev/core/policy.py
+++ b/continuedev/src/continuedev/core/policy.py
@@ -58,7 +58,7 @@ class DemoPolicy(Policy):
                 # AnswerQuestionChroma(question=user_input),
                 # EditFileChroma(request=user_input),
                 (SimpleChatStep(user_input=user_input),
-                 "Respond to the user with a chat message"),
+                 "Respond to the user with a chat message. Can answer questions about code or anything else."),
             ], default_step=EditHighlightedCodeStep(user_input=user_input))
 
         state = history.get_current()
diff --git a/continuedev/src/continuedev/recipes/AddTransformRecipe/steps.py b/continuedev/src/continuedev/recipes/AddTransformRecipe/steps.py
index f042424c..6a743fb5 100644
--- a/continuedev/src/continuedev/recipes/AddTransformRecipe/steps.py
+++ b/continuedev/src/continuedev/recipes/AddTransformRecipe/steps.py
@@ -24,15 +24,15 @@ class SetUpChessPipelineStep(Step):
 
         # running commands to get started when creating a new dlt pipeline
         await sdk.run([
-            'python3 -m venv env',
-            'source env/bin/activate',
+            'python3 -m venv .env',
+            'source .env/bin/activate',
             'pip install dlt',
             'dlt --non-interactive init chess duckdb',
             'pip install -r requirements.txt',
             'pip install pandas streamlit'  # Needed for the pipeline show step later
         ], name="Set up Python environment", description=dedent(f"""\
-            - Create a Python virtual environment: `python3 -m venv env`
-            - Activate the virtual environment: `source env/bin/activate`
+            - Create a Python virtual environment: `python3 -m venv .env`
+            - Activate the virtual environment: `source .env/bin/activate`
             - Install dlt: `pip install dlt`
             - Create a new dlt pipeline called "chess" that loads data into a local DuckDB instance: `dlt init chess duckdb`
             - Install the Python dependencies for the pipeline: `pip install -r requirements.txt`"""))
diff --git a/continuedev/src/continuedev/recipes/CreatePipelineRecipe/steps.py b/continuedev/src/continuedev/recipes/CreatePipelineRecipe/steps.py
index ea4607da..88e27d2a 100644
--- a/continuedev/src/continuedev/recipes/CreatePipelineRecipe/steps.py
+++ b/continuedev/src/continuedev/recipes/CreatePipelineRecipe/steps.py
@@ -35,15 +35,15 @@ class SetupPipelineStep(Step):
 
         # running commands to get started when creating a new dlt pipeline
         await sdk.run([
-            'python3 -m venv env',
-            'source env/bin/activate',
+            'python3 -m venv .env',
+            'source .env/bin/activate',
             'pip install dlt',
             f'dlt --non-interactive init {source_name} duckdb',
             'pip install -r requirements.txt'
         ], description=dedent(f"""\
             Running the following commands:
-            - `python3 -m venv env`: Create a Python virtual environment
-            - `source env/bin/activate`: Activate the virtual environment
+            - `python3 -m venv .env`: Create a Python virtual environment
+            - `source .env/bin/activate`: Activate the virtual environment
             - `pip install dlt`: Install dlt
             - `dlt init {source_name} duckdb`: Create a new dlt pipeline called {source_name} that loads data into a local DuckDB instance
             - `pip install -r requirements.txt`: Install the Python dependencies for the pipeline"""), name="Setup Python environment")
@@ -156,7 +156,7 @@ class RunQueryStep(Step):
     hide: bool = True
 
     async def run(self, sdk: ContinueSDK):
-        output = await sdk.run('env/bin/python3 query.py', name="Run test query", description="Running `env/bin/python3 query.py` to test that the data was loaded into DuckDB as expected", handle_error=False)
+        output = await sdk.run('.env/bin/python3 query.py', name="Run test query", description="Running `.env/bin/python3 query.py` to test that the data was loaded into DuckDB as expected", handle_error=False)
 
         if "Traceback" in output or "SyntaxError" in output:
             suggestion = sdk.models.gpt35.complete(dedent(f"""\
diff --git a/continuedev/src/continuedev/recipes/DDtoBQRecipe/steps.py b/continuedev/src/continuedev/recipes/DDtoBQRecipe/steps.py
index 5cf89ccf..4b8971c2 100644
--- a/continuedev/src/continuedev/recipes/DDtoBQRecipe/steps.py
+++ b/continuedev/src/continuedev/recipes/DDtoBQRecipe/steps.py
@@ -27,15 +27,15 @@ class SetUpChessPipelineStep(Step):
 
         # running commands to get started when creating a new dlt pipeline
         await sdk.run([
-            'python3 -m venv env',
-            'source env/bin/activate',
+            'python3 -m venv .env',
+            'source .env/bin/activate',
             'pip install dlt',
             'dlt --non-interactive init chess duckdb',
             'pip install -r requirements.txt',
         ], name="Set up Python environment", description=dedent(f"""\
             Running the following commands:
-            - `python3 -m venv env`: Create a Python virtual environment
-            - `source env/bin/activate`: Activate the virtual environment
+            - `python3 -m venv .env`: Create a Python virtual environment
+            - `source .env/bin/activate`: Activate the virtual environment
             - `pip install dlt`: Install dlt
             - `dlt init chess duckdb`: Create a new dlt pipeline called "chess" that loads data into a local DuckDB instance
             - `pip install -r requirements.txt`: Install the Python dependencies for the pipeline"""))
@@ -75,7 +75,7 @@ class LoadDataStep(Step):
 
     async def run(self, sdk: ContinueSDK):
         # Run the pipeline again to load data to BigQuery
-        output = await sdk.run('env/bin/python3 chess_pipeline.py', name="Load data to BigQuery", description="Running `env/bin/python3 chess_pipeline.py` to load data to Google BigQuery")
+        output = await sdk.run('.env/bin/python3 chess_pipeline.py', name="Load data to BigQuery", description="Running `.env/bin/python3 chess_pipeline.py` to load data to Google BigQuery")
 
         if "Traceback" in output or "SyntaxError" in output:
             with open(os.path.join(os.path.dirname(__file__), "dlt_duckdb_to_bigquery_docs.md"), "r") as f:
diff --git a/continuedev/src/continuedev/recipes/DeployPipelineAirflowRecipe/steps.py b/continuedev/src/continuedev/recipes/DeployPipelineAirflowRecipe/steps.py
index ee3275e7..c9749348 100644
--- a/continuedev/src/continuedev/recipes/DeployPipelineAirflowRecipe/steps.py
+++ b/continuedev/src/continuedev/recipes/DeployPipelineAirflowRecipe/steps.py
@@ -28,15 +28,15 @@ class SetupPipelineStep(Step):
 
     async def run(self, sdk: ContinueSDK):
         await sdk.run([
-            'python3 -m venv env',
-            'source env/bin/activate',
+            'python3 -m venv .env',
+            'source .env/bin/activate',
             'pip install dlt',
             f'dlt --non-interactive init {self.source_name} duckdb',
             'pip install -r requirements.txt'
         ], description=dedent(f"""\
             Running the following commands:
-            - `python3 -m venv env`: Create a Python virtual environment
-            - `source env/bin/activate`: Activate the virtual environment
+            - `python3 -m venv .env`: Create a Python virtual environment
+            - `source .env/bin/activate`: Activate the virtual environment
             - `pip install dlt`: Install dlt
             - `dlt init {self.source_name} duckdb`: Create a new dlt pipeline called {self.source_name} that loads data into a local DuckDB instance
             - `pip install -r requirements.txt`: Install the Python dependencies for the pipeline"""), name="Setup Python environment")
diff --git a/continuedev/src/continuedev/recipes/WritePytestsRecipe/main.py b/continuedev/src/continuedev/recipes/WritePytestsRecipe/main.py
index a19caf8b..688f44c3 100644
--- a/continuedev/src/continuedev/recipes/WritePytestsRecipe/main.py
+++ b/continuedev/src/continuedev/recipes/WritePytestsRecipe/main.py
@@ -9,6 +9,9 @@ class WritePytestsRecipe(Step):
     for_filepath: Union[str, None] = None
     user_input: str = "Write unit tests for this file."
 
+    async def describe(self, models):
+        return f"Writing unit tests for {self.for_filepath}"
+
     async def run(self, sdk: ContinueSDK):
         if self.for_filepath is None:
             self.for_filepath = (await sdk.ide.getOpenFiles())[0]
diff --git a/docs/docs/walkthroughs/create-a-recipe.md b/docs/docs/walkthroughs/create-a-recipe.md
index 3b80df8a..5d80d083 100644
--- a/docs/docs/walkthroughs/create-a-recipe.md
+++ b/docs/docs/walkthroughs/create-a-recipe.md
@@ -93,5 +93,5 @@ class SetUpVenvStep(Step):
         if os == "Windows":
             await sdk.run("python -m venv env; .\\env\\Scripts\\activate")
         else:
-            await sdk.run("python3 -m venv env && source env/bin/activate") # MacOS and Linux
+            await sdk.run("python3 -m venv .env && source .env/bin/activate") # MacOS and Linux
 ```
diff --git a/extension/react-app/src/components/ComboBox.tsx b/extension/react-app/src/components/ComboBox.tsx
index 1b7c60e6..46d8c4d3 100644
--- a/extension/react-app/src/components/ComboBox.tsx
+++ b/extension/react-app/src/components/ComboBox.tsx
@@ -105,7 +105,7 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
     <div className="flex px-2" ref={divRef} hidden={!isOpen}>
       <MainTextInput
         disabled={props.disabled}
-        placeholder="Ask anything:"
+        placeholder="Type an instruction or question."
         {...getInputProps({
           onKeyDown: (event) => {
             if (event.key === "Enter" && (!isOpen || items.length === 0)) {
diff --git a/extension/react-app/src/components/StepContainer.tsx b/extension/react-app/src/components/StepContainer.tsx
index ca142b06..48f970d7 100644
--- a/extension/react-app/src/components/StepContainer.tsx
+++ b/extension/react-app/src/components/StepContainer.tsx
@@ -194,15 +194,17 @@ function StepContainer(props: StepContainerProps) {
             <ReactMarkdown
               key={1}
               className="overflow-scroll"
-              components={{
-                pre: ({ node, ...props }) => {
-                  return (
-                    <CodeBlock
-                      children={props.children[0] as string}
-                    ></CodeBlock>
-                  );
-                },
-              }}
+              components={
+                {
+                  // pre: ({ node, ...props }) => {
+                  //   return (
+                  //     <CodeBlock
+                  //       children={props.children[0] as string}
+                  //     ></CodeBlock>
+                  //   );
+                  // },
+                }
+              }
             >
               {props.historyNode.step.description as any}
             </ReactMarkdown>
-- 
cgit v1.2.3-70-g09d2


From 2e98a6a61bc32e77c03feefe211dce0dd920ce0d Mon Sep 17 00:00:00 2001
From: Nate Sesti <sestinj@gmail.com>
Date: Tue, 13 Jun 2023 13:06:18 -0700
Subject: configurable default model and small updates

---
 continuedev/src/continuedev/core/config.py         |  5 ++--
 continuedev/src/continuedev/core/policy.py         |  2 +-
 continuedev/src/continuedev/core/sdk.py            | 27 ++++++++++++++++++++--
 .../recipes/AddTransformRecipe/steps.py            |  8 ++++---
 .../src/continuedev/recipes/DDtoBQRecipe/steps.py  |  2 +-
 .../recipes/DeployPipelineAirflowRecipe/main.py    |  3 ++-
 .../recipes/DeployPipelineAirflowRecipe/steps.py   | 14 ++++++-----
 continuedev/src/continuedev/steps/chat.py          |  2 +-
 continuedev/src/continuedev/steps/core/core.py     | 12 ++++++----
 continuedev/src/continuedev/steps/main.py          |  4 ++--
 extension/react-app/src/components/ComboBox.tsx    |  2 +-
 11 files changed, 55 insertions(+), 26 deletions(-)

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

diff --git a/continuedev/src/continuedev/core/config.py b/continuedev/src/continuedev/core/config.py
index ed056be9..ebd1fdb8 100644
--- a/continuedev/src/continuedev/core/config.py
+++ b/continuedev/src/continuedev/core/config.py
@@ -1,11 +1,9 @@
 import json
 import os
 from pydantic import BaseModel, validator
-from typing import List, Optional, Dict
+from typing import List, Literal, Optional, Dict
 import yaml
 
-from .main import Step
-
 
 class SlashCommand(BaseModel):
     name: str
@@ -21,6 +19,7 @@ class ContinueConfig(BaseModel):
     steps_on_startup: Optional[Dict[str, Dict]] = {}
     server_url: Optional[str] = None
     allow_anonymous_telemetry: Optional[bool] = True
+    default_model: Literal["gpt-3.5-turbo", "gpt-4", "starcoder"]
     slash_commands: Optional[List[SlashCommand]] = [
         # SlashCommand(
         #     name="pytest",
diff --git a/continuedev/src/continuedev/core/policy.py b/continuedev/src/continuedev/core/policy.py
index 2b50307a..9fcda882 100644
--- a/continuedev/src/continuedev/core/policy.py
+++ b/continuedev/src/continuedev/core/policy.py
@@ -26,7 +26,7 @@ class DemoPolicy(Policy):
         # At the very start, run initial Steps spcecified in the config
         if history.get_current() is None:
             return (
-                # MessageStep(name="Welcome to Continue!", message="") >>
+                MessageStep(name="Welcome to Continue!", message="You can type a question or instructions for a file edit in the text box. If you highlight code, edits will be localized to the highlighted range. Otherwise, the currently open file is taken as context. If you type '/', you can see the list of available slash commands.") >>
                 # SetupContinueWorkspaceStep() >>
                 # CreateCodebaseIndexChroma() >>
                 StepsOnStartupStep())
diff --git a/continuedev/src/continuedev/core/sdk.py b/continuedev/src/continuedev/core/sdk.py
index 1f4cdfb2..a54048b0 100644
--- a/continuedev/src/continuedev/core/sdk.py
+++ b/continuedev/src/continuedev/core/sdk.py
@@ -3,7 +3,7 @@ from functools import cached_property
 from typing import Coroutine, Union
 import os
 
-from ..steps.core.core import Gpt35EditCodeStep
+from ..steps.core.core import DefaultModelEditCodeStep
 from ..models.main import Range
 from .abstract_sdk import AbstractContinueSDK
 from .config import ContinueConfig, load_config
@@ -41,6 +41,29 @@ class Models:
             return OpenAI(api_key=api_key, default_model="gpt-3.5-turbo")
         return asyncio.get_event_loop().run_until_complete(load_gpt35())
 
+    @cached_property
+    def gpt4(self):
+        async def load_gpt4():
+            api_key = await self.sdk.get_user_secret(
+                'OPENAI_API_KEY', 'Please add your OpenAI API key to the .env file')
+            return OpenAI(api_key=api_key, default_model="gpt-4")
+        return asyncio.get_event_loop().run_until_complete(load_gpt4())
+
+    def __model_from_name(self, model_name: str):
+        if model_name == "starcoder":
+            return self.starcoder
+        elif model_name == "gpt35":
+            return self.gpt35
+        elif model_name == "gpt4":
+            return self.gpt4
+        else:
+            raise Exception(f"Unknown model {model_name}")
+
+    @cached_property
+    def default(self):
+        default_model = self.sdk.config.default_model
+        return self.__model_from_name(default_model) if default_model is not None else self.gpt35
+
 
 class ContinueSDK(AbstractContinueSDK):
     """The SDK provided as parameters to a step"""
@@ -85,7 +108,7 @@ class ContinueSDK(AbstractContinueSDK):
 
         await self.ide.setFileOpen(filepath)
         contents = await self.ide.readFile(filepath)
-        await self.run_step(Gpt35EditCodeStep(
+        await self.run_step(DefaultModelEditCodeStep(
             range_in_files=[RangeInFile(filepath=filepath, range=range) if range is not None else RangeInFile.from_entire_file(
                 filepath, contents)],
             user_input=prompt,
diff --git a/continuedev/src/continuedev/recipes/AddTransformRecipe/steps.py b/continuedev/src/continuedev/recipes/AddTransformRecipe/steps.py
index 6a743fb5..9744146c 100644
--- a/continuedev/src/continuedev/recipes/AddTransformRecipe/steps.py
+++ b/continuedev/src/continuedev/recipes/AddTransformRecipe/steps.py
@@ -49,15 +49,15 @@ class AddTransformStep(Step):
         filename = f'{source_name}_pipeline.py'
         abs_filepath = os.path.join(sdk.ide.workspace_directory, filename)
 
+        # Open the file and highlight the function to be edited
+        await sdk.ide.setFileOpen(abs_filepath)
+
         await sdk.run_step(MessageStep(message=dedent("""\
                 This step will customize your resource function with a transform of your choice:
                 - Add a filter or map transformation depending on your request
                 - Load the data into a local DuckDB instance
                 - Open up a Streamlit app for you to view the data"""), name="Write transformation function"))
 
-        # Open the file and highlight the function to be edited
-        await sdk.ide.setFileOpen(abs_filepath)
-
         with open(os.path.join(os.path.dirname(__file__), 'dlt_transform_docs.md')) as f:
             dlt_transform_docs = f.read()
 
@@ -77,6 +77,8 @@ class AddTransformStep(Step):
             name=f"Writing transform function {AI_ASSISTED_STRING}"
         )
 
+        await sdk.wait_for_user_confirmation("Press Continue to confirm that the changes are okay before we run the pipeline.")
+
         # run the pipeline and load the data
         await sdk.run(f'python3 {filename}', name="Run the pipeline", description=f"Running `python3 {filename}` to load the data into a local DuckDB instance")
 
diff --git a/continuedev/src/continuedev/recipes/DDtoBQRecipe/steps.py b/continuedev/src/continuedev/recipes/DDtoBQRecipe/steps.py
index 4b8971c2..6426df87 100644
--- a/continuedev/src/continuedev/recipes/DDtoBQRecipe/steps.py
+++ b/continuedev/src/continuedev/recipes/DDtoBQRecipe/steps.py
@@ -82,7 +82,7 @@ class LoadDataStep(Step):
                 docs = f.read()
 
             output = "Traceback" + output.split("Traceback")[-1]
-            suggestion = sdk.models.gpt35.complete(dedent(f"""\
+            suggestion = sdk.models.gpt4.complete(dedent(f"""\
                 When trying to load data into BigQuery, the following error occurred:
 
                 ```ascii
diff --git a/continuedev/src/continuedev/recipes/DeployPipelineAirflowRecipe/main.py b/continuedev/src/continuedev/recipes/DeployPipelineAirflowRecipe/main.py
index f3601c2d..503b0c85 100644
--- a/continuedev/src/continuedev/recipes/DeployPipelineAirflowRecipe/main.py
+++ b/continuedev/src/continuedev/recipes/DeployPipelineAirflowRecipe/main.py
@@ -5,7 +5,7 @@ from ...core.main import Step
 from ...core.sdk import ContinueSDK
 from ...steps.core.core import WaitForUserInputStep
 from ...steps.core.core import MessageStep
-from .steps import SetupPipelineStep, DeployAirflowStep
+from .steps import SetupPipelineStep, DeployAirflowStep, RunPipelineStep
 
 
 # https://github.com/dlt-hub/dlt-deploy-template/blob/master/airflow-composer/dag_template.py
@@ -46,5 +46,6 @@ class DeployPipelineAirflowRecipe(Step):
         )
         await sdk.run_step(
             SetupPipelineStep(source_name=source_name) >>
+            RunPipelineStep(source_name=source_name) >>
             DeployAirflowStep(source_name=source_name)
         )
diff --git a/continuedev/src/continuedev/recipes/DeployPipelineAirflowRecipe/steps.py b/continuedev/src/continuedev/recipes/DeployPipelineAirflowRecipe/steps.py
index c9749348..2f346b49 100644
--- a/continuedev/src/continuedev/recipes/DeployPipelineAirflowRecipe/steps.py
+++ b/continuedev/src/continuedev/recipes/DeployPipelineAirflowRecipe/steps.py
@@ -69,24 +69,26 @@ class DeployAirflowStep(Step):
             f'dlt --non-interactive deploy {self.source_name}_pipeline.py airflow-composer',
         ], description="Running `dlt deploy airflow` to deploy the dlt pipeline to Airflow", name="Deploy dlt pipeline to Airflow")
 
-        # Modify the DAG file
+        # Get filepaths, open the DAG file
         directory = await sdk.ide.getWorkspaceDirectory()
         pipeline_filepath = os.path.join(
             directory, f"{self.source_name}_pipeline.py")
         dag_filepath = os.path.join(
             directory, f"dags/dag_{self.source_name}_pipeline.py")
 
+        await sdk.ide.setFileOpen(dag_filepath)
+
         # Replace the pipeline name and dataset name
         await sdk.run_step(FindAndReplaceStep(filepath=pipeline_filepath, pattern="'pipeline_name'", replacement=f"'{self.source_name}_pipeline'"))
         await sdk.run_step(FindAndReplaceStep(filepath=pipeline_filepath, pattern="'dataset_name'", replacement=f"'{self.source_name}_data'"))
         await sdk.run_step(FindAndReplaceStep(filepath=pipeline_filepath, pattern="pipeline_or_source_script", replacement=f"{self.source_name}_pipeline"))
 
         # Prompt the user for the DAG schedule
-        edit_dag_range = Range.from_shorthand(18, 0, 23, 0)
-        await sdk.ide.highlightCode(range_in_file=RangeInFile(filepath=dag_filepath, range=edit_dag_range), color="#33993333")
-        response = await sdk.run_step(WaitForUserInputStep(prompt="When would you like this Airflow DAG to run? (e.g. every day, every Monday, every 1st of the month, etc.)"))
-        await sdk.edit_file(dag_filepath, prompt=f"Edit the DAG so that it runs at the following schedule: '{response.text}'",
-                            range=edit_dag_range)
+        # edit_dag_range = Range.from_shorthand(18, 0, 23, 0)
+        # await sdk.ide.highlightCode(range_in_file=RangeInFile(filepath=dag_filepath, range=edit_dag_range), color="#33993333")
+        # response = await sdk.run_step(WaitForUserInputStep(prompt="When would you like this Airflow DAG to run? (e.g. every day, every Monday, every 1st of the month, etc.)"))
+        # await sdk.edit_file(dag_filepath, prompt=f"Edit the DAG so that it runs at the following schedule: '{response.text}'",
+        #                     range=edit_dag_range)
 
         # Tell the user to check the schedule and fill in owner, email, other default_args
         await sdk.run_step(MessageStep(message="Fill in the owner, email, and other default_args in the DAG file with your own personal information. Then the DAG will be ready to run!", name="Fill in default_args"))
diff --git a/continuedev/src/continuedev/steps/chat.py b/continuedev/src/continuedev/steps/chat.py
index aadcfa8e..aca0ab2a 100644
--- a/continuedev/src/continuedev/steps/chat.py
+++ b/continuedev/src/continuedev/steps/chat.py
@@ -11,7 +11,7 @@ class SimpleChatStep(Step):
 
     async def run(self, sdk: ContinueSDK):
         self.description = ""
-        for chunk in sdk.models.gpt35.stream_chat(self.user_input, with_history=await sdk.get_chat_context()):
+        for chunk in sdk.models.default.stream_chat(self.user_input, with_history=await sdk.get_chat_context()):
             self.description += chunk
             await sdk.update_ui()
 
diff --git a/continuedev/src/continuedev/steps/core/core.py b/continuedev/src/continuedev/steps/core/core.py
index 8dc2478b..ff498b9b 100644
--- a/continuedev/src/continuedev/steps/core/core.py
+++ b/continuedev/src/continuedev/steps/core/core.py
@@ -109,7 +109,7 @@ class ShellCommandsStep(Step):
         # return None
 
 
-class Gpt35EditCodeStep(Step):
+class DefaultModelEditCodeStep(Step):
     user_input: str
     range_in_files: List[RangeInFile]
     name: str = "Editing Code"
@@ -153,11 +153,13 @@ class Gpt35EditCodeStep(Step):
     async def describe(self, models: Models) -> Coroutine[str, None, None]:
         description = models.gpt35.complete(
             f"{self._prompt_and_completion}\n\nPlease give brief a description of the changes made above using markdown bullet points. Be concise and only mention changes made to the commit before, not prefix or suffix:")
-        self.name = models.gpt35.complete(
-            f"Write a short title for this description: {description}")
+        # self.name = models.gpt35.complete(
+        #     f"Write a short title for this description: {description}")
         return description
 
     async def run(self, sdk: ContinueSDK) -> Coroutine[Observation, None, None]:
+        self.name = self.user_input
+
         rif_with_contents = []
         for range_in_file in self.range_in_files:
             file_contents = await sdk.ide.readRangeInFile(range_in_file)
@@ -174,7 +176,7 @@ class Gpt35EditCodeStep(Step):
             prompt = self._prompt.format(
                 code=rif.contents, user_request=self.user_input, file_prefix=segs[0], file_suffix=segs[1])
 
-            completion = str(sdk.models.gpt35.complete(prompt))
+            completion = str(sdk.models.default.complete(prompt))
             eot_token = "<|endoftext|>"
             completion = completion.removesuffix(eot_token)
 
@@ -225,7 +227,7 @@ class EditFileStep(Step):
 
     async def run(self, sdk: ContinueSDK) -> Coroutine[Observation, None, None]:
         file_contents = await sdk.ide.readFile(self.filepath)
-        await sdk.run_step(Gpt35EditCodeStep(
+        await sdk.run_step(DefaultModelEditCodeStep(
             range_in_files=[RangeInFile.from_entire_file(
                 self.filepath, file_contents)],
             user_input=self.prompt
diff --git a/continuedev/src/continuedev/steps/main.py b/continuedev/src/continuedev/steps/main.py
index 36e4f519..0e42d8bf 100644
--- a/continuedev/src/continuedev/steps/main.py
+++ b/continuedev/src/continuedev/steps/main.py
@@ -15,7 +15,7 @@ from ..core.main import Step
 from ..core.sdk import ContinueSDK, Models
 from ..core.observation import Observation
 import subprocess
-from .core.core import Gpt35EditCodeStep
+from .core.core import DefaultModelEditCodeStep
 from ..libs.util.calculate_diff import calculate_diff2
 
 
@@ -287,7 +287,7 @@ class EditHighlightedCodeStep(Step):
             range_in_files = [RangeInFile.from_entire_file(
                 filepath, content) for filepath, content in contents.items()]
 
-        await sdk.run_step(Gpt35EditCodeStep(user_input=self.user_input, range_in_files=range_in_files))
+        await sdk.run_step(DefaultModelEditCodeStep(user_input=self.user_input, range_in_files=range_in_files))
 
 
 class FindCodeStep(Step):
diff --git a/extension/react-app/src/components/ComboBox.tsx b/extension/react-app/src/components/ComboBox.tsx
index 46d8c4d3..11d04974 100644
--- a/extension/react-app/src/components/ComboBox.tsx
+++ b/extension/react-app/src/components/ComboBox.tsx
@@ -105,7 +105,7 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
     <div className="flex px-2" ref={divRef} hidden={!isOpen}>
       <MainTextInput
         disabled={props.disabled}
-        placeholder="Type an instruction or question."
+        placeholder="Type instructions or a question. Highlighted code / the open file are used as context."
         {...getInputProps({
           onKeyDown: (event) => {
             if (event.key === "Enter" && (!isOpen || items.length === 0)) {
-- 
cgit v1.2.3-70-g09d2


From 9cf110602621f80d0971f698ee40e7d73d0fa2b7 Mon Sep 17 00:00:00 2001
From: Ty Dunn <ty@tydunn.com>
Date: Thu, 15 Jun 2023 11:35:17 -0700
Subject: adds /edit and /explain commands

---
 continuedev/src/continuedev/core/config.py         | 28 +++++-----------------
 continuedev/src/continuedev/core/policy.py         |  8 +------
 .../continuedev/libs/util/step_name_to_steps.py    | 18 ++++----------
 extension/package.json                             |  1 -
 extension/react-app/src/components/ComboBox.tsx    |  2 +-
 extension/src/README.md                            |  3 +--
 6 files changed, 14 insertions(+), 46 deletions(-)

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

diff --git a/continuedev/src/continuedev/core/config.py b/continuedev/src/continuedev/core/config.py
index 8ebdc145..a1c58399 100644
--- a/continuedev/src/continuedev/core/config.py
+++ b/continuedev/src/continuedev/core/config.py
@@ -27,37 +27,21 @@ class ContinueConfig(BaseModel):
         #     description="Write pytest unit tests for the current file",
         #     step_name="WritePytestsRecipe",
         #     params=??)
-
-        SlashCommand(
-            name="dlt",
-            description="Create a dlt pipeline",
-            step_name="CreatePipelineRecipe",
-        ),
         SlashCommand(
-            name="ddtobq",
-            description="Adjust a dlt pipeline to load data into BigQuery",
-            step_name="DDtoBQRecipe",
+            name="edit",
+            description="Edit code in the current file or the highlighted code",
+            step_name="EditHighlightedCodeStep",
         ),
         SlashCommand(
-            name="addtransform",
-            description="Add transforms to the chess.com API dlt pipeline.",
-            step_name="AddTransformRecipe",
-        ),
-        SlashCommand(
-            name="deployairflow",
-            description="Deploy a dlt pipeline to Airflow",
-            step_name="DeployPipelineAirflowRecipe",
+            name="explain",
+            description="Reply to instructions or a question with previous steps as context",
+            step_name="SimpleChatStep",
         ),
         SlashCommand(
             name="comment",
             description="Write comments for the current file or highlighted code",
             step_name="CommentCodeStep",
         ),
-        SlashCommand(
-            name="pytest",
-            description="Write pytest unit tests for the current file",
-            step_name="WritePytestsRecipe",
-        ),
         SlashCommand(
             name="feedback",
             description="Send feedback to improve Continue",
diff --git a/continuedev/src/continuedev/core/policy.py b/continuedev/src/continuedev/core/policy.py
index 9fcda882..255f598d 100644
--- a/continuedev/src/continuedev/core/policy.py
+++ b/continuedev/src/continuedev/core/policy.py
@@ -26,7 +26,7 @@ class DemoPolicy(Policy):
         # At the very start, run initial Steps spcecified in the config
         if history.get_current() is None:
             return (
-                MessageStep(name="Welcome to Continue!", message="You can type a question or instructions for a file edit in the text box. If you highlight code, edits will be localized to the highlighted range. Otherwise, the currently open file is taken as context. If you type '/', you can see the list of available slash commands.") >>
+                MessageStep(name="Welcome to Continue!", message="Type '/' to see the list of available slash commands. If you highlight code, edits and explanations will be localized to the highlighted range. Otherwise, the currently open file is used. In both cases, the code is combined with the previous steps to construct the context.") >>
                 # SetupContinueWorkspaceStep() >>
                 # CreateCodebaseIndexChroma() >>
                 StepsOnStartupStep())
@@ -45,12 +45,6 @@ class DemoPolicy(Policy):
                         params["user_input"] = after_command
                         return get_step_from_name(slash_command.step_name, params)
 
-            if "/ask" in user_input:
-                return AnswerQuestionChroma(question=" ".join(user_input.split(" ")[1:]))
-            elif "/edit" in user_input:
-                return EditFileChroma(request=" ".join(user_input.split(" ")[1:]))
-            elif "/step" in user_input:
-                return ContinueStepStep(prompt=" ".join(user_input.split(" ")[1:]))
             # return EditHighlightedCodeStep(user_input=user_input)
             return NLDecisionStep(user_input=user_input, steps=[
                 (EditHighlightedCodeStep(user_input=user_input),
diff --git a/continuedev/src/continuedev/libs/util/step_name_to_steps.py b/continuedev/src/continuedev/libs/util/step_name_to_steps.py
index fd1aab5b..4dd9c430 100644
--- a/continuedev/src/continuedev/libs/util/step_name_to_steps.py
+++ b/continuedev/src/continuedev/libs/util/step_name_to_steps.py
@@ -2,23 +2,15 @@ from typing import Dict
 
 from ...core.main import Step
 from ...steps.core.core import UserInputStep
-from ...recipes.CreatePipelineRecipe.main import CreatePipelineRecipe
-from ...recipes.DDtoBQRecipe.main import DDtoBQRecipe
-from ...recipes.DeployPipelineAirflowRecipe.main import DeployPipelineAirflowRecipe
-from ...recipes.DDtoBQRecipe.main import DDtoBQRecipe
-from ...recipes.AddTransformRecipe.main import AddTransformRecipe
-from ...recipes.WritePytestsRecipe.main import WritePytestsRecipe
+from ...steps.main import EditHighlightedCodeStep
+from ...steps.chat import SimpleChatStep
 from ...steps.comment_code import CommentCodeStep
 from ...steps.feedback import FeedbackStep
 
 step_name_to_step_class = {
     "UserInputStep": UserInputStep,
-    "CreatePipelineRecipe": CreatePipelineRecipe,
-    "DDtoBQRecipe": DDtoBQRecipe,
-    "DeployPipelineAirflowRecipe": DeployPipelineAirflowRecipe,
-    "AddTransformRecipe": AddTransformRecipe,
-    "DDtoBQRecipe": DDtoBQRecipe,
-    "WritePytestsRecipe": WritePytestsRecipe,
+    "EditHighlightedCodeStep": EditHighlightedCodeStep,
+    "SimpleChatStep": SimpleChatStep,
     "CommentCodeStep": CommentCodeStep,
     "FeedbackStep": FeedbackStep,
 }
@@ -30,4 +22,4 @@ def get_step_from_name(step_name: str, params: Dict) -> Step:
     except:
         print(
             f"Incorrect parameters for step {step_name}. Parameters provided were: {params}")
-        raise
+        raise
\ No newline at end of file
diff --git a/extension/package.json b/extension/package.json
index 13cc92a2..c41c3565 100644
--- a/extension/package.json
+++ b/extension/package.json
@@ -111,7 +111,6 @@
     "clientgen": "rm -rf src/client/ && npx @openapitools/openapi-generator-cli generate -i ../schema/openapi.json -g typescript-fetch -o src/client/ --additional-properties=supportsES6=true,npmVersion=8.19.2,typescriptThreePlus=true",
     "typegen": "node scripts/typegen.js",
     "rebuild": "electron-rebuild -v 19.1.8 node-pty",
-    "compile": "tsc -p ./",
     "watch": "tsc -watch -p ./",
     "pretest": "npm run compile && npm run lint",
     "lint": "eslint src --ext ts",
diff --git a/extension/react-app/src/components/ComboBox.tsx b/extension/react-app/src/components/ComboBox.tsx
index 11d04974..ace0605e 100644
--- a/extension/react-app/src/components/ComboBox.tsx
+++ b/extension/react-app/src/components/ComboBox.tsx
@@ -105,7 +105,7 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
     <div className="flex px-2" ref={divRef} hidden={!isOpen}>
       <MainTextInput
         disabled={props.disabled}
-        placeholder="Type instructions or a question. Highlighted code / the open file are used as context."
+        placeholder="Type '/' to see the list of available slash commands..."
         {...getInputProps({
           onKeyDown: (event) => {
             if (event.key === "Enter" && (!isOpen || items.length === 0)) {
diff --git a/extension/src/README.md b/extension/src/README.md
index c46de79f..4969890f 100644
--- a/extension/src/README.md
+++ b/extension/src/README.md
@@ -20,9 +20,8 @@
 
 9. `cmd+shift+p` to look at developer console and select Continue commands
 
-10. Every time you make changes to the code, you need to run `npm run compile`
+10. Every time you make changes to the code, you need to run `npm run esbuild` unless you make changes inside of `react-app` and then you need to run `npm run build` from there
 
-11. If you run into a "command not found" error, try running `npm run rebuild` and then `npm run compile`
 
 ## Alternative: Install from source
 
-- 
cgit v1.2.3-70-g09d2


From ccca93eb18ceac9769ebac380bca47f21a691d99 Mon Sep 17 00:00:00 2001
From: Nate Sesti <sestinj@gmail.com>
Date: Thu, 15 Jun 2023 20:50:52 -0700
Subject: tab autocomplete for slash commands

---
 extension/react-app/src/components/ComboBox.tsx | 3 +++
 1 file changed, 3 insertions(+)

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

diff --git a/extension/react-app/src/components/ComboBox.tsx b/extension/react-app/src/components/ComboBox.tsx
index ace0605e..2b140567 100644
--- a/extension/react-app/src/components/ComboBox.tsx
+++ b/extension/react-app/src/components/ComboBox.tsx
@@ -113,6 +113,9 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
               (event.nativeEvent as any).preventDownshiftDefault = true;
               if (props.onEnter) props.onEnter(event);
               setInputValue("");
+            } else if (event.key === "Tab" && items.length > 0) {
+              setInputValue(items[0].name);
+              event.preventDefault();
             }
           },
           ref: ref as any,
-- 
cgit v1.2.3-70-g09d2


From 5a6fa9ae784c5942f1e37c7a0ae3acdd6337c459 Mon Sep 17 00:00:00 2001
From: Nate Sesti <sestinj@gmail.com>
Date: Fri, 16 Jun 2023 23:42:10 -0700
Subject: polishing

---
 continuedev/src/continuedev/core/config.py         | 15 ++++++++++--
 continuedev/src/continuedev/core/sdk.py            |  3 +++
 .../src/continuedev/libs/llm/proxy_server.py       |  2 +-
 .../continuedev/libs/util/step_name_to_steps.py    |  2 ++
 continuedev/src/continuedev/steps/clear_history.py | 10 ++++++++
 continuedev/src/continuedev/steps/core/core.py     |  2 ++
 extension/package-lock.json                        |  4 ++--
 extension/package.json                             |  8 +++----
 extension/react-app/src/components/ComboBox.tsx    | 21 ++++++++++++++++
 .../src/components/HeaderButtonWithText.tsx        |  4 +---
 .../react-app/src/components/StepContainer.tsx     |  1 -
 extension/react-app/src/components/TextDialog.tsx  | 28 ++++++++++++++++++++--
 extension/react-app/src/tabs/gui.tsx               |  3 +++
 extension/src/commands.ts                          |  5 +---
 extension/src/continueIdeClient.ts                 |  2 +-
 15 files changed, 90 insertions(+), 20 deletions(-)
 create mode 100644 continuedev/src/continuedev/steps/clear_history.py

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

diff --git a/continuedev/src/continuedev/core/config.py b/continuedev/src/continuedev/core/config.py
index 8f703758..1ee3a7f8 100644
--- a/continuedev/src/continuedev/core/config.py
+++ b/continuedev/src/continuedev/core/config.py
@@ -52,6 +52,11 @@ class ContinueConfig(BaseModel):
             name="feedback",
             description="Send feedback to improve Continue",
             step_name="FeedbackStep",
+        ),
+        SlashCommand(
+            name="clear",
+            description="Clear step history",
+            step_name="ClearHistoryStep",
         )
     ]
     on_traceback: Optional[List[OnTracebackSteps]] = [
@@ -68,10 +73,16 @@ def load_config(config_file: str) -> ContinueConfig:
     _, ext = os.path.splitext(config_file)
     if ext == '.yaml':
         with open(config_file, 'r') as f:
-            config_dict = yaml.safe_load(f)
+            try:
+                config_dict = yaml.safe_load(f)
+            except:
+                return ContinueConfig()
     elif ext == '.json':
         with open(config_file, 'r') as f:
-            config_dict = json.load(f)
+            try:
+                config_dict = json.load(f)
+            except:
+                return ContinueConfig()
     else:
         raise ValueError(f'Unknown config file extension: {ext}')
     return ContinueConfig(**config_dict)
diff --git a/continuedev/src/continuedev/core/sdk.py b/continuedev/src/continuedev/core/sdk.py
index 7639d010..4ab2f027 100644
--- a/continuedev/src/continuedev/core/sdk.py
+++ b/continuedev/src/continuedev/core/sdk.py
@@ -192,3 +192,6 @@ class ContinueSDK(AbstractContinueSDK):
 
     async def update_ui(self):
         await self.__autopilot.update_subscribers()
+
+    async def clear_history(self):
+        await self.__autopilot.clear_history()
diff --git a/continuedev/src/continuedev/libs/llm/proxy_server.py b/continuedev/src/continuedev/libs/llm/proxy_server.py
index 93f2d48a..dd0d3aca 100644
--- a/continuedev/src/continuedev/libs/llm/proxy_server.py
+++ b/continuedev/src/continuedev/libs/llm/proxy_server.py
@@ -18,7 +18,7 @@ CHAT_MODELS = {
 }
 
 # SERVER_URL = "http://127.0.0.1:8080"
-SERVER_URL = "https://proxy-server-l6vsfbzhba-uc.a.run.app"
+SERVER_URL = "https://proxy-server-l6vsfbzhba-uw.a.run.app"
 
 
 class ProxyServer(LLM):
diff --git a/continuedev/src/continuedev/libs/util/step_name_to_steps.py b/continuedev/src/continuedev/libs/util/step_name_to_steps.py
index 2c4474af..f431f317 100644
--- a/continuedev/src/continuedev/libs/util/step_name_to_steps.py
+++ b/continuedev/src/continuedev/libs/util/step_name_to_steps.py
@@ -11,6 +11,7 @@ from ...recipes.CreatePipelineRecipe.main import CreatePipelineRecipe
 from ...recipes.DDtoBQRecipe.main import DDtoBQRecipe
 from ...recipes.DeployPipelineAirflowRecipe.main import DeployPipelineAirflowRecipe
 from ...steps.on_traceback import DefaultOnTracebackStep
+from ...steps.clear_history import ClearHistoryStep
 
 # This mapping is used to convert from string in ContinueConfig json to corresponding Step class.
 # Used for example in slash_commands and steps_on_startup
@@ -25,6 +26,7 @@ step_name_to_step_class = {
     "DDtoBQRecipe": DDtoBQRecipe,
     "DeployPipelineAirflowRecipe": DeployPipelineAirflowRecipe,
     "DefaultOnTracebackStep": DefaultOnTracebackStep,
+    "ClearHistoryStep": ClearHistoryStep,
 }
 
 
diff --git a/continuedev/src/continuedev/steps/clear_history.py b/continuedev/src/continuedev/steps/clear_history.py
new file mode 100644
index 00000000..a875c6d3
--- /dev/null
+++ b/continuedev/src/continuedev/steps/clear_history.py
@@ -0,0 +1,10 @@
+from ..core.main import Step
+from ..core.sdk import ContinueSDK
+
+
+class ClearHistoryStep(Step):
+    name: str = "Clear History"
+    hide: bool = True
+
+    async def run(self, sdk: ContinueSDK):
+        await sdk.clear_history()
diff --git a/continuedev/src/continuedev/steps/core/core.py b/continuedev/src/continuedev/steps/core/core.py
index 59af5f38..330f60ed 100644
--- a/continuedev/src/continuedev/steps/core/core.py
+++ b/continuedev/src/continuedev/steps/core/core.py
@@ -186,6 +186,8 @@ class DefaultModelEditCodeStep(Step):
             completion = completion.removesuffix(eot_token)
 
             # Remove tags and If it accidentally includes prefix or suffix, remove it
+            if completion.strip().startswith("```"):
+                completion = completion.strip().removeprefix("```").removesuffix("```")
             completion = completion.replace("<file_prefix>", "").replace("<file_suffix>", "").replace(
                 "<commit_before>", "").replace("<commit_msg>", "").replace("<commit_after>", "")
             completion = completion.removeprefix(segs[0])
diff --git a/extension/package-lock.json b/extension/package-lock.json
index 86c816e0..92df6a4f 100644
--- a/extension/package-lock.json
+++ b/extension/package-lock.json
@@ -1,12 +1,12 @@
 {
   "name": "continue",
-  "version": "0.0.47",
+  "version": "0.0.50",
   "lockfileVersion": 2,
   "requires": true,
   "packages": {
     "": {
       "name": "continue",
-      "version": "0.0.47",
+      "version": "0.0.50",
       "license": "Apache-2.0",
       "dependencies": {
         "@electron/rebuild": "^3.2.10",
diff --git a/extension/package.json b/extension/package.json
index 3a3927f3..a875c82d 100644
--- a/extension/package.json
+++ b/extension/package.json
@@ -14,7 +14,7 @@
   "displayName": "Continue",
   "pricing": "Free",
   "description": "Refine code 10x faster",
-  "version": "0.0.47",
+  "version": "0.0.50",
   "publisher": "Continue",
   "engines": {
     "vscode": "^1.74.0"
@@ -86,8 +86,8 @@
       "activitybar": [
         {
           "id": "continue",
-          "title": "Continue",
-          "icon": "media/continue-gradient.png"
+          "title": "Continue  ",
+          "icon": "react-app/dist/continue_arrow.png"
         }
       ]
     },
@@ -96,7 +96,7 @@
         {
           "type": "webview",
           "id": "continue.continueGUIView",
-          "name": ")",
+          "name": "  )",
           "visibility": "visible"
         }
       ]
diff --git a/extension/react-app/src/components/ComboBox.tsx b/extension/react-app/src/components/ComboBox.tsx
index 2b140567..29f8a53b 100644
--- a/extension/react-app/src/components/ComboBox.tsx
+++ b/extension/react-app/src/components/ComboBox.tsx
@@ -68,6 +68,9 @@ interface ComboBoxProps {
 }
 
 const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
+  const [history, setHistory] = React.useState<string[]>([]);
+  // The position of the current command you are typing now, so the one that will be appended to history once you press enter
+  const [positionInHistory, setPositionInHistory] = React.useState<number>(0);
   const [items, setItems] = React.useState(props.items);
   const {
     isOpen,
@@ -113,9 +116,27 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
               (event.nativeEvent as any).preventDownshiftDefault = true;
               if (props.onEnter) props.onEnter(event);
               setInputValue("");
+              const value = event.currentTarget.value;
+              if (value !== "") {
+                setPositionInHistory(history.length + 1);
+                setHistory([...history, value]);
+              }
             } else if (event.key === "Tab" && items.length > 0) {
               setInputValue(items[0].name);
               event.preventDefault();
+            } else if (event.key === "ArrowUp" && !isOpen) {
+              if (positionInHistory == 0) return;
+              setInputValue(history[positionInHistory - 1]);
+              setPositionInHistory((prev) => prev - 1);
+            } else if (event.key === "ArrowDown" && !isOpen) {
+              if (positionInHistory >= history.length - 1) {
+                setInputValue("");
+              } else {
+                setInputValue(history[positionInHistory + 1]);
+              }
+              setPositionInHistory((prev) =>
+                Math.min(prev + 1, history.length)
+              );
             }
           },
           ref: ref as any,
diff --git a/extension/react-app/src/components/HeaderButtonWithText.tsx b/extension/react-app/src/components/HeaderButtonWithText.tsx
index c4f22211..f9483f0f 100644
--- a/extension/react-app/src/components/HeaderButtonWithText.tsx
+++ b/extension/react-app/src/components/HeaderButtonWithText.tsx
@@ -15,9 +15,7 @@ const HeaderButtonWithText = (props: HeaderButtonWithTextProps) => {
       style={{ padding: "3px" }}
       onMouseEnter={() => setHover(true)}
       onMouseLeave={() => {
-        setTimeout(() => {
-          setHover(false);
-        }, 100);
+        setHover(false);
       }}
       onClick={props.onClick}
     >
diff --git a/extension/react-app/src/components/StepContainer.tsx b/extension/react-app/src/components/StepContainer.tsx
index 480f517f..7adbd7c2 100644
--- a/extension/react-app/src/components/StepContainer.tsx
+++ b/extension/react-app/src/components/StepContainer.tsx
@@ -63,7 +63,6 @@ const HeaderDiv = styled.div<{ error: boolean }>`
 const ContentDiv = styled.div`
   padding: 8px;
   padding-left: 16px;
-  background-color: ${vscBackground};
 `;
 
 const OnHoverDiv = styled.div`
diff --git a/extension/react-app/src/components/TextDialog.tsx b/extension/react-app/src/components/TextDialog.tsx
index 167e12cf..31a385d5 100644
--- a/extension/react-app/src/components/TextDialog.tsx
+++ b/extension/react-app/src/components/TextDialog.tsx
@@ -1,5 +1,5 @@
 // Write a component that displays a dialog box with a text field and a button.
-import React, { useState } from "react";
+import React, { useEffect, useState } from "react";
 import styled from "styled-components";
 import { Button, buttonColor, secondaryDark, vscBackground } from ".";
 
@@ -28,6 +28,10 @@ const TextArea = styled.textarea`
   padding: 8px;
   outline: 1px solid black;
   font-family: Arial, Helvetica, sans-serif;
+
+  &:focus {
+    outline: 1px solid orange;
+  }
 `;
 
 const P = styled.p`
@@ -38,19 +42,39 @@ const P = styled.p`
 const TextDialog = (props: {
   showDialog: boolean;
   onEnter: (text: string) => void;
+  onClose: () => void;
 }) => {
   const [text, setText] = useState("");
   const textAreaRef = React.createRef<HTMLTextAreaElement>();
 
+  useEffect(() => {
+    if (textAreaRef.current) {
+      textAreaRef.current.focus();
+    }
+  }, [props.showDialog]);
+
   return (
     <DialogContainer hidden={!props.showDialog}>
       <Dialog>
         <P>Thanks for your feedback. We'll get back to you soon!</P>
-        <TextArea cols={50} rows={10} ref={textAreaRef}></TextArea>
+        <TextArea
+          cols={50}
+          rows={10}
+          ref={textAreaRef}
+          onKeyDown={(e) => {
+            if (e.key === "Enter" && e.metaKey && textAreaRef.current) {
+              props.onEnter(textAreaRef.current.value);
+              setText("");
+            } else if (e.key === "Escape") {
+              props.onClose();
+            }
+          }}
+        />
         <Button
           onClick={() => {
             if (textAreaRef.current) {
               props.onEnter(textAreaRef.current.value);
+              setText("");
             }
           }}
         >
diff --git a/extension/react-app/src/tabs/gui.tsx b/extension/react-app/src/tabs/gui.tsx
index 994cb896..63da595f 100644
--- a/extension/react-app/src/tabs/gui.tsx
+++ b/extension/react-app/src/tabs/gui.tsx
@@ -297,6 +297,9 @@ function GUI(props: GUIProps) {
           client?.sendMainInput(`/feedback ${text}`);
           setShowFeedbackDialog(false);
         }}
+        onClose={() => {
+          setShowFeedbackDialog(false);
+        }}
       ></TextDialog>
 
       <TopGUIDiv
diff --git a/extension/src/commands.ts b/extension/src/commands.ts
index c98cd3c3..5392a7a3 100644
--- a/extension/src/commands.ts
+++ b/extension/src/commands.ts
@@ -61,12 +61,9 @@ const commandsMap: { [command: string]: (...args: any) => any } = {
   "continue.suggestionUp": suggestionUpCommand,
   "continue.acceptSuggestion": acceptSuggestionCommand,
   "continue.rejectSuggestion": rejectSuggestionCommand,
-  "continue.openContinueGUI": () => {
-    ideProtocolClient.openGUI();
-  },
   "continue.focusContinueInput": async () => {
     if (!debugPanelWebview) {
-      await ideProtocolClient.openGUI();
+      vscode.commands.executeCommand("continue.continueGUIView.focus");
     }
     debugPanelWebview?.postMessage({
       type: "focusContinueInput",
diff --git a/extension/src/continueIdeClient.ts b/extension/src/continueIdeClient.ts
index 9a93a4ef..b4937ac4 100644
--- a/extension/src/continueIdeClient.ts
+++ b/extension/src/continueIdeClient.ts
@@ -192,7 +192,7 @@ class IdeProtocolClient {
   async getUserSecret(key: string) {
     // Check if secret already exists in VS Code settings (global)
     let secret = vscode.workspace.getConfiguration("continue").get(key);
-    if (typeof secret !== "undefined") return secret;
+    if (typeof secret !== "undefined" && secret !== null) return secret;
 
     // If not, ask user for secret
     secret = await vscode.window.showInputBox({
-- 
cgit v1.2.3-70-g09d2


From 5ae9fdcf9aadf57101ecfd4b7635f4325f53d392 Mon Sep 17 00:00:00 2001
From: Nate Sesti <sestinj@gmail.com>
Date: Sat, 17 Jun 2023 10:46:54 -0700
Subject: ui details

---
 .../src/continuedev/libs/llm/proxy_server.py       |   2 ++
 extension/package-lock.json                        |   4 ++--
 extension/package.json                             |   2 +-
 extension/react-app/src/components/ComboBox.tsx    |   4 ++--
 .../react-app/src/components/StepContainer.tsx     |  23 +++++++++++++--------
 extension/react-app/src/tabs/gui.tsx               |  19 +++++++++++++++++
 .../scripts/continuedev-0.1.1-py3-none-any.whl     | Bin 84291 -> 84332 bytes
 extension/src/bridge.ts                            |   8 +++++++
 8 files changed, 48 insertions(+), 14 deletions(-)

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

diff --git a/continuedev/src/continuedev/libs/llm/proxy_server.py b/continuedev/src/continuedev/libs/llm/proxy_server.py
index dd0d3aca..84c94d62 100644
--- a/continuedev/src/continuedev/libs/llm/proxy_server.py
+++ b/continuedev/src/continuedev/libs/llm/proxy_server.py
@@ -23,12 +23,14 @@ SERVER_URL = "https://proxy-server-l6vsfbzhba-uw.a.run.app"
 
 class ProxyServer(LLM):
     unique_id: str
+    name: str
     default_model: Literal["gpt-3.5-turbo", "gpt-4"]
 
     def __init__(self, unique_id: str, default_model: Literal["gpt-3.5-turbo", "gpt-4"], system_message: str = None):
         self.unique_id = unique_id
         self.default_model = default_model
         self.system_message = system_message
+        self.name = default_model
 
     @cached_property
     def __encoding_for_model(self):
diff --git a/extension/package-lock.json b/extension/package-lock.json
index 92df6a4f..64fa3660 100644
--- a/extension/package-lock.json
+++ b/extension/package-lock.json
@@ -1,12 +1,12 @@
 {
   "name": "continue",
-  "version": "0.0.50",
+  "version": "0.0.52",
   "lockfileVersion": 2,
   "requires": true,
   "packages": {
     "": {
       "name": "continue",
-      "version": "0.0.50",
+      "version": "0.0.52",
       "license": "Apache-2.0",
       "dependencies": {
         "@electron/rebuild": "^3.2.10",
diff --git a/extension/package.json b/extension/package.json
index a875c82d..bf4f5eb3 100644
--- a/extension/package.json
+++ b/extension/package.json
@@ -14,7 +14,7 @@
   "displayName": "Continue",
   "pricing": "Free",
   "description": "Refine code 10x faster",
-  "version": "0.0.50",
+  "version": "0.0.52",
   "publisher": "Continue",
   "engines": {
     "vscode": "^1.74.0"
diff --git a/extension/react-app/src/components/ComboBox.tsx b/extension/react-app/src/components/ComboBox.tsx
index 29f8a53b..e855ebe5 100644
--- a/extension/react-app/src/components/ComboBox.tsx
+++ b/extension/react-app/src/components/ComboBox.tsx
@@ -124,11 +124,11 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
             } else if (event.key === "Tab" && items.length > 0) {
               setInputValue(items[0].name);
               event.preventDefault();
-            } else if (event.key === "ArrowUp" && !isOpen) {
+            } else if (event.key === "ArrowUp") {
               if (positionInHistory == 0) return;
               setInputValue(history[positionInHistory - 1]);
               setPositionInHistory((prev) => prev - 1);
-            } else if (event.key === "ArrowDown" && !isOpen) {
+            } else if (event.key === "ArrowDown") {
               if (positionInHistory >= history.length - 1) {
                 setInputValue("");
               } else {
diff --git a/extension/react-app/src/components/StepContainer.tsx b/extension/react-app/src/components/StepContainer.tsx
index 7adbd7c2..4c98b04d 100644
--- a/extension/react-app/src/components/StepContainer.tsx
+++ b/extension/react-app/src/components/StepContainer.tsx
@@ -31,7 +31,9 @@ interface StepContainerProps {
   onUserInput: (input: string) => void;
   onRetry: () => void;
   onDelete: () => void;
-  open?: boolean;
+  open: boolean;
+  onToggleAll: () => void;
+  onToggle: () => void;
 }
 
 const MainDiv = styled.div<{ stepDepth: number; inFuture: boolean }>`
@@ -81,9 +83,6 @@ const MarkdownPre = styled.pre`
 const MarkdownCode = styled.code``;
 
 function StepContainer(props: StepContainerProps) {
-  const [open, setOpen] = useState(
-    typeof props.open === "undefined" ? true : props.open
-  );
   const [isHovered, setIsHovered] = useState(false);
   const naturalLanguageInputRef = useRef<HTMLTextAreaElement>(null);
   const userInputRef = useRef<HTMLInputElement>(null);
@@ -119,19 +118,25 @@ function StepContainer(props: StepContainerProps) {
       }}
       hidden={props.historyNode.step.hide as any}
     >
-      <StepContainerDiv open={open}>
+      <StepContainerDiv open={props.open}>
         <GradientBorder
           borderColor={
             props.historyNode.observation?.error ? "#f00" : undefined
           }
           className="overflow-hidden cursor-pointer"
-          onClick={() => setOpen((prev) => !prev)}
+          onClick={(e) => {
+            if (props.open && e.metaKey) {
+              props.onToggleAll();
+            } else {
+              props.onToggle();
+            }
+          }}
         >
           <HeaderDiv
             error={props.historyNode.observation?.error ? true : false}
           >
             <h4 className="m-2">
-              {open ? (
+              {props.open ? (
                 <ChevronDown size="1.4em" />
               ) : (
                 <ChevronRight size="1.4em" />
@@ -174,8 +179,8 @@ function StepContainer(props: StepContainerProps) {
             </>
           </HeaderDiv>
         </GradientBorder>
-        <ContentDiv hidden={!open}>
-          {open && false && (
+        <ContentDiv hidden={!props.open}>
+          {props.open && false && (
             <>
               <pre className="overflow-x-scroll">
                 Step Details:
diff --git a/extension/react-app/src/tabs/gui.tsx b/extension/react-app/src/tabs/gui.tsx
index 63da595f..6aa20e0e 100644
--- a/extension/react-app/src/tabs/gui.tsx
+++ b/extension/react-app/src/tabs/gui.tsx
@@ -54,6 +54,7 @@ function GUI(props: GUIProps) {
   const [availableSlashCommands, setAvailableSlashCommands] = useState<
     { name: string; description: string }[]
   >([]);
+  const [stepsOpen, setStepsOpen] = useState<boolean[]>([]);
   const [history, setHistory] = useState<History | undefined>();
   // {
   //   timeline: [
@@ -212,6 +213,15 @@ function GUI(props: GUIProps) {
       setWaitingForSteps(state.active);
       setHistory(state.history);
       setUserInputQueue(state.user_input_queue);
+      const nextStepsOpen = [...stepsOpen];
+      for (
+        let i = nextStepsOpen.length;
+        i < state.history.timeline.length;
+        i++
+      ) {
+        nextStepsOpen.push(true);
+      }
+      setStepsOpen(nextStepsOpen);
 
       if (shouldScrollToBottom) {
         scrollToBottom();
@@ -321,6 +331,15 @@ function GUI(props: GUIProps) {
         {history?.timeline.map((node: HistoryNode, index: number) => {
           return (
             <StepContainer
+              open={stepsOpen[index]}
+              onToggle={() => {
+                const nextStepsOpen = [...stepsOpen];
+                nextStepsOpen[index] = !nextStepsOpen[index];
+                setStepsOpen(nextStepsOpen);
+              }}
+              onToggleAll={() => {
+                setStepsOpen((prev) => prev.map(() => !prev[index]));
+              }}
               key={index}
               onUserInput={(input: string) => {
                 onStepUserInput(input, index);
diff --git a/extension/scripts/continuedev-0.1.1-py3-none-any.whl b/extension/scripts/continuedev-0.1.1-py3-none-any.whl
index b0b84230..2e45a933 100644
Binary files a/extension/scripts/continuedev-0.1.1-py3-none-any.whl and b/extension/scripts/continuedev-0.1.1-py3-none-any.whl differ
diff --git a/extension/src/bridge.ts b/extension/src/bridge.ts
index 3e21a205..b0fdafa7 100644
--- a/extension/src/bridge.ts
+++ b/extension/src/bridge.ts
@@ -10,6 +10,7 @@ import {
 } from "./client";
 import { convertSingleToDoubleQuoteJSON } from "./util/util";
 import { getExtensionUri } from "./util/vscode";
+import { extensionContext } from "./activation/activate";
 const axios = require("axios").default;
 const util = require("util");
 const exec = util.promisify(require("child_process").exec);
@@ -52,6 +53,13 @@ export function get_api_url() {
 const API_URL = get_api_url();
 
 export function getContinueServerUrl() {
+  // If in debug mode, always use 8001
+  if (
+    extensionContext &&
+    extensionContext.extensionMode === vscode.ExtensionMode.Development
+  ) {
+    return "http://localhost:8001";
+  }
   return (
     vscode.workspace.getConfiguration("continue").get<string>("serverUrl") ||
     "http://localhost:8000"
-- 
cgit v1.2.3-70-g09d2


From f197e701a21e40f65b17ba2a5a25bb0cda7003f2 Mon Sep 17 00:00:00 2001
From: Nate Sesti <sestinj@gmail.com>
Date: Sat, 17 Jun 2023 12:06:25 -0700
Subject: more ui details

---
 extension/react-app/src/components/CodeBlock.tsx   |  63 +++++++----
 extension/react-app/src/components/ComboBox.tsx    |  22 +++-
 .../react-app/src/components/StepContainer.tsx     | 118 +++++++++------------
 extension/react-app/src/components/TextDialog.tsx  |  77 +++++++++-----
 extension/react-app/src/components/index.ts        |  20 ----
 extension/react-app/src/index.css                  |   5 +-
 extension/react-app/src/tabs/gui.tsx               |   2 +
 7 files changed, 164 insertions(+), 143 deletions(-)

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

diff --git a/extension/react-app/src/components/CodeBlock.tsx b/extension/react-app/src/components/CodeBlock.tsx
index eedae3fb..c4524a51 100644
--- a/extension/react-app/src/components/CodeBlock.tsx
+++ b/extension/react-app/src/components/CodeBlock.tsx
@@ -1,44 +1,62 @@
 import hljs from "highlight.js";
-import { useEffect } from "react";
+import { useEffect, useState } from "react";
 import styled from "styled-components";
-import { defaultBorderRadius, vscBackground } from ".";
+import { defaultBorderRadius, secondaryDark, vscBackground } from ".";
 
-import { Clipboard } from "@styled-icons/heroicons-outline";
+import { Clipboard, CheckCircle } from "@styled-icons/heroicons-outline";
 
 const StyledPre = styled.pre`
   overflow-y: scroll;
   word-wrap: normal;
-  border: 1px solid gray;
+  border: 0.5px solid gray;
   border-radius: ${defaultBorderRadius};
-  background-color: ${vscBackground};
+  background-color: ${secondaryDark};
   padding: 8px;
+  padding-top: 14px;
+  padding-bottom: 16px;
 `;
 
-const StyledCode = styled.code`
-  background-color: ${vscBackground};
-`;
+const StyledCode = styled.code``;
 
-const StyledCopyButton = styled.button`
+const StyledCopyButton = styled.button<{ visible: boolean }>`
+  /* position: relative; */
   float: right;
   border: none;
-  background-color: ${vscBackground};
+  background-color: transparent;
   cursor: pointer;
   padding: 0;
-  margin: 4px;
-  &:hover {
-    color: #fff;
-  }
+  /* margin: 4px; */
+  margin-top: -6px;
+
+  visibility: ${(props) => (props.visible ? "visible" : "hidden")};
 `;
 
-function CopyButton(props: { textToCopy: string }) {
+function CopyButton(props: { textToCopy: string; visible: boolean }) {
+  const [hovered, setHovered] = useState<boolean>(false);
+  const [clicked, setClicked] = useState<boolean>(false);
   return (
     <>
       <StyledCopyButton
+        onMouseEnter={() => {
+          setHovered(true);
+        }}
+        onMouseLeave={() => {
+          setHovered(false);
+        }}
+        visible={clicked || props.visible}
         onClick={() => {
           navigator.clipboard.writeText(props.textToCopy);
+          setClicked(true);
+          setTimeout(() => {
+            setClicked(false);
+          }, 2000);
         }}
       >
-        <Clipboard color="white" size="1.4em" />
+        {clicked ? (
+          <CheckCircle color="#00ff00" size="1.4em" />
+        ) : (
+          <Clipboard color={hovered ? "#00ff00" : "white"} size="1.4em" />
+        )}
       </StyledCopyButton>
     </>
   );
@@ -48,9 +66,18 @@ function CodeBlock(props: { language?: string; children: string }) {
   useEffect(() => {
     hljs.highlightAll();
   }, [props.children]);
+  const [hovered, setHovered] = useState<boolean>(false);
+
   return (
-    <StyledPre>
-      <CopyButton textToCopy={props.children} />
+    <StyledPre
+      onMouseEnter={() => {
+        setHovered(true);
+      }}
+      onMouseLeave={() => {
+        setHovered(false);
+      }}
+    >
+      <CopyButton visible={hovered} textToCopy={props.children} />
       <StyledCode>{props.children}</StyledCode>
     </StyledPre>
   );
diff --git a/extension/react-app/src/components/ComboBox.tsx b/extension/react-app/src/components/ComboBox.tsx
index e855ebe5..ddc9d5dc 100644
--- a/extension/react-app/src/components/ComboBox.tsx
+++ b/extension/react-app/src/components/ComboBox.tsx
@@ -9,16 +9,22 @@ import {
 } from ".";
 
 const mainInputFontSize = 16;
-const MainTextInput = styled.input`
+const MainTextInput = styled.textarea`
+  resize: none;
+
   padding: 8px;
   font-size: ${mainInputFontSize}px;
   border-radius: ${defaultBorderRadius};
-  border: 1px solid #ccc;
+  border: 1px solid white;
   margin: 8px auto;
   width: 100%;
   background-color: ${vscBackground};
   color: white;
-  outline: 1px solid orange;
+
+  &:focus {
+    border: 1px solid transparent;
+    outline: 1px solid orange;
+  }
 `;
 
 const UlMaxHeight = 200;
@@ -108,10 +114,16 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
     <div className="flex px-2" ref={divRef} hidden={!isOpen}>
       <MainTextInput
         disabled={props.disabled}
-        placeholder="Type '/' to see the list of available slash commands..."
+        placeholder="Type '/' to see available slash commands."
         {...getInputProps({
           onKeyDown: (event) => {
-            if (event.key === "Enter" && (!isOpen || items.length === 0)) {
+            if (event.key === "Enter" && event.shiftKey) {
+              // Prevent Downshift's default 'Enter' behavior.
+              (event.nativeEvent as any).preventDownshiftDefault = true;
+            } else if (
+              event.key === "Enter" &&
+              (!isOpen || items.length === 0)
+            ) {
               // Prevent Downshift's default 'Enter' behavior.
               (event.nativeEvent as any).preventDownshiftDefault = true;
               if (props.onEnter) props.onEnter(event);
diff --git a/extension/react-app/src/components/StepContainer.tsx b/extension/react-app/src/components/StepContainer.tsx
index 4c98b04d..1eb1d1fd 100644
--- a/extension/react-app/src/components/StepContainer.tsx
+++ b/extension/react-app/src/components/StepContainer.tsx
@@ -5,14 +5,8 @@ import {
   defaultBorderRadius,
   secondaryDark,
   vscBackground,
-  GradientBorder,
   vscBackgroundTransparent,
-  HeaderButton,
 } from ".";
-import { RangeInFile, FileEdit } from "../../../src/client";
-import CodeBlock from "./CodeBlock";
-import SubContainer from "./SubContainer";
-
 import {
   ChevronDown,
   ChevronRight,
@@ -22,6 +16,7 @@ import {
 import { HistoryNode } from "../../../schema/HistoryNode";
 import ReactMarkdown from "react-markdown";
 import HeaderButtonWithText from "./HeaderButtonWithText";
+import CodeBlock from "./CodeBlock";
 
 interface StepContainerProps {
   historyNode: HistoryNode;
@@ -34,6 +29,8 @@ interface StepContainerProps {
   open: boolean;
   onToggleAll: () => void;
   onToggle: () => void;
+  isFirst: boolean;
+  isLast: boolean;
 }
 
 const MainDiv = styled.div<{ stepDepth: number; inFuture: boolean }>`
@@ -67,12 +64,6 @@ const ContentDiv = styled.div`
   padding-left: 16px;
 `;
 
-const OnHoverDiv = styled.div`
-  text-align: center;
-  padding: 10px;
-  animation: ${appear} 0.3s ease-in-out;
-`;
-
 const MarkdownPre = styled.pre`
   background-color: ${secondaryDark};
   padding: 10px;
@@ -80,7 +71,34 @@ const MarkdownPre = styled.pre`
   border: 0.5px solid white;
 `;
 
-const MarkdownCode = styled.code``;
+const StyledCode = styled.code`
+  word-wrap: break-word;
+  color: lightgray;
+`;
+
+const GradientBorder = styled.div<{
+  borderWidth?: number;
+  borderRadius?: string;
+  borderColor?: string;
+  isFirst: boolean;
+  isLast: boolean;
+}>`
+  border-radius: ${(props) => props.borderRadius || "0"};
+  padding-top: ${(props) =>
+    `${(props.borderWidth || 1) / (props.isFirst ? 1 : 2)}px`};
+  padding-bottom: ${(props) =>
+    `${(props.borderWidth || 1) / (props.isLast ? 1 : 2)}px`};
+  background: ${(props) =>
+    props.borderColor
+      ? props.borderColor
+      : `linear-gradient(
+    101.79deg,
+    #12887a 0%,
+    #87245c 37.64%,
+    #e12637 65.98%,
+    #ffb215 110.45%
+  )`};
+`;
 
 function StepContainer(props: StepContainerProps) {
   const [isHovered, setIsHovered] = useState(false);
@@ -120,12 +138,14 @@ function StepContainer(props: StepContainerProps) {
     >
       <StepContainerDiv open={props.open}>
         <GradientBorder
+          isFirst={props.isFirst}
+          isLast={props.isLast}
           borderColor={
             props.historyNode.observation?.error ? "#f00" : undefined
           }
           className="overflow-hidden cursor-pointer"
           onClick={(e) => {
-            if (props.open && e.metaKey) {
+            if (e.metaKey) {
               props.onToggleAll();
             } else {
               props.onToggle();
@@ -198,66 +218,28 @@ function StepContainer(props: StepContainerProps) {
             <ReactMarkdown
               key={1}
               className="overflow-x-scroll"
-              components={
-                {
-                  // pre: ({ node, ...props }) => {
-                  //   return (
-                  //     <CodeBlock
-                  //       children={props.children[0] as string}
-                  //     ></CodeBlock>
-                  //   );
-                  // },
-                }
-              }
+              components={{
+                pre: ({ node, ...props }) => {
+                  return (
+                    <CodeBlock
+                      children={props.children[0] as string}
+                    ></CodeBlock>
+                  );
+                },
+                code: ({ node, ...props }) => {
+                  return (
+                    <StyledCode
+                      children={props.children[0] as string}
+                    ></StyledCode>
+                  );
+                },
+              }}
             >
               {props.historyNode.step.description as any}
             </ReactMarkdown>
           )}
-
-          {/* {props.historyNode.step.name === "Waiting for user input" && (
-            <InputAndButton
-              onUserInput={(value) => {
-                props.onUserInput(value);
-              }}
-            ></InputAndButton>
-          )}
-          {props.historyNode.step.name === "Waiting for user confirmation" && (
-            <>
-              <input
-                type="button"
-                value="Cancel"
-                className="m-4 p-2 rounded-md border border-solid text-white border-gray-200 bg-vsc-background cursor-pointer hover:bg-white hover:text-black"
-              ></input>
-              <input
-                className="m-4 p-2 rounded-md border border-solid text-white border-gray-200 bg-vsc-background cursor-pointer hover:bg-white hover:text-black"
-                onClick={(e) => {
-                  props.onUserInput("ok");
-                  e.preventDefault();
-                  e.stopPropagation();
-                }}
-                type="button"
-                value="Confirm"
-              />
-            </>
-          )} */}
         </ContentDiv>
       </StepContainerDiv>
-
-      {/* <OnHoverDiv hidden={!open}>
-        <NaturalLanguageInput
-          onKeyDown={(e) => {
-            if (e.key === "Enter") {
-              onTextInput();
-            }
-          }}
-          ref={naturalLanguageInputRef}
-          onClick={(e) => {
-            e.stopPropagation();
-            e.preventDefault();
-          }}
-        ></NaturalLanguageInput>
-        <ContinueButton onClick={onTextInput}></ContinueButton>
-      </OnHoverDiv> */}
     </MainDiv>
   );
 }
diff --git a/extension/react-app/src/components/TextDialog.tsx b/extension/react-app/src/components/TextDialog.tsx
index 31a385d5..e50a7686 100644
--- a/extension/react-app/src/components/TextDialog.tsx
+++ b/extension/react-app/src/components/TextDialog.tsx
@@ -3,6 +3,13 @@ import React, { useEffect, useState } from "react";
 import styled from "styled-components";
 import { Button, buttonColor, secondaryDark, vscBackground } from ".";
 
+const ScreenCover = styled.div`
+  position: absolute;
+  width: 100%;
+  height: 100%;
+  background-color: rgba(168, 168, 168, 0.5);
+`;
+
 const DialogContainer = styled.div`
   position: absolute;
   top: 50%;
@@ -28,9 +35,10 @@ const TextArea = styled.textarea`
   padding: 8px;
   outline: 1px solid black;
   font-family: Arial, Helvetica, sans-serif;
+  resize: none;
 
   &:focus {
-    outline: 1px solid orange;
+    outline: 1px solid ${buttonColor};
   }
 `;
 
@@ -54,34 +62,45 @@ const TextDialog = (props: {
   }, [props.showDialog]);
 
   return (
-    <DialogContainer hidden={!props.showDialog}>
-      <Dialog>
-        <P>Thanks for your feedback. We'll get back to you soon!</P>
-        <TextArea
-          cols={50}
-          rows={10}
-          ref={textAreaRef}
-          onKeyDown={(e) => {
-            if (e.key === "Enter" && e.metaKey && textAreaRef.current) {
-              props.onEnter(textAreaRef.current.value);
-              setText("");
-            } else if (e.key === "Escape") {
-              props.onClose();
-            }
-          }}
-        />
-        <Button
-          onClick={() => {
-            if (textAreaRef.current) {
-              props.onEnter(textAreaRef.current.value);
-              setText("");
-            }
-          }}
-        >
-          Enter
-        </Button>
-      </Dialog>
-    </DialogContainer>
+    <ScreenCover
+      onClick={() => {
+        props.onClose();
+      }}
+      hidden={!props.showDialog}
+    >
+      <DialogContainer
+        onClick={(e) => {
+          e.stopPropagation();
+        }}
+      >
+        <Dialog>
+          <P>Thanks for your feedback. We'll get back to you soon!</P>
+          <TextArea
+            cols={50}
+            rows={10}
+            ref={textAreaRef}
+            onKeyDown={(e) => {
+              if (e.key === "Enter" && e.metaKey && textAreaRef.current) {
+                props.onEnter(textAreaRef.current.value);
+                setText("");
+              } else if (e.key === "Escape") {
+                props.onClose();
+              }
+            }}
+          />
+          <Button
+            onClick={() => {
+              if (textAreaRef.current) {
+                props.onEnter(textAreaRef.current.value);
+                setText("");
+              }
+            }}
+          >
+            Enter
+          </Button>
+        </Dialog>
+      </DialogContainer>
+    </ScreenCover>
   );
 };
 
diff --git a/extension/react-app/src/components/index.ts b/extension/react-app/src/components/index.ts
index d99b4d96..fc94c51f 100644
--- a/extension/react-app/src/components/index.ts
+++ b/extension/react-app/src/components/index.ts
@@ -95,26 +95,6 @@ export const Loader = styled.div`
   margin: auto;
 `;
 
-export const GradientBorder = styled.div<{
-  borderWidth?: string;
-  borderRadius?: string;
-  borderColor?: string;
-}>`
-  border-radius: ${(props) => props.borderRadius || "0"};
-  padding-top: ${(props) => props.borderWidth || "1px"};
-  padding-bottom: ${(props) => props.borderWidth || "1px"};
-  background: ${(props) =>
-    props.borderColor
-      ? props.borderColor
-      : `linear-gradient(
-    101.79deg,
-    #12887a 0%,
-    #87245c 37.64%,
-    #e12637 65.98%,
-    #ffb215 110.45%
-  )`};
-`;
-
 export const MainContainerWithBorder = styled.div<{ borderWidth?: string }>`
   border-radius: ${defaultBorderRadius};
   padding: ${(props) => props.borderWidth || "1px"};
diff --git a/extension/react-app/src/index.css b/extension/react-app/src/index.css
index db8afab9..6dc514ec 100644
--- a/extension/react-app/src/index.css
+++ b/extension/react-app/src/index.css
@@ -3,8 +3,8 @@
 @tailwind utilities;
 
 :root {
-  --secondary-dark: 37 37 38;
-  --vsc-background: 30 30 30;
+  --secondary-dark: rgb(37, 37, 38);
+  --vsc-background: rgb(30, 30, 30);
   --button-color: rgb(113, 28, 59);
   --button-color-hover: rgba(113, 28, 59, 0.667);
   --def-border-radius: 5px;
@@ -26,7 +26,6 @@ body,
 }
 
 body {
-  background-color: var(--vsc-background);
   padding: 0;
   color: white;
   font-family: "Mona Sans", "Arial", sans-serif;
diff --git a/extension/react-app/src/tabs/gui.tsx b/extension/react-app/src/tabs/gui.tsx
index 6aa20e0e..624d22d5 100644
--- a/extension/react-app/src/tabs/gui.tsx
+++ b/extension/react-app/src/tabs/gui.tsx
@@ -331,6 +331,8 @@ function GUI(props: GUIProps) {
         {history?.timeline.map((node: HistoryNode, index: number) => {
           return (
             <StepContainer
+              isLast={index === history.timeline.length - 1}
+              isFirst={index === 0}
               open={stepsOpen[index]}
               onToggle={() => {
                 const nextStepsOpen = [...stepsOpen];
-- 
cgit v1.2.3-70-g09d2


From ea8e812a9361a609c1d666bd518112196c6e64b0 Mon Sep 17 00:00:00 2001
From: Nate Sesti <sestinj@gmail.com>
Date: Sun, 18 Jun 2023 18:55:14 -0700
Subject: posthog on data switch, fixed copy button

---
 extension/react-app/src/components/CodeBlock.tsx |  7 +++++--
 extension/react-app/src/components/ComboBox.tsx  |  9 +++++++++
 extension/react-app/src/tabs/gui.tsx             | 12 ++++++++++++
 3 files changed, 26 insertions(+), 2 deletions(-)

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

diff --git a/extension/react-app/src/components/CodeBlock.tsx b/extension/react-app/src/components/CodeBlock.tsx
index c4524a51..0aae0bbb 100644
--- a/extension/react-app/src/components/CodeBlock.tsx
+++ b/extension/react-app/src/components/CodeBlock.tsx
@@ -22,7 +22,7 @@ const StyledCopyButton = styled.button<{ visible: boolean }>`
   /* position: relative; */
   float: right;
   border: none;
-  background-color: transparent;
+  background-color: ${secondaryDark};
   cursor: pointer;
   padding: 0;
   /* margin: 4px; */
@@ -77,7 +77,10 @@ function CodeBlock(props: { language?: string; children: string }) {
         setHovered(false);
       }}
     >
-      <CopyButton visible={hovered} textToCopy={props.children} />
+      <CopyButton
+        visible={hovered}
+        textToCopy={(props.children as any).props.children[0]}
+      />
       <StyledCode>{props.children}</StyledCode>
     </StyledPre>
   );
diff --git a/extension/react-app/src/components/ComboBox.tsx b/extension/react-app/src/components/ComboBox.tsx
index ddc9d5dc..8c1f80e0 100644
--- a/extension/react-app/src/components/ComboBox.tsx
+++ b/extension/react-app/src/components/ComboBox.tsx
@@ -116,6 +116,15 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
         disabled={props.disabled}
         placeholder="Type '/' to see available slash commands."
         {...getInputProps({
+          onChange: (e) => {
+            const target = e.target as HTMLTextAreaElement;
+            // Update the height of the textarea to match the content, up to a max of 200px.
+            target.style.height = "auto";
+            target.style.height = `${Math.min(
+              target.scrollHeight,
+              200
+            ).toString()}px`;
+          },
           onKeyDown: (event) => {
             if (event.key === "Enter" && event.shiftKey) {
               // Prevent Downshift's default 'Enter' behavior.
diff --git a/extension/react-app/src/tabs/gui.tsx b/extension/react-app/src/tabs/gui.tsx
index 52318dca..eee2b1a0 100644
--- a/extension/react-app/src/tabs/gui.tsx
+++ b/extension/react-app/src/tabs/gui.tsx
@@ -15,6 +15,9 @@ import ComboBox from "../components/ComboBox";
 import TextDialog from "../components/TextDialog";
 import HeaderButtonWithText from "../components/HeaderButtonWithText";
 import ReactSwitch from "react-switch";
+import { usePostHog } from "posthog-js/react";
+import { useSelector } from "react-redux";
+import { RootStore } from "../redux/store";
 
 const TopGUIDiv = styled.div`
   overflow: hidden;
@@ -46,6 +49,11 @@ interface GUIProps {
 }
 
 function GUI(props: GUIProps) {
+  const posthog = usePostHog();
+  const vscMachineId = useSelector(
+    (state: RootStore) => state.config.vscMachineId
+  );
+
   const [waitingForSteps, setWaitingForSteps] = useState(false);
   const [userInputQueue, setUserInputQueue] = useState<string[]>([]);
   const [availableSlashCommands, setAvailableSlashCommands] = useState<
@@ -432,6 +440,10 @@ function GUI(props: GUIProps) {
             handleDiameter={20}
             width={40}
             onChange={() => {
+              posthog?.capture("data_switch_toggled", {
+                vscMachineId: vscMachineId,
+                dataSwitchChecked: !dataSwitchChecked,
+              });
               setDataSwitchChecked((prev) => !prev);
             }}
             onColor="#12887a"
-- 
cgit v1.2.3-70-g09d2


From 315de821c109a2ac45f4cb553890f941d33104bd Mon Sep 17 00:00:00 2001
From: Nate Sesti <sestinj@gmail.com>
Date: Mon, 19 Jun 2023 09:59:01 -0700
Subject: check for codespaces, stream edits

---
 continuedev/poetry.lock                            |  14 ++-
 continuedev/pyproject.toml                         |   1 +
 continuedev/src/continuedev/libs/util/telemetry.py |  16 ++-
 continuedev/src/continuedev/steps/core/core.py     | 109 +++++++++++++++------
 extension/react-app/src/components/ComboBox.tsx    |   2 +-
 extension/react-app/src/tabs/gui.tsx               |   4 +-
 extension/src/continueIdeClient.ts                 |   7 +-
 7 files changed, 111 insertions(+), 42 deletions(-)

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

diff --git a/continuedev/poetry.lock b/continuedev/poetry.lock
index 93aaf82b..017f12f9 100644
--- a/continuedev/poetry.lock
+++ b/continuedev/poetry.lock
@@ -585,6 +585,18 @@ files = [
     {file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"},
 ]
 
+[[package]]
+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 = [
+    {file = "jsonref-1.1.0-py3-none-any.whl", hash = "sha256:590dc7773df6c21cbf948b5dac07a72a251db28b0238ceecce0a2abfa8ec30a9"},
+    {file = "jsonref-1.1.0.tar.gz", hash = "sha256:32fe8e1d85af0fdefbebce950af85590b22b60f9e95443176adbde4e1ecea552"},
+]
+
 [[package]]
 name = "langchain"
 version = "0.0.171"
@@ -1737,4 +1749,4 @@ multidict = ">=4.0"
 [metadata]
 lock-version = "2.0"
 python-versions = "^3.9"
-content-hash = "17910714e3ad780ae7222b62c98539489d198aea67e5c7e4a9fc7672207f500f"
+content-hash = "9406bc70d0463b354c294bd9548897a33270b8a04f55141a763d45af8d6928b8"
diff --git a/continuedev/pyproject.toml b/continuedev/pyproject.toml
index af6ff045..bbd8a687 100644
--- a/continuedev/pyproject.toml
+++ b/continuedev/pyproject.toml
@@ -21,6 +21,7 @@ urllib3 = "1.26.15"
 gpt-index = "^0.6.8"
 posthog = "^3.0.1"
 tiktoken = "^0.4.0"
+jsonref = "^1.1.0"
 
 [tool.poetry.scripts]
 typegen = "src.continuedev.models.generate_json_schema:main" 
diff --git a/continuedev/src/continuedev/libs/util/telemetry.py b/continuedev/src/continuedev/libs/util/telemetry.py
index 03ec93c6..bd9fde9d 100644
--- a/continuedev/src/continuedev/libs/util/telemetry.py
+++ b/continuedev/src/continuedev/libs/util/telemetry.py
@@ -1,12 +1,22 @@
+from typing import Any
 from posthog import Posthog
 from ...core.config import load_config
+import os
+from dotenv import load_dotenv
+
+load_dotenv()
+in_codespaces = os.getenv("CODESPACES") == "true"
 
 # The personal API key is necessary only if you want to use local evaluation of feature flags.
 posthog = Posthog('phc_JS6XFROuNbhJtVCEdTSYk6gl5ArRrTNMpCcguAXlSPs',
                   host='https://app.posthog.com')
 
 
-def capture_event(unique_id: str, event_name, event_properties):
+def capture_event(unique_id: str, event_name: str, event_properties: Any):
     config = load_config('.continue/config.json')
-    if config.allow_anonymous_telemetry:
-        posthog.capture(unique_id, event_name, event_properties)
+    if not config.allow_anonymous_telemetry:
+        return
+
+    if in_codespaces:
+        event_properties['codespaces'] = True
+    posthog.capture(unique_id, event_name, event_properties)
diff --git a/continuedev/src/continuedev/steps/core/core.py b/continuedev/src/continuedev/steps/core/core.py
index 6d6246fd..237171a6 100644
--- a/continuedev/src/continuedev/steps/core/core.py
+++ b/continuedev/src/continuedev/steps/core/core.py
@@ -235,45 +235,90 @@ class DefaultModelEditCodeStep(Step):
             prompt = self._prompt.format(
                 code=rif.contents, user_request=self.user_input, file_prefix=segs[0], file_suffix=segs[1])
 
-            completion = str(await model_to_use.complete(prompt, with_history=await sdk.get_chat_context()))
-
-            eot_token = "<|endoftext|>"
-            completion = completion.removesuffix(eot_token)
-
-            # Remove tags and If it accidentally includes prefix or suffix, remove it
-            if completion.strip().startswith("```"):
-                completion = completion.strip().removeprefix("```").removesuffix("```")
-            completion = completion.replace("<file_prefix>", "").replace("<file_suffix>", "").replace(
-                "<commit_before>", "").replace("<commit_msg>", "").replace("<commit_after>", "")
-            completion = completion.removeprefix(segs[0])
-            completion = completion.removesuffix(segs[1])
+            lines = []
+            unfinished_line = ""
+            i = 0
+            original_lines = rif.contents.split("\n")
+            lines_to_highlight = []
+
+            async def add_line(i: int, line: str):
+                range = Range.from_shorthand(
+                    rif.range.start.line + i, rif.range.start.character if i == 0 else 0, rif.range.start.line + i + 1, 0)
+                await sdk.ide.applyFileSystemEdit(FileEdit(
+                    filepath=rif.filepath,
+                    range=range,
+                    replacement=line + "\n"
+                ))
+                lines_to_highlight.append(rif.range.start.line + i)
+                # await sdk.ide.highlightCode(RangeInFile(
+                #     filepath=rif.filepath,
+                #     range=range
+                # ))
+
+            async for chunk in model_to_use.stream_chat(prompt, with_history=await sdk.get_chat_context()):
+                chunk_lines = chunk.split("\n")
+                chunk_lines[0] = unfinished_line + chunk_lines[0]
+                if chunk.endswith("\n"):
+                    unfinished_line = ""
+                    chunk_lines.pop()  # because this will be an empty string
+                else:
+                    unfinished_line = chunk_lines.pop()
+                lines.extend(chunk_lines)
+
+                for line in chunk_lines:
+                    if i < len(original_lines) and line == original_lines[i]:
+                        i += 1
+                        continue
+
+                    await add_line(i, line)
+                    i += 1
+
+            # Add the unfinished line
+            if unfinished_line != "":
+                if not i < len(original_lines) or not unfinished_line == original_lines[i]:
+                    await add_line(i, unfinished_line)
+                lines.append(unfinished_line)
+                i += 1
+
+            # Remove the leftover original lines
+            while i < len(original_lines):
+                range = Range.from_shorthand(
+                    rif.range.start.line + i, rif.range.start.character, rif.range.start.line + i, len(original_lines[i]))
+                await sdk.ide.applyFileSystemEdit(FileEdit(
+                    filepath=rif.filepath,
+                    range=range,
+                    replacement=""
+                ))
+                # await sdk.ide.highlightCode(RangeInFile(
+                #     filepath=rif.filepath,
+                #     range=range
+                # ))
+                i += 1
+
+            completion = "\n".join(lines)
+            # eot_token = "<|endoftext|>"
+            # completion = completion.removesuffix(eot_token)
+
+            # # Remove tags and If it accidentally includes prefix or suffix, remove it
+            # if completion.strip().startswith("```"):
+            #     completion = completion.strip().removeprefix("```").removesuffix("```")
+            # completion = completion.replace("<file_prefix>", "").replace("<file_suffix>", "").replace(
+            #     "<commit_before>", "").replace("<commit_msg>", "").replace("<commit_after>", "")
+            # completion = completion.removeprefix(segs[0])
+            # completion = completion.removesuffix(segs[1])
 
             self._prompt_and_completion += prompt + completion
 
-            diff = list(difflib.ndiff(rif.contents.splitlines(
-                keepends=True), completion.splitlines(keepends=True)))
-
-            lines_to_highlight = set()
-            index = 0
-            for line in diff:
-                if line.startswith("-"):
-                    pass
-                elif line.startswith("+"):
-                    lines_to_highlight.add(index + rif.range.start.line)
-                    index += 1
-                elif line.startswith(" "):
-                    index += 1
-
-            await sdk.ide.applyFileSystemEdit(FileEdit(
-                filepath=rif.filepath,
-                range=rif.range,
-                replacement=completion
-            ))
+            # await sdk.ide.applyFileSystemEdit(FileEdit(
+            #     filepath=rif.filepath,
+            #     range=rif.range,
+            #     replacement=completion
+            # ))
 
             current_hl_start = None
             last_hl = None
             rifs_to_highlight = []
-            for line in sorted(list(lines_to_highlight)):
+            for line in lines_to_highlight:
                 if current_hl_start is None:
                     current_hl_start = line
                 elif line != last_hl + 1:
diff --git a/extension/react-app/src/components/ComboBox.tsx b/extension/react-app/src/components/ComboBox.tsx
index 8c1f80e0..1a3a2b90 100644
--- a/extension/react-app/src/components/ComboBox.tsx
+++ b/extension/react-app/src/components/ComboBox.tsx
@@ -122,7 +122,7 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
             target.style.height = "auto";
             target.style.height = `${Math.min(
               target.scrollHeight,
-              200
+              300
             ).toString()}px`;
           },
           onKeyDown: (event) => {
diff --git a/extension/react-app/src/tabs/gui.tsx b/extension/react-app/src/tabs/gui.tsx
index 7716d561..62d44515 100644
--- a/extension/react-app/src/tabs/gui.tsx
+++ b/extension/react-app/src/tabs/gui.tsx
@@ -364,7 +364,7 @@ function GUI(props: GUIProps) {
                 setStepsOpen(nextStepsOpen);
               }}
               onToggleAll={() => {
-                setStepsOpen((prev) => prev.map(() => !prev[index]));
+                setStepsOpen((prev) => prev.map((_, index) => !prev[index]));
               }}
               key={index}
               onUserInput={(input: string) => {
@@ -388,7 +388,7 @@ function GUI(props: GUIProps) {
             />
           );
         })}
-        {waitingForSteps && <Loader></Loader>}
+        {/* {waitingForSteps && <Loader></Loader>} */}
 
         <div>
           {userInputQueue.map((input) => {
diff --git a/extension/src/continueIdeClient.ts b/extension/src/continueIdeClient.ts
index 3b5de93f..fbad5f5d 100644
--- a/extension/src/continueIdeClient.ts
+++ b/extension/src/continueIdeClient.ts
@@ -159,7 +159,7 @@ class IdeProtocolClient {
       editor.setDecorations(decorationType, [range]);
 
       // Listen for changes to cursor position and then remove the decoration (but keep for at least 2 seconds)
-      setTimeout(() => {
+      const allowRemoveHighlight = () => {
         const cursorDisposable = vscode.window.onDidChangeTextEditorSelection(
           (event) => {
             if (event.textEditor.document.uri.fsPath === rangeInFile.filepath) {
@@ -168,7 +168,8 @@ class IdeProtocolClient {
             }
           }
         );
-      }, 2000);
+      };
+      setTimeout(allowRemoveHighlight, 2000);
     }
   }
 
@@ -285,7 +286,7 @@ class IdeProtocolClient {
           edit.range.start.line,
           edit.range.start.character,
           edit.range.end.line,
-          edit.range.end.character + 1
+          edit.range.end.character
         );
 
         editor.edit((editBuilder) => {
-- 
cgit v1.2.3-70-g09d2


From 3c0d07017e305ca4feca2b884f0e5cee8b04eed3 Mon Sep 17 00:00:00 2001
From: Nate Sesti <sestinj@gmail.com>
Date: Mon, 19 Jun 2023 10:09:41 -0700
Subject: fix up/down arrow key behavior in main entry

---
 extension/react-app/src/components/ComboBox.tsx | 20 +++++++++++++++-----
 1 file changed, 15 insertions(+), 5 deletions(-)

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

diff --git a/extension/react-app/src/components/ComboBox.tsx b/extension/react-app/src/components/ComboBox.tsx
index 1a3a2b90..3816cee8 100644
--- a/extension/react-app/src/components/ComboBox.tsx
+++ b/extension/react-app/src/components/ComboBox.tsx
@@ -145,14 +145,24 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
             } else if (event.key === "Tab" && items.length > 0) {
               setInputValue(items[0].name);
               event.preventDefault();
-            } else if (event.key === "ArrowUp") {
+            } else if (
+              event.key === "ArrowUp" ||
+              (event.key === "ArrowDown" &&
+                event.currentTarget.value.split("\n").length > 1)
+            ) {
+              (event.nativeEvent as any).preventDownshiftDefault = true;
+            } else if (
+              event.key === "ArrowUp" &&
+              event.currentTarget.value.split("\n").length > 1
+            ) {
               if (positionInHistory == 0) return;
               setInputValue(history[positionInHistory - 1]);
               setPositionInHistory((prev) => prev - 1);
-            } else if (event.key === "ArrowDown") {
-              if (positionInHistory >= history.length - 1) {
-                setInputValue("");
-              } else {
+            } else if (
+              event.key === "ArrowDown" &&
+              event.currentTarget.value.split("\n").length > 1
+            ) {
+              if (positionInHistory < history.length - 1) {
                 setInputValue(history[positionInHistory + 1]);
               }
               setPositionInHistory((prev) =>
-- 
cgit v1.2.3-70-g09d2


From 359c277f25c323d3fd47830d569fb05f93920d3a Mon Sep 17 00:00:00 2001
From: Nate Sesti <sestinj@gmail.com>
Date: Sat, 1 Jul 2023 12:36:57 -0700
Subject: explicit context pill buttons

---
 continuedev/src/continuedev/core/autopilot.py      |  40 +++-
 continuedev/src/continuedev/core/main.py           |   2 +
 continuedev/src/continuedev/core/sdk.py            |   7 +-
 continuedev/src/continuedev/models/filesystem.py   |  29 +++
 continuedev/src/continuedev/models/main.py         |   6 +
 continuedev/src/continuedev/server/gui.py          |   7 +
 continuedev/src/continuedev/server/ide.py          |  10 +-
 continuedev/src/continuedev/server/ide_protocol.py |   6 +-
 continuedev/src/continuedev/steps/core/core.py     |   3 +-
 extension/react-app/src/components/CodeBlock.tsx   |  73 +++---
 extension/react-app/src/components/ComboBox.tsx    | 258 ++++++++++++++-------
 .../src/components/IterationContainer.tsx          |  77 ------
 .../react-app/src/components/StepContainer.tsx     |   8 +-
 .../src/hooks/ContinueGUIClientProtocol.ts         |   2 +
 .../react-app/src/hooks/useContinueGUIProtocol.ts  |   4 +
 extension/react-app/src/tabs/gui.tsx               | 221 +-----------------
 extension/src/continueIdeClient.ts                 |  39 +++-
 17 files changed, 369 insertions(+), 423 deletions(-)
 delete mode 100644 extension/react-app/src/components/IterationContainer.tsx

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

diff --git a/continuedev/src/continuedev/core/autopilot.py b/continuedev/src/continuedev/core/autopilot.py
index 3c7fbdef..b9e61c63 100644
--- a/continuedev/src/continuedev/core/autopilot.py
+++ b/continuedev/src/continuedev/core/autopilot.py
@@ -2,8 +2,10 @@ from functools import cached_property
 import traceback
 import time
 from typing import Any, Callable, Coroutine, Dict, List
-
+import os
 from aiohttp import ClientPayloadError
+
+from ..models.filesystem import RangeInFileWithContents
 from ..models.filesystem_edit import FileEditWithFullContents
 from ..libs.llm import LLM
 from .observation import Observation, InternalErrorObservation
@@ -59,7 +61,13 @@ class Autopilot(ContinueBaseModel):
         keep_untouched = (cached_property,)
 
     def get_full_state(self) -> FullState:
-        return FullState(history=self.history, active=self._active, user_input_queue=self._main_user_input_queue, default_model=self.continue_sdk.config.default_model)
+        return FullState(
+            history=self.history,
+            active=self._active,
+            user_input_queue=self._main_user_input_queue,
+            default_model=self.continue_sdk.config.default_model,
+            highlighted_ranges=self._highlighted_ranges
+        )
 
     async def get_available_slash_commands(self) -> List[Dict]:
         return list(map(lambda x: {"name": x.name, "description": x.description}, self.continue_sdk.config.slash_commands)) or []
@@ -124,6 +132,30 @@ class Autopilot(ContinueBaseModel):
                         tb_step.step_name, {"output": output, **tb_step.params})
                     await self._run_singular_step(step)
 
+    _highlighted_ranges: List[RangeInFileWithContents] = []
+
+    async def handle_highlighted_code(self, range_in_files: List[RangeInFileWithContents]):
+        workspace_path = self.continue_sdk.ide.workspace_directory
+        for rif in range_in_files:
+            rif.filepath = os.path.relpath(rif.filepath, workspace_path)
+
+        new_ranges = []
+        for rif in range_in_files:
+            found_overlap = False
+            for i in range(len(self._highlighted_ranges)):
+                hr = self._highlighted_ranges[i]
+                if hr.filepath == rif.filepath and hr.range.overlaps_with(rif.range):
+                    new_ranges.append(rif.union(hr))
+                    found_overlap = True
+                    self._highlighted_ranges.pop(i)
+                    break
+
+            if not found_overlap:
+                new_ranges.append(rif)
+
+        self._highlighted_ranges += new_ranges
+        await self.update_subscribers()
+
     _step_depth: int = 0
 
     async def retry_at_index(self, index: int):
@@ -135,6 +167,10 @@ class Autopilot(ContinueBaseModel):
         self.history.timeline[index].deleted = True
         await self.update_subscribers()
 
+    async def delete_context_item_at_index(self, index: int):
+        self._highlighted_ranges.pop(index)
+        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:
diff --git a/continuedev/src/continuedev/core/main.py b/continuedev/src/continuedev/core/main.py
index 4c6f4dc2..2d84801c 100644
--- a/continuedev/src/continuedev/core/main.py
+++ b/continuedev/src/continuedev/core/main.py
@@ -2,6 +2,7 @@ import json
 from textwrap import dedent
 from typing import Callable, Coroutine, Dict, Generator, List, Literal, Tuple, Union
 
+from ..models.filesystem import RangeInFileWithContents
 from ..models.main import ContinueBaseModel
 from pydantic import validator
 from .observation import Observation
@@ -201,6 +202,7 @@ class FullState(ContinueBaseModel):
     active: bool
     user_input_queue: List[str]
     default_model: str
+    highlighted_ranges: List[RangeInFileWithContents]
 
 
 class ContinueSDK:
diff --git a/continuedev/src/continuedev/core/sdk.py b/continuedev/src/continuedev/core/sdk.py
index d95a233f..632f8683 100644
--- a/continuedev/src/continuedev/core/sdk.py
+++ b/continuedev/src/continuedev/core/sdk.py
@@ -179,7 +179,7 @@ class ContinueSDK(AbstractContinueSDK):
 
     async def get_chat_context(self) -> List[ChatMessage]:
         history_context = self.history.to_chat_history()
-        highlighted_code = await self.ide.getHighlightedCode()
+        highlighted_code = self.__autopilot._highlighted_ranges
 
         preface = "The following code is highlighted"
 
@@ -190,11 +190,10 @@ class ContinueSDK(AbstractContinueSDK):
             if len(files) > 0:
                 content = await self.ide.readFile(files[0])
                 highlighted_code = [
-                    RangeInFile.from_entire_file(files[0], content)]
+                    RangeInFileWithContents.from_entire_file(files[0], content)]
 
         for rif in highlighted_code:
-            code = await self.ide.readRangeInFile(rif)
-            msg = ChatMessage(content=f"{preface} ({rif.filepath}):\n```\n{code}\n```",
+            msg = ChatMessage(content=f"{preface} ({rif.filepath}):\n```\n{rif.contents}\n```",
                               role="system", summary=f"{preface}: {rif.filepath}")
 
             # Don't insert after latest user message or function call
diff --git a/continuedev/src/continuedev/models/filesystem.py b/continuedev/src/continuedev/models/filesystem.py
index b709dd21..fc1c3f13 100644
--- a/continuedev/src/continuedev/models/filesystem.py
+++ b/continuedev/src/continuedev/models/filesystem.py
@@ -23,11 +23,40 @@ class RangeInFile(BaseModel):
 
 
 class RangeInFileWithContents(RangeInFile):
+    """A range in a file with the contents of the range."""
     contents: str
 
     def __hash__(self):
         return hash((self.filepath, self.range, self.contents))
 
+    def union(self, other: "RangeInFileWithContents") -> "RangeInFileWithContents":
+        assert self.filepath == other.filepath
+        # Use a placeholder variable for self and swap it with other if other comes before self
+        first = self
+        second = other
+        if other.range.start < self.range.start:
+            first = other
+            second = self
+
+        assert first.filepath == second.filepath
+
+        # Calculate the start and end positions of the overlap
+        overlap_start = max(first.range.start,
+                            second.range.start) - first.range.start
+        overlap_end = min(first.range.end, second.range.end) - \
+            first.range.start
+
+        # Calculate the new contents by removing the overlap
+        union_contents = first.contents[:overlap_start] + \
+            second.contents[overlap_start:overlap_end] + \
+            first.contents[overlap_end:]
+
+        return RangeInFileWithContents(
+            filepath=first.filepath,
+            range=first.range.union(second.range),
+            contents=union_contents
+        )
+
     @staticmethod
     def from_entire_file(filepath: str, content: str) -> "RangeInFileWithContents":
         lines = content.splitlines()
diff --git a/continuedev/src/continuedev/models/main.py b/continuedev/src/continuedev/models/main.py
index d5f6e650..101be4ae 100644
--- a/continuedev/src/continuedev/models/main.py
+++ b/continuedev/src/continuedev/models/main.py
@@ -49,6 +49,12 @@ class Range(BaseModel):
     start: Position
     end: Position
 
+    def __lt__(self, other: "Range") -> bool:
+        return self.start < other.start or (self.start == other.start and self.end < other.end)
+
+    def __eq__(self, other: "Range") -> bool:
+        return self.start == other.start and self.end == other.end
+
     def __hash__(self):
         return hash((self.start, self.end))
 
diff --git a/continuedev/src/continuedev/server/gui.py b/continuedev/src/continuedev/server/gui.py
index c0178920..9a33fb6c 100644
--- a/continuedev/src/continuedev/server/gui.py
+++ b/continuedev/src/continuedev/server/gui.py
@@ -83,6 +83,8 @@ class GUIProtocolServer(AbstractGUIProtocolServer):
                 self.on_clear_history()
             elif message_type == "delete_at_index":
                 self.on_delete_at_index(data["index"])
+            elif message_type == "delete_context_item_at_index":
+                self.on_delete_context_item_at_index(data["index"])
         except Exception as e:
             print(e)
 
@@ -127,6 +129,11 @@ class GUIProtocolServer(AbstractGUIProtocolServer):
     def on_delete_at_index(self, index: int):
         asyncio.create_task(self.session.autopilot.delete_at_index(index))
 
+    def on_delete_context_item_at_index(self, index: int):
+        asyncio.create_task(
+            self.session.autopilot.delete_context_item_at_index(index)
+        )
+
 
 @router.websocket("/ws")
 async def websocket_endpoint(websocket: WebSocket, session: Session = Depends(websocket_session)):
diff --git a/continuedev/src/continuedev/server/ide.py b/continuedev/src/continuedev/server/ide.py
index e1f19447..f3deecdb 100644
--- a/continuedev/src/continuedev/server/ide.py
+++ b/continuedev/src/continuedev/server/ide.py
@@ -8,7 +8,7 @@ from fastapi import WebSocket, Body, APIRouter
 from uvicorn.main import Server
 
 from ..libs.util.queue import AsyncSubscriptionQueue
-from ..models.filesystem import FileSystem, RangeInFile, EditDiff, RealFileSystem
+from ..models.filesystem import FileSystem, RangeInFile, EditDiff, RangeInFileWithContents, RealFileSystem
 from ..models.filesystem_edit import AddDirectory, AddFile, DeleteDirectory, DeleteFile, FileSystemEdit, FileEdit, FileEditWithFullContents, RenameDirectory, RenameFile, SequentialFileSystemEdit
 from pydantic import BaseModel
 from .gui import SessionManager, session_manager
@@ -139,6 +139,9 @@ class IdeProtocolServer(AbstractIdeProtocolServer):
             fileEdits = list(
                 map(lambda d: FileEditWithFullContents.parse_obj(d), data["fileEdits"]))
             self.onFileEdits(fileEdits)
+        elif message_type == "highlightedCodePush":
+            self.onHighlightedCodeUpdate(
+                [RangeInFileWithContents(**rif) for rif in data["highlightedCode"]])
         elif message_type == "commandOutput":
             output = data["output"]
             self.onCommandOutput(output)
@@ -229,6 +232,11 @@ class IdeProtocolServer(AbstractIdeProtocolServer):
             asyncio.create_task(
                 session.autopilot.handle_command_output(output))
 
+    def onHighlightedCodeUpdate(self, range_in_files: List[RangeInFileWithContents]):
+        for _, session in self.session_manager.sessions.items():
+            asyncio.create_task(
+                session.autopilot.handle_highlighted_code(range_in_files))
+
     # Request information. Session doesn't matter.
     async def getOpenFiles(self) -> List[str]:
         resp = await self._send_and_receive_json({}, OpenFilesResponse, "openFiles")
diff --git a/continuedev/src/continuedev/server/ide_protocol.py b/continuedev/src/continuedev/server/ide_protocol.py
index d2dafa9a..17a09c3d 100644
--- a/continuedev/src/continuedev/server/ide_protocol.py
+++ b/continuedev/src/continuedev/server/ide_protocol.py
@@ -3,7 +3,7 @@ from abc import ABC, abstractmethod, abstractproperty
 
 from ..models.main import Traceback
 from ..models.filesystem_edit import FileEdit, FileSystemEdit, EditDiff
-from ..models.filesystem import RangeInFile
+from ..models.filesystem import RangeInFile, RangeInFileWithContents
 
 
 class AbstractIdeProtocolServer(ABC):
@@ -91,6 +91,10 @@ class AbstractIdeProtocolServer(ABC):
     async def runCommand(self, command: str) -> str:
         """Run a command"""
 
+    @abstractmethod
+    def onHighlightedCodeUpdate(self, range_in_files: List[RangeInFileWithContents]):
+        """Called when highlighted code is updated"""
+
     @abstractproperty
     def workspace_directory(self) -> str:
         """Get the workspace directory"""
diff --git a/continuedev/src/continuedev/steps/core/core.py b/continuedev/src/continuedev/steps/core/core.py
index a84263cc..729f5e66 100644
--- a/continuedev/src/continuedev/steps/core/core.py
+++ b/continuedev/src/continuedev/steps/core/core.py
@@ -311,8 +311,7 @@ class DefaultModelEditCodeStep(Step):
             nonlocal current_block_start, current_line_in_file, original_lines, original_lines_below_previous_blocks, current_block_lines, indices_of_last_matched_lines, LINES_TO_MATCH_BEFORE_ENDING_BLOCK, offset_from_blocks
 
             # Highlight the line to show progress
-            # - len(current_block_lines)
-            line_to_highlight = current_line_in_file
+            line_to_highlight = current_line_in_file - len(current_block_lines)
             await sdk.ide.highlightCode(RangeInFile(filepath=rif.filepath, range=Range.from_shorthand(
                 line_to_highlight, 0, line_to_highlight, 0)), "#FFFFFF22" if len(current_block_lines) == 0 else "#00FF0022")
 
diff --git a/extension/react-app/src/components/CodeBlock.tsx b/extension/react-app/src/components/CodeBlock.tsx
index 1624b986..17f5626b 100644
--- a/extension/react-app/src/components/CodeBlock.tsx
+++ b/extension/react-app/src/components/CodeBlock.tsx
@@ -61,7 +61,7 @@ function CopyButton(props: { textToCopy: string; visible: boolean }) {
   );
 }
 
-function CodeBlock(props: { children: React.ReactNode }) {
+function CodeBlock(props: { children: string; showCopy?: boolean }) {
   const [result, setResult] = useState<AutoHighlightResult | undefined>(
     undefined
   );
@@ -78,39 +78,36 @@ function CodeBlock(props: { children: React.ReactNode }) {
 
     setHighlightTimeout(
       setTimeout(() => {
-        const result = hljs.highlightAuto(
-          (props.children as any).props.children[0],
-          [
-            "python",
-            "javascript",
-            "typescript",
-            "bash",
-            "html",
-            "css",
-            "json",
-            "yaml",
-            "markdown",
-            "sql",
-            "java",
-            "c",
-            "cpp",
-            "csharp",
-            "go",
-            "kotlin",
-            "php",
-            "ruby",
-            "rust",
-            "scala",
-            "swift",
-            "dart",
-            "haskell",
-            "perl",
-            "r",
-            "julia",
-            "objectivec",
-            "ocaml",
-          ]
-        );
+        const result = hljs.highlightAuto(props.children, [
+          "python",
+          "javascript",
+          "typescript",
+          "bash",
+          "html",
+          "css",
+          "json",
+          "yaml",
+          "markdown",
+          "sql",
+          "java",
+          "c",
+          "cpp",
+          "csharp",
+          "go",
+          "kotlin",
+          "php",
+          "ruby",
+          "rust",
+          "scala",
+          "swift",
+          "dart",
+          "haskell",
+          "perl",
+          "r",
+          "julia",
+          "objectivec",
+          "ocaml",
+        ]);
         setResult(result);
         setHighlightTimeout(undefined);
       }, 100)
@@ -129,13 +126,11 @@ function CodeBlock(props: { children: React.ReactNode }) {
     >
       <CopyButtonDiv>
         <CopyButton
-          visible={hovered}
-          textToCopy={(props.children as any).props.children[0]}
+          visible={hovered && (props.showCopy || true)}
+          textToCopy={props.children}
         />
       </CopyButtonDiv>
-      <StyledCode language={result?.language}>
-        {(props.children as any).props.children[0]}
-      </StyledCode>
+      <StyledCode language={result?.language}>{props.children}</StyledCode>
     </StyledPre>
   );
 }
diff --git a/extension/react-app/src/components/ComboBox.tsx b/extension/react-app/src/components/ComboBox.tsx
index 3816cee8..34027a42 100644
--- a/extension/react-app/src/components/ComboBox.tsx
+++ b/extension/react-app/src/components/ComboBox.tsx
@@ -1,4 +1,4 @@
-import React, { useCallback } from "react";
+import React, { useCallback, useEffect } from "react";
 import { useCombobox } from "downshift";
 import styled from "styled-components";
 import {
@@ -7,8 +7,44 @@ import {
   secondaryDark,
   vscBackground,
 } from ".";
+import CodeBlock from "./CodeBlock";
+import { RangeInFile } from "../../../src/client";
 
 const mainInputFontSize = 16;
+
+const ContextDropdown = styled.div`
+  position: absolute;
+  padding: 4px;
+  width: calc(100% - 16px - 8px);
+  background-color: ${secondaryDark};
+  color: white;
+  border-bottom-right-radius: ${defaultBorderRadius};
+  border-bottom-left-radius: ${defaultBorderRadius};
+  /* border: 1px solid white; */
+  border-top: none;
+  margin-left: 8px;
+  margin-right: 8px;
+  margin-top: -12px;
+  outline: 1px solid orange;
+`;
+
+const PillButton = styled.button`
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  border: none;
+  color: white;
+  background-color: gray;
+  border-radius: 50px;
+  padding: 5px 10px;
+  margin: 5px 0;
+  cursor: pointer;
+
+  &:hover {
+    background-color: ${buttonColor};
+  }
+`;
+
 const MainTextInput = styled.textarea`
   resize: none;
 
@@ -20,6 +56,7 @@ const MainTextInput = styled.textarea`
   width: 100%;
   background-color: ${vscBackground};
   color: white;
+  z-index: 1;
 
   &:focus {
     border: 1px solid transparent;
@@ -49,6 +86,7 @@ const Ul = styled.ul<{
   border-radius: ${defaultBorderRadius};
   overflow: hidden;
   border: 0.5px solid gray;
+  z-index: 2;
 `;
 
 const Li = styled.li<{
@@ -71,6 +109,8 @@ interface ComboBoxProps {
   onInputValueChange: (inputValue: string) => void;
   disabled?: boolean;
   onEnter?: (e: React.KeyboardEvent<HTMLInputElement>) => void;
+  highlightedCodeSections?: (RangeInFile & { contents: string })[];
+  deleteContextItem?: (idx: number) => void;
 }
 
 const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
@@ -78,6 +118,24 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
   // The position of the current command you are typing now, so the one that will be appended to history once you press enter
   const [positionInHistory, setPositionInHistory] = React.useState<number>(0);
   const [items, setItems] = React.useState(props.items);
+  const [showContextDropdown, setShowContextDropdown] = React.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';",
+      },
+    ]
+  );
+
+  useEffect(() => {
+    setHighlightedCodeSections(props.highlightedCodeSections || []);
+  }, [props.highlightedCodeSections]);
+
   const {
     isOpen,
     getToggleButtonProps,
@@ -111,90 +169,124 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
   };
 
   return (
-    <div className="flex px-2" ref={divRef} hidden={!isOpen}>
-      <MainTextInput
-        disabled={props.disabled}
-        placeholder="Type '/' to see available slash commands."
-        {...getInputProps({
-          onChange: (e) => {
-            const target = e.target as HTMLTextAreaElement;
-            // Update the height of the textarea to match the content, up to a max of 200px.
-            target.style.height = "auto";
-            target.style.height = `${Math.min(
-              target.scrollHeight,
-              300
-            ).toString()}px`;
-          },
-          onKeyDown: (event) => {
-            if (event.key === "Enter" && event.shiftKey) {
-              // Prevent Downshift's default 'Enter' behavior.
-              (event.nativeEvent as any).preventDownshiftDefault = true;
-            } else if (
-              event.key === "Enter" &&
-              (!isOpen || items.length === 0)
-            ) {
-              // Prevent Downshift's default 'Enter' behavior.
-              (event.nativeEvent as any).preventDownshiftDefault = true;
-              if (props.onEnter) props.onEnter(event);
-              setInputValue("");
-              const value = event.currentTarget.value;
-              if (value !== "") {
-                setPositionInHistory(history.length + 1);
-                setHistory([...history, value]);
+    <>
+      <div className="flex px-2" ref={divRef} hidden={!isOpen}>
+        <MainTextInput
+          disabled={props.disabled}
+          placeholder="Type '/' to see available slash commands."
+          {...getInputProps({
+            onChange: (e) => {
+              const target = e.target as HTMLTextAreaElement;
+              // Update the height of the textarea to match the content, up to a max of 200px.
+              target.style.height = "auto";
+              target.style.height = `${Math.min(
+                target.scrollHeight,
+                300
+              ).toString()}px`;
+
+              setShowContextDropdown(target.value.endsWith("@"));
+            },
+            onKeyDown: (event) => {
+              if (event.key === "Enter" && event.shiftKey) {
+                // Prevent Downshift's default 'Enter' behavior.
+                (event.nativeEvent as any).preventDownshiftDefault = true;
+              } else if (
+                event.key === "Enter" &&
+                (!isOpen || items.length === 0)
+              ) {
+                // Prevent Downshift's default 'Enter' behavior.
+                (event.nativeEvent as any).preventDownshiftDefault = true;
+                if (props.onEnter) props.onEnter(event);
+                setInputValue("");
+                const value = event.currentTarget.value;
+                if (value !== "") {
+                  setPositionInHistory(history.length + 1);
+                  setHistory([...history, value]);
+                }
+              } else if (event.key === "Tab" && items.length > 0) {
+                setInputValue(items[0].name);
+                event.preventDefault();
+              } else if (
+                event.key === "ArrowUp" ||
+                (event.key === "ArrowDown" &&
+                  event.currentTarget.value.split("\n").length > 1)
+              ) {
+                (event.nativeEvent as any).preventDownshiftDefault = true;
+              } else if (
+                event.key === "ArrowUp" &&
+                event.currentTarget.value.split("\n").length > 1
+              ) {
+                if (positionInHistory == 0) return;
+                setInputValue(history[positionInHistory - 1]);
+                setPositionInHistory((prev) => prev - 1);
+              } else if (
+                event.key === "ArrowDown" &&
+                event.currentTarget.value.split("\n").length > 1
+              ) {
+                if (positionInHistory < history.length - 1) {
+                  setInputValue(history[positionInHistory + 1]);
+                }
+                setPositionInHistory((prev) =>
+                  Math.min(prev + 1, history.length)
+                );
               }
-            } else if (event.key === "Tab" && items.length > 0) {
-              setInputValue(items[0].name);
-              event.preventDefault();
-            } else if (
-              event.key === "ArrowUp" ||
-              (event.key === "ArrowDown" &&
-                event.currentTarget.value.split("\n").length > 1)
-            ) {
-              (event.nativeEvent as any).preventDownshiftDefault = true;
-            } else if (
-              event.key === "ArrowUp" &&
-              event.currentTarget.value.split("\n").length > 1
-            ) {
-              if (positionInHistory == 0) return;
-              setInputValue(history[positionInHistory - 1]);
-              setPositionInHistory((prev) => prev - 1);
-            } else if (
-              event.key === "ArrowDown" &&
-              event.currentTarget.value.split("\n").length > 1
-            ) {
-              if (positionInHistory < history.length - 1) {
-                setInputValue(history[positionInHistory + 1]);
+            },
+            ref: ref as any,
+          })}
+        />
+        <Ul
+          {...getMenuProps({
+            ref: ulRef,
+          })}
+          showAbove={showAbove()}
+          ulHeightPixels={ulRef.current?.getBoundingClientRect().height || 0}
+        >
+          {isOpen &&
+            items.map((item, index) => (
+              <Li
+                key={`${item.name}${index}`}
+                {...getItemProps({ item, index })}
+                highlighted={highlightedIndex === index}
+                selected={selectedItem === item}
+              >
+                <span>
+                  {item.name}: {item.description}
+                </span>
+              </Li>
+            ))}
+        </Ul>
+      </div>
+      <ContextDropdown hidden={!showContextDropdown}>
+        <p>Highlight code to include as context:</p>
+        {highlightedCodeSections.map((section, idx) => (
+          <>
+            <p>{section.filepath}</p>
+            <CodeBlock showCopy={false} key={idx}>
+              {section.contents}
+            </CodeBlock>
+          </>
+        ))}
+      </ContextDropdown>
+      <div className="px-2">
+        {highlightedCodeSections.map((section, idx) => (
+          <PillButton
+            onClick={() => {
+              console.log("delete context item", idx);
+              if (props.deleteContextItem) {
+                props.deleteContextItem(idx);
               }
-              setPositionInHistory((prev) =>
-                Math.min(prev + 1, history.length)
-              );
-            }
-          },
-          ref: ref as any,
-        })}
-      />
-      <Ul
-        {...getMenuProps({
-          ref: ulRef,
-        })}
-        showAbove={showAbove()}
-        ulHeightPixels={ulRef.current?.getBoundingClientRect().height || 0}
-      >
-        {isOpen &&
-          items.map((item, index) => (
-            <Li
-              key={`${item.name}${index}`}
-              {...getItemProps({ item, index })}
-              highlighted={highlightedIndex === index}
-              selected={selectedItem === item}
-            >
-              <span>
-                {item.name}: {item.description}
-              </span>
-            </Li>
-          ))}
-      </Ul>
-    </div>
+              setHighlightedCodeSections((prev) => {
+                const newSections = [...prev];
+                newSections.splice(idx, 1);
+                return newSections;
+              });
+            }}
+          >
+            {section.filepath}
+          </PillButton>
+        ))}
+      </div>
+    </>
   );
 });
 
diff --git a/extension/react-app/src/components/IterationContainer.tsx b/extension/react-app/src/components/IterationContainer.tsx
deleted file mode 100644
index a0053519..00000000
--- a/extension/react-app/src/components/IterationContainer.tsx
+++ /dev/null
@@ -1,77 +0,0 @@
-import { useState } from "react";
-import styled from "styled-components";
-import {
-  defaultBorderRadius,
-  MainContainerWithBorder,
-  secondaryDark,
-  vscBackground,
-} from ".";
-import { RangeInFile, FileEdit } from "../../../src/client";
-import CodeBlock from "./CodeBlock";
-import SubContainer from "./SubContainer";
-
-import { ChevronDown, ChevronRight } from "@styled-icons/heroicons-outline";
-
-export interface IterationContext {
-  codeSelections: RangeInFile[];
-  instruction: string;
-  suggestedChanges: FileEdit[];
-  status: "waiting" | "accepted" | "rejected";
-  summary?: string;
-  action: string;
-  error?: string;
-}
-
-interface IterationContainerProps {
-  iterationContext: IterationContext;
-}
-
-const IterationContainerDiv = styled.div<{ open: boolean }>`
-  background-color: ${(props) => (props.open ? vscBackground : secondaryDark)};
-  border-radius: ${defaultBorderRadius};
-  padding: ${(props) => (props.open ? "2px" : "8px")};
-`;
-
-function IterationContainer(props: IterationContainerProps) {
-  const [open, setOpen] = useState(false);
-
-  return (
-    <MainContainerWithBorder className="m-2 overflow-hidden">
-      <IterationContainerDiv open={open}>
-        <p
-          className="m-2 cursor-pointer"
-          onClick={() => setOpen((prev) => !prev)}
-        >
-          {open ? <ChevronDown size="1.4em" /> : <ChevronRight size="1.4em" />}
-          {props.iterationContext.summary ||
-            props.iterationContext.codeSelections
-              .map((cs) => cs.filepath)
-              .join("\n")}
-        </p>
-
-        {open && (
-          <>
-            <SubContainer title="Action">
-              {props.iterationContext.action}
-            </SubContainer>
-            {props.iterationContext.error && (
-              <SubContainer title="Error">
-                <CodeBlock>{props.iterationContext.error}</CodeBlock>
-              </SubContainer>
-            )}
-            {props.iterationContext.suggestedChanges.map((sc) => {
-              return (
-                <SubContainer title="Suggested Change">
-                  {sc.filepath}
-                  <CodeBlock>{sc.replacement}</CodeBlock>
-                </SubContainer>
-              );
-            })}
-          </>
-        )}
-      </IterationContainerDiv>
-    </MainContainerWithBorder>
-  );
-}
-
-export default IterationContainer;
diff --git a/extension/react-app/src/components/StepContainer.tsx b/extension/react-app/src/components/StepContainer.tsx
index 02c04548..cb83f20a 100644
--- a/extension/react-app/src/components/StepContainer.tsx
+++ b/extension/react-app/src/components/StepContainer.tsx
@@ -246,10 +246,14 @@ function StepContainer(props: StepContainerProps) {
               className="overflow-x-scroll"
               components={{
                 pre: ({ node, ...props }) => {
-                  return <CodeBlock children={props.children[0]} />;
+                  return (
+                    <CodeBlock
+                      children={(props.children[0] as any).props.children[0]}
+                    />
+                  );
                 },
                 code: ({ node, ...props }) => {
-                  return <StyledCode children={props.children[0]} />;
+                  return <StyledCode children={props.children[0] as any} />;
                 },
               }}
             >
diff --git a/extension/react-app/src/hooks/ContinueGUIClientProtocol.ts b/extension/react-app/src/hooks/ContinueGUIClientProtocol.ts
index 3d8e0a38..228e9a53 100644
--- a/extension/react-app/src/hooks/ContinueGUIClientProtocol.ts
+++ b/extension/react-app/src/hooks/ContinueGUIClientProtocol.ts
@@ -20,6 +20,8 @@ abstract class AbstractContinueGUIClientProtocol {
   abstract retryAtIndex(index: number): void;
 
   abstract deleteAtIndex(index: number): void;
+
+  abstract deleteContextItemAtIndex(index: number): void;
 }
 
 export default AbstractContinueGUIClientProtocol;
diff --git a/extension/react-app/src/hooks/useContinueGUIProtocol.ts b/extension/react-app/src/hooks/useContinueGUIProtocol.ts
index f43a66ff..a0c38c0f 100644
--- a/extension/react-app/src/hooks/useContinueGUIProtocol.ts
+++ b/extension/react-app/src/hooks/useContinueGUIProtocol.ts
@@ -70,6 +70,10 @@ class ContinueGUIClientProtocol extends AbstractContinueGUIClientProtocol {
   deleteAtIndex(index: number) {
     this.messenger.send("delete_at_index", { index });
   }
+
+  deleteContextItemAtIndex(index: number) {
+    this.messenger.send("delete_context_item_at_index", { index });
+  }
 }
 
 export default ContinueGUIClientProtocol;
diff --git a/extension/react-app/src/tabs/gui.tsx b/extension/react-app/src/tabs/gui.tsx
index 39925fc5..658aa503 100644
--- a/extension/react-app/src/tabs/gui.tsx
+++ b/extension/react-app/src/tabs/gui.tsx
@@ -69,6 +69,7 @@ function GUI(props: GUIProps) {
   const [usingFastModel, setUsingFastModel] = useState(false);
   const [waitingForSteps, setWaitingForSteps] = useState(false);
   const [userInputQueue, setUserInputQueue] = useState<string[]>([]);
+  const [highlightedRanges, setHighlightedRanges] = useState([]);
   const [availableSlashCommands, setAvailableSlashCommands] = useState<
     { name: string; description: string }[]
   >([]);
@@ -81,60 +82,6 @@ function GUI(props: GUIProps) {
   ]);
   const [history, setHistory] = useState<History | undefined>({
     timeline: [
-      {
-        step: {
-          name: "SequentialStep",
-          hide: true,
-          description: "Running step: SequentialStep",
-          system_message: null,
-          chat_context: [],
-          manage_own_chat_context: false,
-          steps: [
-            {
-              name: "Welcome to Continue",
-              hide: false,
-              description: `Welcome to Continue`,
-              system_message: null,
-              chat_context: [],
-              manage_own_chat_context: false,
-              message: `# Welcome to Continue
-
-              _If it's your first time using Continue, it can take up to a minute for the server to install._
-              
-              Continue is not perfect, but a great tool to add to your toolbox. These are the tasks that Continue is currently best at:
-              
-              - Highlight a section of code and instruct Continue to refactor it, e.g. \`"/edit make this use more descriptive variable names"\`
-              - Ask questions of the open file, e.g. \`"/explain what is the purpose of each of these if statements?"\`
-              - Ask Continue to build the scaffolding of a new file from scratch, e.g. \`"add a React component for syntax highlighted code"\`
-              
-              You can use "slash commands" to directly instruct Continue what to do, or just enter a request and it will automatically decide next steps. To see the list of available slash commands, type '/'.
-              
-              If you highlight code, edits and explanations will be localized to the highlighted range. Otherwise, the currently open file is used. In both cases, the code is combined with the previous steps to construct the context.
-              `,
-            },
-            {
-              name: "Welcome to Continue!",
-              hide: true,
-              description: "Welcome to Continue!",
-              system_message: null,
-              chat_context: [],
-              manage_own_chat_context: false,
-            },
-            {
-              name: "StepsOnStartupStep",
-              hide: true,
-              description: "Running steps on startup",
-              system_message: null,
-              chat_context: [],
-              manage_own_chat_context: false,
-            },
-          ],
-        },
-        observation: null,
-        depth: 0,
-        deleted: false,
-        active: false,
-      },
       {
         step: {
           name: "Welcome to Continue",
@@ -147,167 +94,13 @@ function GUI(props: GUIProps) {
           message:
             "Type '/' to see the list of available slash commands. If you highlight code, edits and explanations will be localized to the highlighted range. Otherwise, the currently open file is used. In both cases, the code is combined with the previous steps to construct the context.",
         },
-        observation: {
-          text: "Type '/' to see the list of available slash commands. If you highlight code, edits and explanations will be localized to the highlighted range. Otherwise, the currently open file is used. In both cases, the code is combined with the previous steps to construct the context.",
-        },
-        depth: 1,
-        deleted: false,
-        active: false,
-      },
-      {
-        step: {
-          name: "Welcome to Continue!",
-          hide: true,
-          description: "Welcome to Continue!",
-          system_message: null,
-          chat_context: [],
-          manage_own_chat_context: false,
-        },
-        observation: null,
-        depth: 1,
-        deleted: false,
-        active: false,
-      },
-      {
-        step: {
-          name: "StepsOnStartupStep",
-          hide: true,
-          description: "Running steps on startup",
-          system_message: null,
-          chat_context: [],
-          manage_own_chat_context: false,
-        },
-        observation: null,
-        depth: 1,
+        depth: 0,
         deleted: false,
         active: false,
       },
     ],
     current_index: 3,
   } as any);
-  //   {
-  //   timeline: [
-  //     {
-  //       step: {
-  //         name: "Waiting for user input",
-  //         cmd: "python3 /Users/natesesti/Desktop/continue/extension/examples/python/main.py",
-  //         description:
-  //           "Run `python3 /Users/natesesti/Desktop/continue/extension/examples/python/main.py` and ```\nprint(sum(first, second))\n```\n- Testing\n- Testing 2\n- Testing 3",
-  //       },
-  //       observation: {
-  //         title: "ERROR FOUND",
-  //         error:
-  //           "Traceback (most recent call last):\n  File \"/Users/natesesti/Desktop/continue/extension/examples/python/main.py\", line 7, in <module>\n    print(sum(first, second))\n          ^^^^^^^^^^^^^^^^^^\n  File \"/Users/natesesti/Desktop/continue/extension/examples/python/sum.py\", line 2, in sum\n    return a + b\n           ~~^~~\nTypeError: unsupported operand type(s) for +: 'int' and 'str'",
-  //       },
-  //       output: [
-  //         {
-  //           traceback: {
-  //             frames: [
-  //               {
-  //                 filepath:
-  //                   "/Users/natesesti/Desktop/continue/extension/examples/python/main.py",
-  //                 lineno: 7,
-  //                 function: "<module>",
-  //                 code: "print(sum(first, second))",
-  //               },
-  //             ],
-  //             message: "unsupported operand type(s) for +: 'int' and 'str'",
-  //             error_type:
-  //               '          ^^^^^^^^^^^^^^^^^^\n  File "/Users/natesesti/Desktop/continue/extension/examples/python/sum.py", line 2, in sum\n    return a + b\n           ~~^~~\nTypeError',
-  //             full_traceback:
-  //               "Traceback (most recent call last):\n  File \"/Users/natesesti/Desktop/continue/extension/examples/python/main.py\", line 7, in <module>\n    print(sum(first, second))\n          ^^^^^^^^^^^^^^^^^^\n  File \"/Users/natesesti/Desktop/continue/extension/examples/python/sum.py\", line 2, in sum\n    return a + b\n           ~~^~~\nTypeError: unsupported operand type(s) for +: 'int' and 'str'",
-  //           },
-  //         },
-  //         null,
-  //       ],
-  //     },
-  //     {
-  //       step: {
-  //         name: "EditCodeStep",
-  //         range_in_files: [
-  //           {
-  //             filepath:
-  //               "/Users/natesesti/Desktop/continue/extension/examples/python/main.py",
-  //             range: {
-  //               start: {
-  //                 line: 0,
-  //                 character: 0,
-  //               },
-  //               end: {
-  //                 line: 6,
-  //                 character: 25,
-  //               },
-  //             },
-  //           },
-  //         ],
-  //         prompt:
-  //           "I ran into this problem with my Python code:\n\n                Traceback (most recent call last):\n  File \"/Users/natesesti/Desktop/continue/extension/examples/python/main.py\", line 7, in <module>\n    print(sum(first, second))\n          ^^^^^^^^^^^^^^^^^^\n  File \"/Users/natesesti/Desktop/continue/extension/examples/python/sum.py\", line 2, in sum\n    return a + b\n           ~~^~~\nTypeError: unsupported operand type(s) for +: 'int' and 'str'\n\n                Below are the files that might need to be fixed:\n\n                {code}\n\n                This is what the code should be in order to avoid the problem:\n",
-  //         description:
-  //           "Run `python3 /Users/natesesti/Desktop/continue/extension/examples/python/main.py` and\n```python\nprint(sum(first, second))\n```\n- Testing\n- Testing 2\n- Testing 3",
-  //       },
-  //       output: [
-  //         null,
-  //         {
-  //           reversible: true,
-  //           actions: [
-  //             {
-  //               reversible: true,
-  //               filesystem: {},
-  //               filepath:
-  //                 "/Users/natesesti/Desktop/continue/extension/examples/python/main.py",
-  //               range: {
-  //                 start: {
-  //                   line: 0,
-  //                   character: 0,
-  //                 },
-  //                 end: {
-  //                   line: 6,
-  //                   character: 25,
-  //                 },
-  //               },
-  //               replacement:
-  //                 "\nfrom sum import sum\n\nfirst = 1\nsecond = 2\n\nprint(sum(first, second))",
-  //             },
-  //           ],
-  //         },
-  //       ],
-  //     },
-  //     {
-  //       active: false,
-  //       step: {
-  //         name: "SolveTracebackStep",
-  //         traceback: {
-  //           frames: [
-  //             {
-  //               filepath:
-  //                 "/Users/natesesti/Desktop/continue/extension/examples/python/main.py",
-  //               lineno: 7,
-  //               function: "<module>",
-  //               code: "print(sum(first, second))",
-  //             },
-  //           ],
-  //           message: "unsupported operand type(s) for +: 'int' and 'str'",
-  //           error_type:
-  //             '          ^^^^^^^^^^^^^^^^^^\n  File "/Users/natesesti/Desktop/continue/extension/examples/python/sum.py", line 2, in sum\n    return a + b\n           ~~^~~\nTypeError',
-  //           full_traceback:
-  //             "Traceback (most recent call last):\n  File \"/Users/natesesti/Desktop/continue/extension/examples/python/main.py\", line 7, in <module>\n    print(sum(first, second))\n          ^^^^^^^^^^^^^^^^^^\n  File \"/Users/natesesti/Desktop/continue/extension/examples/python/sum.py\", line 2, in sum\n    return a + b\n           ~~^~~\nTypeError: unsupported operand type(s) for +: 'int' and 'str'",
-  //         },
-  //         description: "Running step: SolveTracebackStep",
-  //       },
-  //       output: [null, null],
-  //     },
-  //     {
-  //       step: {
-  //         name: "RunCodeStep",
-  //         cmd: "python3 /Users/natesesti/Desktop/continue/extension/examples/python/main.py",
-  //         description:
-  //           "Run `python3 /Users/natesesti/Desktop/continue/extension/examples/python/main.py`",
-  //       },
-  //       output: [null, null],
-  //     },
-  //   ],
-  //   current_index: 3,
-  // } as any);
 
   const [showFeedbackDialog, setShowFeedbackDialog] = useState(false);
 
@@ -356,6 +149,7 @@ function GUI(props: GUIProps) {
         topGuiDivRef.current?.offsetHeight - window.scrollY < 100;
       setWaitingForSteps(state.active);
       setHistory(state.history);
+      setHighlightedRanges(state.highlighted_ranges);
       setUserInputQueue(state.user_input_queue);
       setStepsOpen((prev) => {
         const nextStepsOpen = [...prev];
@@ -392,6 +186,13 @@ function GUI(props: GUIProps) {
 
   const mainTextInputRef = useRef<HTMLInputElement>(null);
 
+  const deleteContextItem = useCallback(
+    (idx: number) => {
+      client?.deleteContextItemAtIndex(idx);
+    },
+    [client]
+  );
+
   useEffect(() => {
     if (mainTextInputRef.current) {
       mainTextInputRef.current.focus();
@@ -533,6 +334,8 @@ function GUI(props: GUIProps) {
           }}
           onInputValueChange={() => {}}
           items={availableSlashCommands}
+          highlightedCodeSections={highlightedRanges}
+          deleteContextItem={deleteContextItem}
         />
         <ContinueButton onClick={onMainTextInput} />
       </TopGUIDiv>
diff --git a/extension/src/continueIdeClient.ts b/extension/src/continueIdeClient.ts
index 21104abe..8f45b849 100644
--- a/extension/src/continueIdeClient.ts
+++ b/extension/src/continueIdeClient.ts
@@ -12,18 +12,17 @@ import {
   acceptSuggestionCommand,
   rejectSuggestionCommand,
 } from "./suggestions";
-import { debugPanelWebview, setupDebugPanel } from "./debugPanel";
 import { FileEditWithFullContents } from "../schema/FileEditWithFullContents";
 import fs = require("fs");
 import { WebsocketMessenger } from "./util/messenger";
-import { decorationManager } from "./decorations";
-
 class IdeProtocolClient {
   private messenger: WebsocketMessenger | null = null;
   private readonly context: vscode.ExtensionContext;
 
   private _makingEdit = 0;
 
+  private _highlightDebounce: NodeJS.Timeout | null = null;
+
   constructor(serverUrl: string, context: vscode.ExtensionContext) {
     this.context = context;
 
@@ -65,6 +64,36 @@ class IdeProtocolClient {
     //     this._makingEdit--;
     //   }
     // });
+
+    // Setup listeners for any file changes in open editors
+    vscode.window.onDidChangeTextEditorSelection((event) => {
+      if (this._highlightDebounce) {
+        clearTimeout(this._highlightDebounce);
+      }
+      this._highlightDebounce = setTimeout(() => {
+        const highlightedCode = event.textEditor.selections
+          .filter((s) => !s.isEmpty)
+          .map((selection) => {
+            const range = new vscode.Range(selection.start, selection.end);
+            const contents = event.textEditor.document.getText(range);
+            return {
+              filepath: event.textEditor.document.uri.fsPath,
+              contents,
+              range: {
+                start: {
+                  line: selection.start.line,
+                  character: selection.start.character,
+                },
+                end: {
+                  line: selection.end.line,
+                  character: selection.end.character,
+                },
+              },
+            };
+          });
+        this.sendHighlightedCode(highlightedCode);
+      }, 100);
+    });
   }
 
   async handleMessage(
@@ -375,6 +404,10 @@ class IdeProtocolClient {
   sendCommandOutput(output: string) {
     this.messenger?.send("commandOutput", { output });
   }
+
+  sendHighlightedCode(highlightedCode: (RangeInFile & { contents: string })[]) {
+    this.messenger?.send("highlightedCodePush", { highlightedCode });
+  }
 }
 
 export default IdeProtocolClient;
-- 
cgit v1.2.3-70-g09d2


From 894a197892fc4e3a6a5af7d47b7702ea895e20b7 Mon Sep 17 00:00:00 2001
From: Nate Sesti <sestinj@gmail.com>
Date: Sun, 2 Jul 2023 20:14:27 -0700
Subject: finishing up explicit context

---
 continuedev/src/continuedev/core/autopilot.py      | 17 ++---
 continuedev/src/continuedev/models/filesystem.py   | 16 ++---
 continuedev/src/continuedev/models/main.py         |  5 ++
 continuedev/src/continuedev/steps/chat.py          |  2 +-
 extension/react-app/src/components/ComboBox.tsx    | 83 ++++++++++++----------
 .../react-app/src/components/ContinueButton.tsx    |  1 +
 extension/react-app/src/components/PillButton.tsx  | 66 +++++++++++++++++
 7 files changed, 131 insertions(+), 59 deletions(-)
 create mode 100644 extension/react-app/src/components/PillButton.tsx

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

diff --git a/continuedev/src/continuedev/core/autopilot.py b/continuedev/src/continuedev/core/autopilot.py
index b9e61c63..1a77ca64 100644
--- a/continuedev/src/continuedev/core/autopilot.py
+++ b/continuedev/src/continuedev/core/autopilot.py
@@ -139,21 +139,22 @@ class Autopilot(ContinueBaseModel):
         for rif in range_in_files:
             rif.filepath = os.path.relpath(rif.filepath, workspace_path)
 
+        old_ranges = self._highlighted_ranges + range_in_files
         new_ranges = []
-        for rif in range_in_files:
+
+        while len(old_ranges) > 0:
+            old_range = old_ranges.pop(0)
             found_overlap = False
-            for i in range(len(self._highlighted_ranges)):
-                hr = self._highlighted_ranges[i]
-                if hr.filepath == rif.filepath and hr.range.overlaps_with(rif.range):
-                    new_ranges.append(rif.union(hr))
+            for i in range(len(new_ranges)):
+                if old_range.filepath == new_ranges[i].filepath and old_range.range.overlaps_with(new_ranges[i].range):
+                    new_ranges[i] = old_range.union(new_ranges[i])
                     found_overlap = True
-                    self._highlighted_ranges.pop(i)
                     break
 
             if not found_overlap:
-                new_ranges.append(rif)
+                new_ranges.append(old_range)
 
-        self._highlighted_ranges += new_ranges
+        self._highlighted_ranges = new_ranges
         await self.update_subscribers()
 
     _step_depth: int = 0
diff --git a/continuedev/src/continuedev/models/filesystem.py b/continuedev/src/continuedev/models/filesystem.py
index fc1c3f13..df0b15d7 100644
--- a/continuedev/src/continuedev/models/filesystem.py
+++ b/continuedev/src/continuedev/models/filesystem.py
@@ -40,21 +40,15 @@ class RangeInFileWithContents(RangeInFile):
 
         assert first.filepath == second.filepath
 
-        # Calculate the start and end positions of the overlap
-        overlap_start = max(first.range.start,
-                            second.range.start) - first.range.start
-        overlap_end = min(first.range.end, second.range.end) - \
-            first.range.start
-
-        # Calculate the new contents by removing the overlap
-        union_contents = first.contents[:overlap_start] + \
-            second.contents[overlap_start:overlap_end] + \
-            first.contents[overlap_end:]
+        # Calculate union of contents
+        num_overlapping_lines = first.range.end.line - second.range.start.line + 1
+        union_lines = first.contents.splitlines()[:-num_overlapping_lines] + \
+            second.contents.splitlines()
 
         return RangeInFileWithContents(
             filepath=first.filepath,
             range=first.range.union(second.range),
-            contents=union_contents
+            contents="\n".join(union_lines)
         )
 
     @staticmethod
diff --git a/continuedev/src/continuedev/models/main.py b/continuedev/src/continuedev/models/main.py
index 101be4ae..fa736772 100644
--- a/continuedev/src/continuedev/models/main.py
+++ b/continuedev/src/continuedev/models/main.py
@@ -43,6 +43,11 @@ class Position(BaseModel):
     def from_end_of_file(contents: str) -> "Position":
         return Position.from_index(contents, len(contents))
 
+    def to_index(self, string: str) -> int:
+        """Convert line and character to index in string"""
+        lines = string.splitlines()
+        return sum(map(len, lines[:self.line])) + self.character
+
 
 class Range(BaseModel):
     """A range in a file. 0-indexed."""
diff --git a/continuedev/src/continuedev/steps/chat.py b/continuedev/src/continuedev/steps/chat.py
index 8494563b..b10ec3d7 100644
--- a/continuedev/src/continuedev/steps/chat.py
+++ b/continuedev/src/continuedev/steps/chat.py
@@ -106,7 +106,7 @@ class RunTerminalCommandStep(Step):
 
 class ViewDirectoryTreeStep(Step):
     name: str = "View Directory Tree"
-    description: str = "View the directory tree to learn which folder and files exist."
+    description: str = "View the directory tree to learn which folder and files exist. You should always do this before adding new files."
 
     async def describe(self, models: Models) -> Coroutine[Any, Any, Coroutine[str, None, None]]:
         return f"Viewed the directory tree."
diff --git a/extension/react-app/src/components/ComboBox.tsx b/extension/react-app/src/components/ComboBox.tsx
index 34027a42..f299c3a2 100644
--- a/extension/react-app/src/components/ComboBox.tsx
+++ b/extension/react-app/src/components/ComboBox.tsx
@@ -9,6 +9,7 @@ import {
 } from ".";
 import CodeBlock from "./CodeBlock";
 import { RangeInFile } from "../../../src/client";
+import PillButton from "./PillButton";
 
 const mainInputFontSize = 16;
 
@@ -22,27 +23,9 @@ const ContextDropdown = styled.div`
   border-bottom-left-radius: ${defaultBorderRadius};
   /* border: 1px solid white; */
   border-top: none;
-  margin-left: 8px;
-  margin-right: 8px;
-  margin-top: -12px;
+  margin: 8px;
   outline: 1px solid orange;
-`;
-
-const PillButton = styled.button`
-  display: flex;
-  justify-content: space-between;
-  align-items: center;
-  border: none;
-  color: white;
-  background-color: gray;
-  border-radius: 50px;
-  padding: 5px 10px;
-  margin: 5px 0;
-  cursor: pointer;
-
-  &:hover {
-    background-color: ${buttonColor};
-  }
+  z-index: 5;
 `;
 
 const MainTextInput = styled.textarea`
@@ -118,7 +101,9 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
   // The position of the current command you are typing now, so the one that will be appended to history once you press enter
   const [positionInHistory, setPositionInHistory] = React.useState<number>(0);
   const [items, setItems] = React.useState(props.items);
-  const [showContextDropdown, setShowContextDropdown] = React.useState(false);
+  const [hoveringButton, setHoveringButton] = React.useState(false);
+  const [hoveringContextDropdown, setHoveringContextDropdown] =
+    React.useState(false);
   const [highlightedCodeSections, setHighlightedCodeSections] = React.useState(
     props.highlightedCodeSections || [
       {
@@ -184,7 +169,7 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
                 300
               ).toString()}px`;
 
-              setShowContextDropdown(target.value.endsWith("@"));
+              // setShowContextDropdown(target.value.endsWith("@"));
             },
             onKeyDown: (event) => {
               if (event.key === "Enter" && event.shiftKey) {
@@ -256,22 +241,11 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
             ))}
         </Ul>
       </div>
-      <ContextDropdown hidden={!showContextDropdown}>
-        <p>Highlight code to include as context:</p>
-        {highlightedCodeSections.map((section, idx) => (
-          <>
-            <p>{section.filepath}</p>
-            <CodeBlock showCopy={false} key={idx}>
-              {section.contents}
-            </CodeBlock>
-          </>
-        ))}
-      </ContextDropdown>
-      <div className="px-2">
+      <div className="px-2 flex gap-2 items-center flex-wrap">
         {highlightedCodeSections.map((section, idx) => (
           <PillButton
-            onClick={() => {
-              console.log("delete context item", idx);
+            title={section.filepath}
+            onDelete={() => {
               if (props.deleteContextItem) {
                 props.deleteContextItem(idx);
               }
@@ -281,11 +255,42 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
                 return newSections;
               });
             }}
-          >
-            {section.filepath}
-          </PillButton>
+            onHover={(val: boolean) => {
+              if (val) {
+                setHoveringButton(val);
+              } else {
+                setTimeout(() => {
+                  setHoveringButton(val);
+                }, 100);
+              }
+            }}
+          />
         ))}
+
+        <span className="text-trueGray-400 ml-auto mr-4 text-xs">
+          Highlight code to include as context.{" "}
+          {highlightedCodeSections.length > 0 &&
+            "Otherwise using entire currently open file."}
+        </span>
       </div>
+      <ContextDropdown
+        onMouseEnter={() => {
+          setHoveringContextDropdown(true);
+        }}
+        onMouseLeave={() => {
+          setHoveringContextDropdown(false);
+        }}
+        hidden={!hoveringContextDropdown && !hoveringButton}
+      >
+        {highlightedCodeSections.map((section, idx) => (
+          <>
+            <p>{section.filepath}</p>
+            <CodeBlock showCopy={false} key={idx}>
+              {section.contents}
+            </CodeBlock>
+          </>
+        ))}
+      </ContextDropdown>
     </>
   );
 });
diff --git a/extension/react-app/src/components/ContinueButton.tsx b/extension/react-app/src/components/ContinueButton.tsx
index ef6719b7..5295799a 100644
--- a/extension/react-app/src/components/ContinueButton.tsx
+++ b/extension/react-app/src/components/ContinueButton.tsx
@@ -6,6 +6,7 @@ import { RootStore } from "../redux/store";
 
 let StyledButton = styled(Button)`
   margin: auto;
+  margin-top: 8px;
   display: grid;
   grid-template-columns: 30px 1fr;
   align-items: center;
diff --git a/extension/react-app/src/components/PillButton.tsx b/extension/react-app/src/components/PillButton.tsx
new file mode 100644
index 00000000..33451db5
--- /dev/null
+++ b/extension/react-app/src/components/PillButton.tsx
@@ -0,0 +1,66 @@
+import { useState } from "react";
+import styled from "styled-components";
+import { defaultBorderRadius } from ".";
+
+const Button = styled.button`
+  border: none;
+  color: white;
+  background-color: transparent;
+  border: 1px solid white;
+  border-radius: ${defaultBorderRadius};
+  padding: 3px 6px;
+
+  &:hover {
+    background-color: white;
+    color: black;
+  }
+`;
+
+interface PillButtonProps {
+  onHover?: (arg0: boolean) => void;
+  onDelete?: () => void;
+  title: string;
+}
+
+const PillButton = (props: PillButtonProps) => {
+  const [isHovered, setIsHovered] = useState(false);
+  return (
+    <Button
+      onMouseEnter={() => {
+        setIsHovered(true);
+        if (props.onHover) {
+          props.onHover(true);
+        }
+      }}
+      onMouseLeave={() => {
+        setIsHovered(false);
+        if (props.onHover) {
+          props.onHover(false);
+        }
+      }}
+    >
+      <div
+        style={{ display: "grid", gridTemplateColumns: "1fr auto", gap: "4px" }}
+      >
+        <span>{props.title}</span>
+        <span
+          style={{
+            cursor: "pointer",
+            color: "red",
+            borderLeft: "1px solid black",
+            paddingLeft: "4px",
+          }}
+          hidden={!isHovered}
+          onClick={() => {
+            props.onDelete?.();
+            props.onHover?.(false);
+          }}
+        >
+          X
+        </span>
+      </div>
+    </Button>
+  );
+};
+
+export default PillButton;
-- 
cgit v1.2.3-70-g09d2


From bc96340b042a37e124c91ac22f7cc2d52858d178 Mon Sep 17 00:00:00 2001
From: Ty Dunn <ty@tydunn.com>
Date: Mon, 3 Jul 2023 18:54:33 -0700
Subject: improving slash command message

---
 continuedev/src/continuedev/core/policy.py      | 4 +++-
 extension/react-app/src/components/ComboBox.tsx | 2 +-
 extension/react-app/src/tabs/gui.tsx            | 4 ++--
 3 files changed, 6 insertions(+), 4 deletions(-)

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

diff --git a/continuedev/src/continuedev/core/policy.py b/continuedev/src/continuedev/core/policy.py
index 0b417959..250ae8f8 100644
--- a/continuedev/src/continuedev/core/policy.py
+++ b/continuedev/src/continuedev/core/policy.py
@@ -29,7 +29,9 @@ class DemoPolicy(Policy):
         if history.get_current() is None:
             return (
                 MessageStep(name="Welcome to Continue", message=dedent("""\
-                    Type '/' to see the list of available slash commands. If you highlight code, edits and explanations will be localized to the highlighted range. Otherwise, the currently open file is used. In both cases, the code is combined with the previous steps to construct the context.""")) >>
+                    - Highlight code and ask a question or give instructions
+                    - Past steps are used as additional context by default
+                    - Use slash commands when you want fine-grained control""")) >>
                 WelcomeStep() >>
                 # SetupContinueWorkspaceStep() >>
                 # CreateCodebaseIndexChroma() >>
diff --git a/extension/react-app/src/components/ComboBox.tsx b/extension/react-app/src/components/ComboBox.tsx
index f299c3a2..87c1abc0 100644
--- a/extension/react-app/src/components/ComboBox.tsx
+++ b/extension/react-app/src/components/ComboBox.tsx
@@ -158,7 +158,7 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
       <div className="flex px-2" ref={divRef} hidden={!isOpen}>
         <MainTextInput
           disabled={props.disabled}
-          placeholder="Type '/' to see available slash commands."
+          placeholder="Ask a question, give instructions, or type '/' to see slash commands"
           {...getInputProps({
             onChange: (e) => {
               const target = e.target as HTMLTextAreaElement;
diff --git a/extension/react-app/src/tabs/gui.tsx b/extension/react-app/src/tabs/gui.tsx
index e0b32a24..973982ba 100644
--- a/extension/react-app/src/tabs/gui.tsx
+++ b/extension/react-app/src/tabs/gui.tsx
@@ -87,12 +87,12 @@ function GUI(props: GUIProps) {
           name: "Welcome to Continue",
           hide: false,
           description:
-            "Type '/' to see the list of available slash commands. If you highlight code, edits and explanations will be localized to the highlighted range. Otherwise, the currently open file is used. In both cases, the code is combined with the previous steps to construct the context.",
+            "Highlight code and ask a question or give instructions. Past steps are used as additional context by default. Use slash commands when you want fine-grained control.",
           system_message: null,
           chat_context: [],
           manage_own_chat_context: false,
           message:
-            "Type '/' to see the list of available slash commands. If you highlight code, edits and explanations will be localized to the highlighted range. Otherwise, the currently open file is used. In both cases, the code is combined with the previous steps to construct the context.",
+            "Highlight code and ask a question or give instructions. Past steps are used as additional context by default. Use slash commands when you want fine-grained control.",
         },
         depth: 0,
         deleted: false,
-- 
cgit v1.2.3-70-g09d2


From 813329600c2c7022b006ba566a869179db067089 Mon Sep 17 00:00:00 2001
From: Nate Sesti <sestinj@gmail.com>
Date: Mon, 3 Jul 2023 19:34:33 -0700
Subject: fix python version on windows, other bugs, jest

---
 continuedev/src/continuedev/models/filesystem.py   |     6 +
 continuedev/src/continuedev/steps/chat.py          |     5 -
 extension/DEV_README.md                            |     4 +
 extension/jest.config.js                           |     4 +
 extension/package-lock.json                        | 10821 +++++++++++++------
 extension/package.json                             |    12 +-
 extension/react-app/src/components/ComboBox.tsx    |     2 +-
 extension/react-app/src/tabs/gui.tsx               |    43 +-
 extension/src/__mocks__/vscode.ts                  |     7 +
 extension/src/activation/environmentSetup.ts       |    17 +-
 .../src/activation/test/environmentSetup.test.ts   |    70 +
 extension/src/test/suite/terminalEmulator.test.ts  |    28 -
 12 files changed, 7787 insertions(+), 3232 deletions(-)
 create mode 100644 extension/jest.config.js
 create mode 100644 extension/src/__mocks__/vscode.ts
 create mode 100644 extension/src/activation/test/environmentSetup.test.ts
 delete mode 100644 extension/src/test/suite/terminalEmulator.test.ts

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

diff --git a/continuedev/src/continuedev/models/filesystem.py b/continuedev/src/continuedev/models/filesystem.py
index df0b15d7..ca12579c 100644
--- a/continuedev/src/continuedev/models/filesystem.py
+++ b/continuedev/src/continuedev/models/filesystem.py
@@ -54,6 +54,12 @@ class RangeInFileWithContents(RangeInFile):
     @staticmethod
     def from_entire_file(filepath: str, content: str) -> "RangeInFileWithContents":
         lines = content.splitlines()
+        if not lines:
+            return RangeInFileWithContents(
+                filepath=filepath,
+                range=Range.from_shorthand(0, 0, 0, 0),
+                contents=""
+            )
         return RangeInFileWithContents(
             filepath=filepath,
             range=Range.from_shorthand(
diff --git a/continuedev/src/continuedev/steps/chat.py b/continuedev/src/continuedev/steps/chat.py
index 58f43bcf..013cb578 100644
--- a/continuedev/src/continuedev/steps/chat.py
+++ b/continuedev/src/continuedev/steps/chat.py
@@ -74,11 +74,6 @@ class AddFileStep(Step):
 
         await sdk.ide.setFileOpen(os.path.join(sdk.ide.workspace_directory, self.filename))
 
-        open_files = await sdk.ide.getOpenFiles()
-        if len(open_files) > 0:
-            currently_open_file = (await sdk.ide.getOpenFiles())[0]
-            await sdk.ide.setFileOpen(currently_open_file)
-
 
 class DeleteFileStep(Step):
     name: str = "Delete File"
diff --git a/extension/DEV_README.md b/extension/DEV_README.md
index cf168cb3..c247b82c 100644
--- a/extension/DEV_README.md
+++ b/extension/DEV_README.md
@@ -7,3 +7,7 @@ This is the Continue VS Code Extension. Its primary jobs are
 3. Run a Continue server in the background, which connects to both the IDE protocol and the React app. The server is launched in `src/activation/environmentSetup.ts` by calling Python code that lives in `scripts/` (unless extension settings define a server URL other than localhost:65432, in which case the extension will just connect to that).
 
 4. Open Continue
+
+# Notes
+
+- We require vscode engine `^1.67.0` and use `@types/vscode` version `1.67.0` because this is the earliest version that doesn't break any of the APIs we are using. If you go back to `1.66.0`, then it will break `vscode.window.tabGroups`.
diff --git a/extension/jest.config.js b/extension/jest.config.js
new file mode 100644
index 00000000..d5393251
--- /dev/null
+++ b/extension/jest.config.js
@@ -0,0 +1,4 @@
+module.exports = {
+  testEnvironment: "node",
+  preset: "ts-jest",
+};
diff --git a/extension/package-lock.json b/extension/package-lock.json
index 74784fdd..07cd8a8b 100644
--- a/extension/package-lock.json
+++ b/extension/package-lock.json
@@ -1,12 +1,12 @@
 {
   "name": "continue",
-  "version": "0.0.104",
+  "version": "0.0.105",
   "lockfileVersion": 2,
   "requires": true,
   "packages": {
     "": {
       "name": "continue",
-      "version": "0.0.104",
+      "version": "0.0.105",
       "license": "Apache-2.0",
       "dependencies": {
         "@electron/rebuild": "^3.2.10",
@@ -20,7 +20,7 @@
         "downshift": "^7.6.0",
         "fkill": "^8.1.0",
         "highlight.js": "^11.7.0",
-        "posthog-js": "^1.63.3",
+        "posthog-js": "^1.68.3",
         "react-markdown": "^8.0.7",
         "react-redux": "^8.0.5",
         "strip-ansi": "^7.1.0",
@@ -32,12 +32,13 @@
       "devDependencies": {
         "@openapitools/openapi-generator-cli": "^2.5.2",
         "@types/glob": "^8.0.0",
+        "@types/jest": "^29.5.2",
         "@types/mocha": "^10.0.1",
         "@types/node": "16.x",
         "@types/node-fetch": "^2.6.2",
         "@types/react-dom": "^18.2.4",
         "@types/styled-components": "^5.1.26",
-        "@types/vscode": "1.60",
+        "@types/vscode": "1.67",
         "@types/ws": "^8.5.4",
         "@typescript-eslint/eslint-plugin": "^5.45.0",
         "@typescript-eslint/parser": "^5.45.0",
@@ -45,13 +46,15 @@
         "esbuild": "^0.17.19",
         "eslint": "^8.28.0",
         "glob": "^8.0.3",
+        "jest": "^29.5.0",
         "json-schema-to-typescript": "^12.0.0",
         "mocha": "^10.1.0",
+        "ts-jest": "^29.1.1",
         "typescript": "^4.9.3",
         "vsce": "^2.15.0"
       },
       "engines": {
-        "vscode": "^1.60.0"
+        "vscode": "^1.67.0"
       }
     },
     "node_modules/@alloc/quick-lru": {
@@ -65,25 +68,90 @@
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
+    "node_modules/@ampproject/remapping": {
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz",
+      "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==",
+      "dev": true,
+      "dependencies": {
+        "@jridgewell/gen-mapping": "^0.3.0",
+        "@jridgewell/trace-mapping": "^0.3.9"
+      },
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
     "node_modules/@babel/code-frame": {
-      "version": "7.21.4",
-      "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.21.4.tgz",
-      "integrity": "sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g==",
-      "peer": true,
+      "version": "7.22.5",
+      "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.5.tgz",
+      "integrity": "sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ==",
+      "dependencies": {
+        "@babel/highlight": "^7.22.5"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/compat-data": {
+      "version": "7.22.5",
+      "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.5.tgz",
+      "integrity": "sha512-4Jc/YuIaYqKnDDz892kPIledykKg12Aw1PYX5i/TY28anJtacvM1Rrr8wbieB9GfEJwlzqT0hUEao0CxEebiDA==",
+      "dev": true,
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/core": {
+      "version": "7.22.5",
+      "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.22.5.tgz",
+      "integrity": "sha512-SBuTAjg91A3eKOvD+bPEz3LlhHZRNu1nFOVts9lzDJTXshHTjII0BAtDS3Y2DAkdZdDKWVZGVwkDfc4Clxn1dg==",
+      "dev": true,
       "dependencies": {
-        "@babel/highlight": "^7.18.6"
+        "@ampproject/remapping": "^2.2.0",
+        "@babel/code-frame": "^7.22.5",
+        "@babel/generator": "^7.22.5",
+        "@babel/helper-compilation-targets": "^7.22.5",
+        "@babel/helper-module-transforms": "^7.22.5",
+        "@babel/helpers": "^7.22.5",
+        "@babel/parser": "^7.22.5",
+        "@babel/template": "^7.22.5",
+        "@babel/traverse": "^7.22.5",
+        "@babel/types": "^7.22.5",
+        "convert-source-map": "^1.7.0",
+        "debug": "^4.1.0",
+        "gensync": "^1.0.0-beta.2",
+        "json5": "^2.2.2",
+        "semver": "^6.3.0"
       },
       "engines": {
         "node": ">=6.9.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/babel"
+      }
+    },
+    "node_modules/@babel/core/node_modules/convert-source-map": {
+      "version": "1.9.0",
+      "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz",
+      "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==",
+      "dev": true
+    },
+    "node_modules/@babel/core/node_modules/semver": {
+      "version": "6.3.0",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+      "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+      "dev": true,
+      "bin": {
+        "semver": "bin/semver.js"
       }
     },
     "node_modules/@babel/generator": {
-      "version": "7.21.4",
-      "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.21.4.tgz",
-      "integrity": "sha512-NieM3pVIYW2SwGzKoqfPrQsf4xGs9M9AIG3ThppsSRmO+m7eQhmI6amajKMUeIO37wFfsvnvcxQFx6x6iqxDnA==",
-      "peer": true,
+      "version": "7.22.5",
+      "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.5.tgz",
+      "integrity": "sha512-+lcUbnTRhd0jOewtFSedLyiPsD5tswKkbgcezOqqWFUVNEwoUTlpPOBmvhG7OXWLR4jMdv0czPGH5XbflnD1EA==",
       "dependencies": {
-        "@babel/types": "^7.21.4",
+        "@babel/types": "^7.22.5",
         "@jridgewell/gen-mapping": "^0.3.2",
         "@jridgewell/trace-mapping": "^0.3.17",
         "jsesc": "^2.5.1"
@@ -104,89 +172,187 @@
         "node": ">=6.9.0"
       }
     },
+    "node_modules/@babel/helper-compilation-targets": {
+      "version": "7.22.5",
+      "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.5.tgz",
+      "integrity": "sha512-Ji+ywpHeuqxB8WDxraCiqR0xfhYjiDE/e6k7FuIaANnoOFxAHskHChz4vA1mJC9Lbm01s1PVAGhQY4FUKSkGZw==",
+      "dev": true,
+      "dependencies": {
+        "@babel/compat-data": "^7.22.5",
+        "@babel/helper-validator-option": "^7.22.5",
+        "browserslist": "^4.21.3",
+        "lru-cache": "^5.1.1",
+        "semver": "^6.3.0"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0"
+      }
+    },
+    "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": {
+      "version": "5.1.1",
+      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
+      "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
+      "dev": true,
+      "dependencies": {
+        "yallist": "^3.0.2"
+      }
+    },
+    "node_modules/@babel/helper-compilation-targets/node_modules/semver": {
+      "version": "6.3.0",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+      "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+      "dev": true,
+      "bin": {
+        "semver": "bin/semver.js"
+      }
+    },
+    "node_modules/@babel/helper-compilation-targets/node_modules/yallist": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
+      "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
+      "dev": true
+    },
     "node_modules/@babel/helper-environment-visitor": {
-      "version": "7.18.9",
-      "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz",
-      "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==",
-      "peer": true,
+      "version": "7.22.5",
+      "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz",
+      "integrity": "sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==",
       "engines": {
         "node": ">=6.9.0"
       }
     },
     "node_modules/@babel/helper-function-name": {
-      "version": "7.21.0",
-      "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.21.0.tgz",
-      "integrity": "sha512-HfK1aMRanKHpxemaY2gqBmL04iAPOPRj7DxtNbiDOrJK+gdwkiNRVpCpUJYbUT+aZyemKN8brqTOxzCaG6ExRg==",
-      "peer": true,
+      "version": "7.22.5",
+      "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz",
+      "integrity": "sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==",
       "dependencies": {
-        "@babel/template": "^7.20.7",
-        "@babel/types": "^7.21.0"
+        "@babel/template": "^7.22.5",
+        "@babel/types": "^7.22.5"
       },
       "engines": {
         "node": ">=6.9.0"
       }
     },
     "node_modules/@babel/helper-hoist-variables": {
-      "version": "7.18.6",
-      "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz",
-      "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==",
-      "peer": true,
+      "version": "7.22.5",
+      "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz",
+      "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==",
       "dependencies": {
-        "@babel/types": "^7.18.6"
+        "@babel/types": "^7.22.5"
       },
       "engines": {
         "node": ">=6.9.0"
       }
     },
     "node_modules/@babel/helper-module-imports": {
-      "version": "7.21.4",
-      "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.21.4.tgz",
-      "integrity": "sha512-orajc5T2PsRYUN3ZryCEFeMDYwyw09c/pZeaQEZPH0MpKzSvn3e0uXsDBu3k03VI+9DBiRo+l22BfKTpKwa/Wg==",
-      "peer": true,
+      "version": "7.22.5",
+      "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.5.tgz",
+      "integrity": "sha512-8Dl6+HD/cKifutF5qGd/8ZJi84QeAKh+CEe1sBzz8UayBBGg1dAIJrdHOcOM5b2MpzWL2yuotJTtGjETq0qjXg==",
+      "dependencies": {
+        "@babel/types": "^7.22.5"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-module-transforms": {
+      "version": "7.22.5",
+      "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.22.5.tgz",
+      "integrity": "sha512-+hGKDt/Ze8GFExiVHno/2dvG5IdstpzCq0y4Qc9OJ25D4q3pKfiIP/4Vp3/JvhDkLKsDK2api3q3fpIgiIF5bw==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-environment-visitor": "^7.22.5",
+        "@babel/helper-module-imports": "^7.22.5",
+        "@babel/helper-simple-access": "^7.22.5",
+        "@babel/helper-split-export-declaration": "^7.22.5",
+        "@babel/helper-validator-identifier": "^7.22.5",
+        "@babel/template": "^7.22.5",
+        "@babel/traverse": "^7.22.5",
+        "@babel/types": "^7.22.5"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-plugin-utils": {
+      "version": "7.22.5",
+      "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz",
+      "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==",
+      "dev": true,
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-simple-access": {
+      "version": "7.22.5",
+      "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz",
+      "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==",
+      "dev": true,
       "dependencies": {
-        "@babel/types": "^7.21.4"
+        "@babel/types": "^7.22.5"
       },
       "engines": {
         "node": ">=6.9.0"
       }
     },
     "node_modules/@babel/helper-split-export-declaration": {
-      "version": "7.18.6",
-      "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz",
-      "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==",
-      "peer": true,
+      "version": "7.22.5",
+      "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.5.tgz",
+      "integrity": "sha512-thqK5QFghPKWLhAV321lxF95yCg2K3Ob5yw+M3VHWfdia0IkPXUtoLH8x/6Fh486QUvzhb8YOWHChTVen2/PoQ==",
       "dependencies": {
-        "@babel/types": "^7.18.6"
+        "@babel/types": "^7.22.5"
       },
       "engines": {
         "node": ">=6.9.0"
       }
     },
     "node_modules/@babel/helper-string-parser": {
-      "version": "7.19.4",
-      "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz",
-      "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==",
-      "peer": true,
+      "version": "7.22.5",
+      "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz",
+      "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==",
       "engines": {
         "node": ">=6.9.0"
       }
     },
     "node_modules/@babel/helper-validator-identifier": {
-      "version": "7.19.1",
-      "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz",
-      "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==",
-      "peer": true,
+      "version": "7.22.5",
+      "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz",
+      "integrity": "sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==",
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-validator-option": {
+      "version": "7.22.5",
+      "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.5.tgz",
+      "integrity": "sha512-R3oB6xlIVKUnxNUxbmgq7pKjxpru24zlimpE8WK47fACIlM0II/Hm1RS8IaOI7NgCr6LNS+jl5l75m20npAziw==",
+      "dev": true,
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helpers": {
+      "version": "7.22.5",
+      "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.22.5.tgz",
+      "integrity": "sha512-pSXRmfE1vzcUIDFQcSGA5Mr+GxBV9oiRKDuDxXvWQQBCh8HoIjs/2DlDB7H8smac1IVrB9/xdXj2N3Wol9Cr+Q==",
+      "dev": true,
+      "dependencies": {
+        "@babel/template": "^7.22.5",
+        "@babel/traverse": "^7.22.5",
+        "@babel/types": "^7.22.5"
+      },
       "engines": {
         "node": ">=6.9.0"
       }
     },
     "node_modules/@babel/highlight": {
-      "version": "7.18.6",
-      "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz",
-      "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==",
-      "peer": true,
+      "version": "7.22.5",
+      "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.5.tgz",
+      "integrity": "sha512-BSKlD1hgnedS5XRnGOljZawtag7H1yPfQp0tdNJCHoH6AZ+Pcm9VvkrK59/Yy593Ypg0zMxH2BxD1VPYUQ7UIw==",
       "dependencies": {
-        "@babel/helper-validator-identifier": "^7.18.6",
+        "@babel/helper-validator-identifier": "^7.22.5",
         "chalk": "^2.0.0",
         "js-tokens": "^4.0.0"
       },
@@ -198,7 +364,6 @@
       "version": "3.2.1",
       "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
       "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
-      "peer": true,
       "dependencies": {
         "color-convert": "^1.9.0"
       },
@@ -210,7 +375,6 @@
       "version": "2.4.2",
       "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
       "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
-      "peer": true,
       "dependencies": {
         "ansi-styles": "^3.2.1",
         "escape-string-regexp": "^1.0.5",
@@ -224,7 +388,6 @@
       "version": "1.9.3",
       "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
       "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
-      "peer": true,
       "dependencies": {
         "color-name": "1.1.3"
       }
@@ -232,14 +395,12 @@
     "node_modules/@babel/highlight/node_modules/color-name": {
       "version": "1.1.3",
       "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
-      "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
-      "peer": true
+      "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="
     },
     "node_modules/@babel/highlight/node_modules/escape-string-regexp": {
       "version": "1.0.5",
       "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
       "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
-      "peer": true,
       "engines": {
         "node": ">=0.8.0"
       }
@@ -248,7 +409,6 @@
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
       "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
-      "peer": true,
       "engines": {
         "node": ">=4"
       }
@@ -257,7 +417,6 @@
       "version": "5.5.0",
       "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
       "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
-      "peer": true,
       "dependencies": {
         "has-flag": "^3.0.0"
       },
@@ -266,10 +425,9 @@
       }
     },
     "node_modules/@babel/parser": {
-      "version": "7.21.4",
-      "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.21.4.tgz",
-      "integrity": "sha512-alVJj7k7zIxqBZ7BTRhz0IqJFxW1VJbm6N8JbcYhQ186df9ZBPbZBmWSqAMXwHGsCJdYks7z/voa3ibiS5bCIw==",
-      "peer": true,
+      "version": "7.22.5",
+      "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.5.tgz",
+      "integrity": "sha512-DFZMC9LJUG9PLOclRC32G63UXwzqS2koQC8dkx+PLdmt1xSePYpbT/NbsrJy8Q/muXz7o/h/d4A7Fuyixm559Q==",
       "bin": {
         "parser": "bin/babel-parser.js"
       },
@@ -277,6 +435,183 @@
         "node": ">=6.0.0"
       }
     },
+    "node_modules/@babel/plugin-syntax-async-generators": {
+      "version": "7.8.4",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz",
+      "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.8.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-bigint": {
+      "version": "7.8.3",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz",
+      "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.8.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-class-properties": {
+      "version": "7.12.13",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz",
+      "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.12.13"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-import-meta": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz",
+      "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.10.4"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-json-strings": {
+      "version": "7.8.3",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz",
+      "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.8.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-jsx": {
+      "version": "7.22.5",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.22.5.tgz",
+      "integrity": "sha512-gvyP4hZrgrs/wWMaocvxZ44Hw0b3W8Pe+cMxc8V1ULQ07oh8VNbIRaoD1LRZVTvD+0nieDKjfgKg89sD7rrKrg==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.22.5"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-logical-assignment-operators": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz",
+      "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.10.4"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": {
+      "version": "7.8.3",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz",
+      "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.8.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-numeric-separator": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz",
+      "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.10.4"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-object-rest-spread": {
+      "version": "7.8.3",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz",
+      "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.8.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-optional-catch-binding": {
+      "version": "7.8.3",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz",
+      "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.8.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-optional-chaining": {
+      "version": "7.8.3",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz",
+      "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.8.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-top-level-await": {
+      "version": "7.14.5",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz",
+      "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.14.5"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-typescript": {
+      "version": "7.22.5",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.22.5.tgz",
+      "integrity": "sha512-1mS2o03i7t1c6VzH6fdQ3OA8tcEIxwG18zIPRp+UY1Ihv6W+XZzBCVxExF9upussPXJ0xE9XRHwMoNs1ep/nRQ==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.22.5"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
     "node_modules/@babel/runtime": {
       "version": "7.21.0",
       "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.21.0.tgz",
@@ -289,33 +624,31 @@
       }
     },
     "node_modules/@babel/template": {
-      "version": "7.20.7",
-      "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz",
-      "integrity": "sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==",
-      "peer": true,
+      "version": "7.22.5",
+      "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.5.tgz",
+      "integrity": "sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw==",
       "dependencies": {
-        "@babel/code-frame": "^7.18.6",
-        "@babel/parser": "^7.20.7",
-        "@babel/types": "^7.20.7"
+        "@babel/code-frame": "^7.22.5",
+        "@babel/parser": "^7.22.5",
+        "@babel/types": "^7.22.5"
       },
       "engines": {
         "node": ">=6.9.0"
       }
     },
     "node_modules/@babel/traverse": {
-      "version": "7.21.4",
-      "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.21.4.tgz",
-      "integrity": "sha512-eyKrRHKdyZxqDm+fV1iqL9UAHMoIg0nDaGqfIOd8rKH17m5snv7Gn4qgjBoFfLz9APvjFU/ICT00NVCv1Epp8Q==",
-      "peer": true,
-      "dependencies": {
-        "@babel/code-frame": "^7.21.4",
-        "@babel/generator": "^7.21.4",
-        "@babel/helper-environment-visitor": "^7.18.9",
-        "@babel/helper-function-name": "^7.21.0",
-        "@babel/helper-hoist-variables": "^7.18.6",
-        "@babel/helper-split-export-declaration": "^7.18.6",
-        "@babel/parser": "^7.21.4",
-        "@babel/types": "^7.21.4",
+      "version": "7.22.5",
+      "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.5.tgz",
+      "integrity": "sha512-7DuIjPgERaNo6r+PZwItpjCZEa5vyw4eJGufeLxrPdBXBoLcCJCIasvK6pK/9DVNrLZTLFhUGqaC6X/PA007TQ==",
+      "dependencies": {
+        "@babel/code-frame": "^7.22.5",
+        "@babel/generator": "^7.22.5",
+        "@babel/helper-environment-visitor": "^7.22.5",
+        "@babel/helper-function-name": "^7.22.5",
+        "@babel/helper-hoist-variables": "^7.22.5",
+        "@babel/helper-split-export-declaration": "^7.22.5",
+        "@babel/parser": "^7.22.5",
+        "@babel/types": "^7.22.5",
         "debug": "^4.1.0",
         "globals": "^11.1.0"
       },
@@ -327,19 +660,17 @@
       "version": "11.12.0",
       "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
       "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==",
-      "peer": true,
       "engines": {
         "node": ">=4"
       }
     },
     "node_modules/@babel/types": {
-      "version": "7.21.4",
-      "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.21.4.tgz",
-      "integrity": "sha512-rU2oY501qDxE8Pyo7i/Orqma4ziCOrby0/9mvbDUGEfvZjb279Nk9k19e2fiCxHbRRpY2ZyrgW1eq22mvmOIzA==",
-      "peer": true,
+      "version": "7.22.5",
+      "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.5.tgz",
+      "integrity": "sha512-zo3MIHGOkPOfoRXitsgHLjEXmlDaD/5KU1Uzuc9GNiZPhSqVxVRtxuPaSBZDsYZ9qV88AjtMtWW7ww98loJ9KA==",
       "dependencies": {
-        "@babel/helper-string-parser": "^7.19.4",
-        "@babel/helper-validator-identifier": "^7.19.1",
+        "@babel/helper-string-parser": "^7.22.5",
+        "@babel/helper-validator-identifier": "^7.22.5",
         "to-fast-properties": "^2.0.0"
       },
       "engines": {
@@ -364,6 +695,12 @@
         "url": "https://github.com/sponsors/philsturgeon"
       }
     },
+    "node_modules/@bcoe/v8-coverage": {
+      "version": "0.2.3",
+      "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz",
+      "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==",
+      "dev": true
+    },
     "node_modules/@electron/rebuild": {
       "version": "3.2.10",
       "resolved": "https://registry.npmjs.org/@electron/rebuild/-/rebuild-3.2.10.tgz",
@@ -866,2683 +1203,3832 @@
       "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==",
       "dev": true
     },
-    "node_modules/@jridgewell/gen-mapping": {
-      "version": "0.3.3",
-      "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz",
-      "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==",
+    "node_modules/@istanbuljs/load-nyc-config": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz",
+      "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==",
+      "dev": true,
       "dependencies": {
-        "@jridgewell/set-array": "^1.0.1",
-        "@jridgewell/sourcemap-codec": "^1.4.10",
-        "@jridgewell/trace-mapping": "^0.3.9"
+        "camelcase": "^5.3.1",
+        "find-up": "^4.1.0",
+        "get-package-type": "^0.1.0",
+        "js-yaml": "^3.13.1",
+        "resolve-from": "^5.0.0"
       },
       "engines": {
-        "node": ">=6.0.0"
+        "node": ">=8"
       }
     },
-    "node_modules/@jridgewell/resolve-uri": {
-      "version": "3.1.0",
-      "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz",
-      "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==",
-      "engines": {
-        "node": ">=6.0.0"
+    "node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": {
+      "version": "1.0.10",
+      "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
+      "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
+      "dev": true,
+      "dependencies": {
+        "sprintf-js": "~1.0.2"
       }
     },
-    "node_modules/@jridgewell/set-array": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz",
-      "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==",
+    "node_modules/@istanbuljs/load-nyc-config/node_modules/camelcase": {
+      "version": "5.3.1",
+      "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
+      "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
+      "dev": true,
       "engines": {
-        "node": ">=6.0.0"
+        "node": ">=6"
       }
     },
-    "node_modules/@jridgewell/sourcemap-codec": {
-      "version": "1.4.15",
-      "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
-      "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg=="
-    },
-    "node_modules/@jridgewell/trace-mapping": {
-      "version": "0.3.18",
-      "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz",
-      "integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==",
+    "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
+      "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+      "dev": true,
       "dependencies": {
-        "@jridgewell/resolve-uri": "3.1.0",
-        "@jridgewell/sourcemap-codec": "1.4.14"
-      }
-    },
-    "node_modules/@jridgewell/trace-mapping/node_modules/@jridgewell/sourcemap-codec": {
-      "version": "1.4.14",
-      "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz",
-      "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw=="
-    },
-    "node_modules/@jsdevtools/ono": {
-      "version": "7.1.3",
-      "resolved": "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz",
-      "integrity": "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==",
-      "dev": true
-    },
-    "node_modules/@lukeed/csprng": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/@lukeed/csprng/-/csprng-1.0.1.tgz",
-      "integrity": "sha512-uSvJdwQU5nK+Vdf6zxcWAY2A8r7uqe+gePwLWzJ+fsQehq18pc0I2hJKwypZ2aLM90+Er9u1xn4iLJPZ+xlL4g==",
+        "locate-path": "^5.0.0",
+        "path-exists": "^4.0.0"
+      },
       "engines": {
         "node": ">=8"
       }
     },
-    "node_modules/@lukeed/uuid": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/@lukeed/uuid/-/uuid-2.0.0.tgz",
-      "integrity": "sha512-dUz8OmYvlY5A9wXaroHIMSPASpSYRLCqbPvxGSyHguhtTQIy24lC+EGxQlwv71AhRCO55WOtgwhzQLpw27JaJQ==",
+    "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": {
+      "version": "3.14.1",
+      "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
+      "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
+      "dev": true,
       "dependencies": {
-        "@lukeed/csprng": "^1.0.0"
+        "argparse": "^1.0.7",
+        "esprima": "^4.0.0"
+      },
+      "bin": {
+        "js-yaml": "bin/js-yaml.js"
+      }
+    },
+    "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
+      "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+      "dev": true,
+      "dependencies": {
+        "p-locate": "^4.1.0"
       },
       "engines": {
         "node": ">=8"
       }
     },
-    "node_modules/@malept/cross-spawn-promise": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/@malept/cross-spawn-promise/-/cross-spawn-promise-2.0.0.tgz",
-      "integrity": "sha512-1DpKU0Z5ThltBwjNySMC14g0CkbyhCaz9FkhxqNsZI6uAPJXFS8cMXlBKo26FJ8ZuW6S9GCMcR9IO5k2X5/9Fg==",
-      "funding": [
-        {
-          "type": "individual",
-          "url": "https://github.com/sponsors/malept"
-        },
-        {
-          "type": "tidelift",
-          "url": "https://tidelift.com/subscription/pkg/npm-.malept-cross-spawn-promise?utm_medium=referral&utm_source=npm_fund"
-        }
-      ],
+    "node_modules/@istanbuljs/load-nyc-config/node_modules/p-limit": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+      "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+      "dev": true,
       "dependencies": {
-        "cross-spawn": "^7.0.1"
+        "p-try": "^2.0.0"
       },
       "engines": {
-        "node": ">= 12.13.0"
+        "node": ">=6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
       }
     },
-    "node_modules/@nestjs/axios": {
-      "version": "0.0.8",
-      "resolved": "https://registry.npmjs.org/@nestjs/axios/-/axios-0.0.8.tgz",
-      "integrity": "sha512-oJyfR9/h9tVk776il0829xyj3b2e81yTu6HjPraxynwNtMNGqZBHHmAQL24yMB3tVbBM0RvG3eUXH8+pRCGwlg==",
+    "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
+      "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
       "dev": true,
       "dependencies": {
-        "axios": "0.27.2"
+        "p-limit": "^2.2.0"
       },
-      "peerDependencies": {
-        "@nestjs/common": "^7.0.0 || ^8.0.0",
-        "reflect-metadata": "^0.1.12",
-        "rxjs": "^6.0.0 || ^7.0.0"
+      "engines": {
+        "node": ">=8"
       }
     },
-    "node_modules/@nestjs/axios/node_modules/axios": {
-      "version": "0.27.2",
-      "resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz",
-      "integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==",
+    "node_modules/@istanbuljs/load-nyc-config/node_modules/resolve-from": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
+      "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@istanbuljs/schema": {
+      "version": "0.1.3",
+      "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz",
+      "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@jest/console": {
+      "version": "29.5.0",
+      "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.5.0.tgz",
+      "integrity": "sha512-NEpkObxPwyw/XxZVLPmAGKE89IQRp4puc6IQRPru6JKd1M3fW9v1xM1AnzIJE65hbCkzQAdnL8P47e9hzhiYLQ==",
       "dev": true,
       "dependencies": {
-        "follow-redirects": "^1.14.9",
-        "form-data": "^4.0.0"
+        "@jest/types": "^29.5.0",
+        "@types/node": "*",
+        "chalk": "^4.0.0",
+        "jest-message-util": "^29.5.0",
+        "jest-util": "^29.5.0",
+        "slash": "^3.0.0"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
       }
     },
-    "node_modules/@nestjs/common": {
-      "version": "8.4.7",
-      "resolved": "https://registry.npmjs.org/@nestjs/common/-/common-8.4.7.tgz",
-      "integrity": "sha512-m/YsbcBal+gA5CFrDpqXqsSfylo+DIQrkFY3qhVIltsYRfu8ct8J9pqsTO6OPf3mvqdOpFGrV5sBjoyAzOBvsw==",
+    "node_modules/@jest/core": {
+      "version": "29.5.0",
+      "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.5.0.tgz",
+      "integrity": "sha512-28UzQc7ulUrOQw1IsN/kv1QES3q2kkbl/wGslyhAclqZ/8cMdB5M68BffkIdSJgKBUt50d3hbwJ92XESlE7LiQ==",
+      "dev": true,
       "dependencies": {
-        "axios": "0.27.2",
-        "iterare": "1.2.1",
-        "tslib": "2.4.0",
-        "uuid": "8.3.2"
+        "@jest/console": "^29.5.0",
+        "@jest/reporters": "^29.5.0",
+        "@jest/test-result": "^29.5.0",
+        "@jest/transform": "^29.5.0",
+        "@jest/types": "^29.5.0",
+        "@types/node": "*",
+        "ansi-escapes": "^4.2.1",
+        "chalk": "^4.0.0",
+        "ci-info": "^3.2.0",
+        "exit": "^0.1.2",
+        "graceful-fs": "^4.2.9",
+        "jest-changed-files": "^29.5.0",
+        "jest-config": "^29.5.0",
+        "jest-haste-map": "^29.5.0",
+        "jest-message-util": "^29.5.0",
+        "jest-regex-util": "^29.4.3",
+        "jest-resolve": "^29.5.0",
+        "jest-resolve-dependencies": "^29.5.0",
+        "jest-runner": "^29.5.0",
+        "jest-runtime": "^29.5.0",
+        "jest-snapshot": "^29.5.0",
+        "jest-util": "^29.5.0",
+        "jest-validate": "^29.5.0",
+        "jest-watcher": "^29.5.0",
+        "micromatch": "^4.0.4",
+        "pretty-format": "^29.5.0",
+        "slash": "^3.0.0",
+        "strip-ansi": "^6.0.0"
       },
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/nest"
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
       },
       "peerDependencies": {
-        "cache-manager": "*",
-        "class-transformer": "*",
-        "class-validator": "*",
-        "reflect-metadata": "^0.1.12",
-        "rxjs": "^7.1.0"
+        "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0"
       },
       "peerDependenciesMeta": {
-        "cache-manager": {
-          "optional": true
-        },
-        "class-transformer": {
-          "optional": true
-        },
-        "class-validator": {
+        "node-notifier": {
           "optional": true
         }
       }
     },
-    "node_modules/@nestjs/common/node_modules/axios": {
-      "version": "0.27.2",
-      "resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz",
-      "integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==",
-      "dependencies": {
-        "follow-redirects": "^1.14.9",
-        "form-data": "^4.0.0"
+    "node_modules/@jest/core/node_modules/ansi-regex": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+      "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
       }
     },
-    "node_modules/@nestjs/common/node_modules/tslib": {
-      "version": "2.4.0",
-      "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
-      "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ=="
-    },
-    "node_modules/@nodelib/fs.scandir": {
-      "version": "2.1.5",
-      "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
-      "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
+    "node_modules/@jest/core/node_modules/strip-ansi": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+      "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+      "dev": true,
       "dependencies": {
-        "@nodelib/fs.stat": "2.0.5",
-        "run-parallel": "^1.1.9"
+        "ansi-regex": "^5.0.1"
       },
       "engines": {
-        "node": ">= 8"
+        "node": ">=8"
       }
     },
-    "node_modules/@nodelib/fs.stat": {
-      "version": "2.0.5",
-      "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
-      "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
+    "node_modules/@jest/environment": {
+      "version": "29.5.0",
+      "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.5.0.tgz",
+      "integrity": "sha512-5FXw2+wD29YU1d4I2htpRX7jYnAyTRjP2CsXQdo9SAM8g3ifxWPSV0HnClSn71xwctr0U3oZIIH+dtbfmnbXVQ==",
+      "dev": true,
+      "dependencies": {
+        "@jest/fake-timers": "^29.5.0",
+        "@jest/types": "^29.5.0",
+        "@types/node": "*",
+        "jest-mock": "^29.5.0"
+      },
       "engines": {
-        "node": ">= 8"
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
       }
     },
-    "node_modules/@nodelib/fs.walk": {
-      "version": "1.2.8",
-      "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
-      "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
+    "node_modules/@jest/expect": {
+      "version": "29.5.0",
+      "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.5.0.tgz",
+      "integrity": "sha512-PueDR2HGihN3ciUNGr4uelropW7rqUfTiOn+8u0leg/42UhblPxHkfoh0Ruu3I9Y1962P3u2DY4+h7GVTSVU6g==",
+      "dev": true,
       "dependencies": {
-        "@nodelib/fs.scandir": "2.1.5",
-        "fastq": "^1.6.0"
+        "expect": "^29.5.0",
+        "jest-snapshot": "^29.5.0"
       },
       "engines": {
-        "node": ">= 8"
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
       }
     },
-    "node_modules/@npmcli/fs": {
-      "version": "2.1.2",
-      "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-2.1.2.tgz",
-      "integrity": "sha512-yOJKRvohFOaLqipNtwYB9WugyZKhC/DZC4VYPmpaCzDBrA8YpK3qHZ8/HGscMnE4GqbkLNuVcCnxkeQEdGt6LQ==",
+    "node_modules/@jest/expect-utils": {
+      "version": "29.5.0",
+      "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.5.0.tgz",
+      "integrity": "sha512-fmKzsidoXQT2KwnrwE0SQq3uj8Z763vzR8LnLBwC2qYWEFpjX8daRsk6rHUM1QvNlEW/UJXNXm59ztmJJWs2Mg==",
+      "dev": true,
       "dependencies": {
-        "@gar/promisify": "^1.1.3",
-        "semver": "^7.3.5"
+        "jest-get-type": "^29.4.3"
       },
       "engines": {
-        "node": "^12.13.0 || ^14.15.0 || >=16.0.0"
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
       }
     },
-    "node_modules/@npmcli/move-file": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-2.0.1.tgz",
-      "integrity": "sha512-mJd2Z5TjYWq/ttPLLGqArdtnC74J6bOzg4rMDnN+p1xTacZ2yPRCk2y0oSWQtygLR9YVQXgOcONrwtnk3JupxQ==",
-      "deprecated": "This functionality has been moved to @npmcli/fs",
+    "node_modules/@jest/fake-timers": {
+      "version": "29.5.0",
+      "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.5.0.tgz",
+      "integrity": "sha512-9ARvuAAQcBwDAqOnglWq2zwNIRUDtk/SCkp/ToGEhFv5r86K21l+VEs0qNTaXtyiY0lEePl3kylijSYJQqdbDg==",
+      "dev": true,
       "dependencies": {
-        "mkdirp": "^1.0.4",
-        "rimraf": "^3.0.2"
+        "@jest/types": "^29.5.0",
+        "@sinonjs/fake-timers": "^10.0.2",
+        "@types/node": "*",
+        "jest-message-util": "^29.5.0",
+        "jest-mock": "^29.5.0",
+        "jest-util": "^29.5.0"
       },
       "engines": {
-        "node": "^12.13.0 || ^14.15.0 || >=16.0.0"
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
       }
     },
-    "node_modules/@npmcli/move-file/node_modules/mkdirp": {
-      "version": "1.0.4",
-      "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
-      "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
-      "bin": {
-        "mkdirp": "bin/cmd.js"
+    "node_modules/@jest/globals": {
+      "version": "29.5.0",
+      "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.5.0.tgz",
+      "integrity": "sha512-S02y0qMWGihdzNbUiqSAiKSpSozSuHX5UYc7QbnHP+D9Lyw8DgGGCinrN9uSuHPeKgSSzvPom2q1nAtBvUsvPQ==",
+      "dev": true,
+      "dependencies": {
+        "@jest/environment": "^29.5.0",
+        "@jest/expect": "^29.5.0",
+        "@jest/types": "^29.5.0",
+        "jest-mock": "^29.5.0"
       },
       "engines": {
-        "node": ">=10"
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
       }
     },
-    "node_modules/@nuxtjs/opencollective": {
-      "version": "0.3.2",
-      "resolved": "https://registry.npmjs.org/@nuxtjs/opencollective/-/opencollective-0.3.2.tgz",
-      "integrity": "sha512-um0xL3fO7Mf4fDxcqx9KryrB7zgRM5JSlvGN5AGkP6JLM5XEKyjeAiPbNxdXVXQ16isuAhYpvP88NgL2BGd6aA==",
+    "node_modules/@jest/reporters": {
+      "version": "29.5.0",
+      "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.5.0.tgz",
+      "integrity": "sha512-D05STXqj/M8bP9hQNSICtPqz97u7ffGzZu+9XLucXhkOFBqKcXe04JLZOgIekOxdb73MAoBUFnqvf7MCpKk5OA==",
       "dev": true,
       "dependencies": {
-        "chalk": "^4.1.0",
-        "consola": "^2.15.0",
-        "node-fetch": "^2.6.1"
+        "@bcoe/v8-coverage": "^0.2.3",
+        "@jest/console": "^29.5.0",
+        "@jest/test-result": "^29.5.0",
+        "@jest/transform": "^29.5.0",
+        "@jest/types": "^29.5.0",
+        "@jridgewell/trace-mapping": "^0.3.15",
+        "@types/node": "*",
+        "chalk": "^4.0.0",
+        "collect-v8-coverage": "^1.0.0",
+        "exit": "^0.1.2",
+        "glob": "^7.1.3",
+        "graceful-fs": "^4.2.9",
+        "istanbul-lib-coverage": "^3.0.0",
+        "istanbul-lib-instrument": "^5.1.0",
+        "istanbul-lib-report": "^3.0.0",
+        "istanbul-lib-source-maps": "^4.0.0",
+        "istanbul-reports": "^3.1.3",
+        "jest-message-util": "^29.5.0",
+        "jest-util": "^29.5.0",
+        "jest-worker": "^29.5.0",
+        "slash": "^3.0.0",
+        "string-length": "^4.0.1",
+        "strip-ansi": "^6.0.0",
+        "v8-to-istanbul": "^9.0.1"
       },
-      "bin": {
-        "opencollective": "bin/opencollective.js"
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
       },
+      "peerDependencies": {
+        "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0"
+      },
+      "peerDependenciesMeta": {
+        "node-notifier": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@jest/reporters/node_modules/ansi-regex": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+      "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+      "dev": true,
       "engines": {
-        "node": ">=8.0.0",
-        "npm": ">=5.0.0"
+        "node": ">=8"
       }
     },
-    "node_modules/@openapitools/openapi-generator-cli": {
-      "version": "2.6.0",
-      "resolved": "https://registry.npmjs.org/@openapitools/openapi-generator-cli/-/openapi-generator-cli-2.6.0.tgz",
-      "integrity": "sha512-M/aOpR7G+Y1nMf+ofuar8pGszajgfhs1aSPSijkcr2tHTxKAI3sA3YYcOGbszxaNRKFyvOcDq+KP9pcJvKoCHg==",
+    "node_modules/@jest/reporters/node_modules/glob": {
+      "version": "7.2.3",
+      "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+      "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
       "dev": true,
-      "hasInstallScript": true,
       "dependencies": {
-        "@nestjs/axios": "0.0.8",
-        "@nestjs/common": "9.3.11",
-        "@nestjs/core": "9.3.11",
-        "@nuxtjs/opencollective": "0.3.2",
-        "chalk": "4.1.2",
-        "commander": "8.3.0",
-        "compare-versions": "4.1.4",
-        "concurrently": "6.5.1",
-        "console.table": "0.10.0",
-        "fs-extra": "10.1.0",
-        "glob": "7.1.6",
-        "inquirer": "8.2.5",
-        "lodash": "4.17.21",
-        "reflect-metadata": "0.1.13",
-        "rxjs": "7.8.0",
-        "tslib": "2.0.3"
-      },
-      "bin": {
-        "openapi-generator-cli": "main.js"
+        "fs.realpath": "^1.0.0",
+        "inflight": "^1.0.4",
+        "inherits": "2",
+        "minimatch": "^3.1.1",
+        "once": "^1.3.0",
+        "path-is-absolute": "^1.0.0"
       },
       "engines": {
-        "node": ">=10.0.0"
+        "node": "*"
       },
       "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/openapi_generator"
+        "url": "https://github.com/sponsors/isaacs"
       }
     },
-    "node_modules/@openapitools/openapi-generator-cli/node_modules/@nestjs/common": {
-      "version": "9.3.11",
-      "resolved": "https://registry.npmjs.org/@nestjs/common/-/common-9.3.11.tgz",
-      "integrity": "sha512-IFZ2G/5UKWC2Uo7tJ4SxGed2+aiA+sJyWeWsGTogKVDhq90oxVBToh+uCDeI31HNUpqYGoWmkletfty42zUd8A==",
+    "node_modules/@jest/reporters/node_modules/strip-ansi": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+      "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
       "dev": true,
       "dependencies": {
-        "iterare": "1.2.1",
-        "tslib": "2.5.0",
-        "uid": "2.0.1"
-      },
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/nest"
-      },
-      "peerDependencies": {
-        "cache-manager": "<=5",
-        "class-transformer": "*",
-        "class-validator": "*",
-        "reflect-metadata": "^0.1.12",
-        "rxjs": "^7.1.0"
+        "ansi-regex": "^5.0.1"
       },
-      "peerDependenciesMeta": {
-        "cache-manager": {
-          "optional": true
-        },
-        "class-transformer": {
-          "optional": true
-        },
-        "class-validator": {
-          "optional": true
-        }
+      "engines": {
+        "node": ">=8"
       }
     },
-    "node_modules/@openapitools/openapi-generator-cli/node_modules/@nestjs/common/node_modules/tslib": {
-      "version": "2.5.0",
-      "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz",
-      "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==",
-      "dev": true
-    },
-    "node_modules/@openapitools/openapi-generator-cli/node_modules/@nestjs/core": {
-      "version": "9.3.11",
-      "resolved": "https://registry.npmjs.org/@nestjs/core/-/core-9.3.11.tgz",
-      "integrity": "sha512-CI27a2JFd5rvvbgkalWqsiwQNhcP4EAG5BUK8usjp29wVp1kx30ghfBT8FLqIgmkRVo65A0IcEnWsxeXMntkxQ==",
+    "node_modules/@jest/schemas": {
+      "version": "29.4.3",
+      "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.4.3.tgz",
+      "integrity": "sha512-VLYKXQmtmuEz6IxJsrZwzG9NvtkQsWNnWMsKxqWNu3+CnfzJQhp0WDDKWLVV9hLKr0l3SLLFRqcYHjhtyuDVxg==",
       "dev": true,
-      "hasInstallScript": true,
       "dependencies": {
-        "@nuxtjs/opencollective": "0.3.2",
-        "fast-safe-stringify": "2.1.1",
-        "iterare": "1.2.1",
-        "path-to-regexp": "3.2.0",
-        "tslib": "2.5.0",
-        "uid": "2.0.1"
-      },
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/nest"
-      },
-      "peerDependencies": {
-        "@nestjs/common": "^9.0.0",
-        "@nestjs/microservices": "^9.0.0",
-        "@nestjs/platform-express": "^9.0.0",
-        "@nestjs/websockets": "^9.0.0",
-        "reflect-metadata": "^0.1.12",
-        "rxjs": "^7.1.0"
+        "@sinclair/typebox": "^0.25.16"
       },
-      "peerDependenciesMeta": {
-        "@nestjs/microservices": {
-          "optional": true
-        },
-        "@nestjs/platform-express": {
-          "optional": true
-        },
-        "@nestjs/websockets": {
-          "optional": true
-        }
-      }
-    },
-    "node_modules/@openapitools/openapi-generator-cli/node_modules/@nestjs/core/node_modules/tslib": {
-      "version": "2.5.0",
-      "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz",
-      "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==",
-      "dev": true
-    },
-    "node_modules/@openapitools/openapi-generator-cli/node_modules/commander": {
-      "version": "8.3.0",
-      "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz",
-      "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==",
-      "dev": true,
       "engines": {
-        "node": ">= 12"
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
       }
     },
-    "node_modules/@openapitools/openapi-generator-cli/node_modules/glob": {
-      "version": "7.1.6",
-      "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
-      "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
+    "node_modules/@jest/source-map": {
+      "version": "29.4.3",
+      "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.4.3.tgz",
+      "integrity": "sha512-qyt/mb6rLyd9j1jUts4EQncvS6Yy3PM9HghnNv86QBlV+zdL2inCdK1tuVlL+J+lpiw2BI67qXOrX3UurBqQ1w==",
       "dev": true,
       "dependencies": {
-        "fs.realpath": "^1.0.0",
-        "inflight": "^1.0.4",
-        "inherits": "2",
-        "minimatch": "^3.0.4",
-        "once": "^1.3.0",
-        "path-is-absolute": "^1.0.0"
+        "@jridgewell/trace-mapping": "^0.3.15",
+        "callsites": "^3.0.0",
+        "graceful-fs": "^4.2.9"
       },
       "engines": {
-        "node": "*"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/isaacs"
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
       }
     },
-    "node_modules/@openapitools/openapi-generator-cli/node_modules/tslib": {
-      "version": "2.0.3",
-      "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.3.tgz",
-      "integrity": "sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ==",
-      "dev": true
-    },
-    "node_modules/@reduxjs/toolkit": {
-      "version": "1.9.3",
-      "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-1.9.3.tgz",
-      "integrity": "sha512-GU2TNBQVofL09VGmuSioNPQIu6Ml0YLf4EJhgj0AvBadRlCGzUWet8372LjvO4fqKZF2vH1xU0htAa7BrK9pZg==",
+    "node_modules/@jest/test-result": {
+      "version": "29.5.0",
+      "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.5.0.tgz",
+      "integrity": "sha512-fGl4rfitnbfLsrfx1uUpDEESS7zM8JdgZgOCQuxQvL1Sn/I6ijeAVQWGfXI9zb1i9Mzo495cIpVZhA0yr60PkQ==",
+      "dev": true,
       "dependencies": {
-        "immer": "^9.0.16",
-        "redux": "^4.2.0",
-        "redux-thunk": "^2.4.2",
-        "reselect": "^4.1.7"
-      },
-      "peerDependencies": {
-        "react": "^16.9.0 || ^17.0.0 || ^18",
-        "react-redux": "^7.2.1 || ^8.0.2"
+        "@jest/console": "^29.5.0",
+        "@jest/types": "^29.5.0",
+        "@types/istanbul-lib-coverage": "^2.0.0",
+        "collect-v8-coverage": "^1.0.0"
       },
-      "peerDependenciesMeta": {
-        "react": {
-          "optional": true
-        },
-        "react-redux": {
-          "optional": true
-        }
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
       }
     },
-    "node_modules/@segment/analytics-core": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/@segment/analytics-core/-/analytics-core-1.2.0.tgz",
-      "integrity": "sha512-2BSliLJi1RWq8+eE+UKcMEiC5WfZZp3SHIA/fGhFftOg2s1OkFaQRHuKFzdgbDuKZMEsRwqek3EITNGSThJ5rg==",
+    "node_modules/@jest/test-sequencer": {
+      "version": "29.5.0",
+      "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.5.0.tgz",
+      "integrity": "sha512-yPafQEcKjkSfDXyvtgiV4pevSeyuA6MQr6ZIdVkWJly9vkqjnFfcfhRQqpD5whjoU8EORki752xQmjaqoFjzMQ==",
+      "dev": true,
       "dependencies": {
-        "@lukeed/uuid": "^2.0.0",
-        "dset": "^3.1.2",
-        "tslib": "^2.4.1"
+        "@jest/test-result": "^29.5.0",
+        "graceful-fs": "^4.2.9",
+        "jest-haste-map": "^29.5.0",
+        "slash": "^3.0.0"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
       }
     },
-    "node_modules/@segment/analytics-core/node_modules/tslib": {
-      "version": "2.5.0",
-      "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz",
-      "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg=="
-    },
-    "node_modules/@segment/analytics-node": {
-      "version": "0.0.1-beta.16",
-      "resolved": "https://registry.npmjs.org/@segment/analytics-node/-/analytics-node-0.0.1-beta.16.tgz",
-      "integrity": "sha512-WYKvLQ1xyDNOzxZ9+ltF/ROB6MhsFeKaNlVAam3FKVczMg+gNa2KKvfOUA3wXxIhvDvWaZY7e7MWEXxxukl4+g==",
+    "node_modules/@jest/transform": {
+      "version": "29.5.0",
+      "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.5.0.tgz",
+      "integrity": "sha512-8vbeZWqLJOvHaDfeMuoHITGKSz5qWc9u04lnWrQE3VyuSw604PzQM824ZeX9XSjUCeDiE3GuxZe5UKa8J61NQw==",
+      "dev": true,
       "dependencies": {
-        "@lukeed/uuid": "^2.0.0",
-        "@segment/analytics-core": "1.2.0",
-        "node-fetch": "^2.6.7",
-        "tslib": "^2.4.1"
+        "@babel/core": "^7.11.6",
+        "@jest/types": "^29.5.0",
+        "@jridgewell/trace-mapping": "^0.3.15",
+        "babel-plugin-istanbul": "^6.1.1",
+        "chalk": "^4.0.0",
+        "convert-source-map": "^2.0.0",
+        "fast-json-stable-stringify": "^2.1.0",
+        "graceful-fs": "^4.2.9",
+        "jest-haste-map": "^29.5.0",
+        "jest-regex-util": "^29.4.3",
+        "jest-util": "^29.5.0",
+        "micromatch": "^4.0.4",
+        "pirates": "^4.0.4",
+        "slash": "^3.0.0",
+        "write-file-atomic": "^4.0.2"
       },
       "engines": {
-        "node": ">=14"
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
       }
     },
-    "node_modules/@segment/analytics-node/node_modules/tslib": {
-      "version": "2.5.0",
-      "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz",
-      "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg=="
-    },
-    "node_modules/@sentry-internal/tracing": {
-      "version": "7.57.0",
-      "resolved": "https://registry.npmjs.org/@sentry-internal/tracing/-/tracing-7.57.0.tgz",
-      "integrity": "sha512-tpViyDd8AhQGYYhI94xi2aaDopXOPfL2Apwrtb3qirWkomIQ2K86W1mPmkce+B0cFOnW2Dxv/ZTFKz6ghjK75A==",
+    "node_modules/@jest/types": {
+      "version": "29.5.0",
+      "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz",
+      "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==",
+      "dev": true,
       "dependencies": {
-        "@sentry/core": "7.57.0",
-        "@sentry/types": "7.57.0",
-        "@sentry/utils": "7.57.0",
-        "tslib": "^2.4.1 || ^1.9.3"
+        "@jest/schemas": "^29.4.3",
+        "@types/istanbul-lib-coverage": "^2.0.0",
+        "@types/istanbul-reports": "^3.0.0",
+        "@types/node": "*",
+        "@types/yargs": "^17.0.8",
+        "chalk": "^4.0.0"
       },
       "engines": {
-        "node": ">=8"
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
       }
     },
-    "node_modules/@sentry/core": {
-      "version": "7.57.0",
-      "resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.57.0.tgz",
-      "integrity": "sha512-l014NudPH0vQlzybtXajPxYFfs9w762NoarjObC3gu76D1jzBBFzhdRelkGpDbSLNTIsKhEDDRpgAjBWJ9icfw==",
+    "node_modules/@jridgewell/gen-mapping": {
+      "version": "0.3.3",
+      "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz",
+      "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==",
       "dependencies": {
-        "@sentry/types": "7.57.0",
-        "@sentry/utils": "7.57.0",
-        "tslib": "^2.4.1 || ^1.9.3"
+        "@jridgewell/set-array": "^1.0.1",
+        "@jridgewell/sourcemap-codec": "^1.4.10",
+        "@jridgewell/trace-mapping": "^0.3.9"
       },
       "engines": {
-        "node": ">=8"
+        "node": ">=6.0.0"
       }
     },
-    "node_modules/@sentry/node": {
-      "version": "7.57.0",
-      "resolved": "https://registry.npmjs.org/@sentry/node/-/node-7.57.0.tgz",
-      "integrity": "sha512-63mjyUVM6sfJFVQ5TGVRVGUsoEfESl5ABzIW1W0s9gUiQPaG8SOdaQJglb2VNrkMYxnRHgD8Q9LUh/qcmUyPGw==",
-      "dependencies": {
-        "@sentry-internal/tracing": "7.57.0",
-        "@sentry/core": "7.57.0",
-        "@sentry/types": "7.57.0",
-        "@sentry/utils": "7.57.0",
-        "cookie": "^0.4.1",
-        "https-proxy-agent": "^5.0.0",
-        "lru_map": "^0.3.3",
-        "tslib": "^2.4.1 || ^1.9.3"
-      },
+    "node_modules/@jridgewell/resolve-uri": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz",
+      "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==",
       "engines": {
-        "node": ">=8"
+        "node": ">=6.0.0"
       }
     },
-    "node_modules/@sentry/types": {
-      "version": "7.57.0",
-      "resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.57.0.tgz",
-      "integrity": "sha512-D7ifoUfxuVCUyktIr5Gc+jXUbtcUMmfHdTtTbf1XCZHua5mJceK9wtl3YCg3eq/HK2Ppd52BKnTzEcS5ZKQM+w==",
+    "node_modules/@jridgewell/set-array": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz",
+      "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==",
       "engines": {
-        "node": ">=8"
+        "node": ">=6.0.0"
       }
     },
-    "node_modules/@sentry/utils": {
-      "version": "7.57.0",
-      "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.57.0.tgz",
-      "integrity": "sha512-YXrkMCiNklqkXctn4mKYkrzNCf/dfVcRUQrkXjeBC+PHXbcpPyaJgInNvztR7Skl8lE3JPGPN4v5XhLxK1bUUg==",
+    "node_modules/@jridgewell/sourcemap-codec": {
+      "version": "1.4.15",
+      "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
+      "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg=="
+    },
+    "node_modules/@jridgewell/trace-mapping": {
+      "version": "0.3.18",
+      "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz",
+      "integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==",
       "dependencies": {
-        "@sentry/types": "7.57.0",
-        "tslib": "^2.4.1 || ^1.9.3"
-      },
+        "@jridgewell/resolve-uri": "3.1.0",
+        "@jridgewell/sourcemap-codec": "1.4.14"
+      }
+    },
+    "node_modules/@jridgewell/trace-mapping/node_modules/@jridgewell/sourcemap-codec": {
+      "version": "1.4.14",
+      "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz",
+      "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw=="
+    },
+    "node_modules/@jsdevtools/ono": {
+      "version": "7.1.3",
+      "resolved": "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz",
+      "integrity": "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==",
+      "dev": true
+    },
+    "node_modules/@lukeed/csprng": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/@lukeed/csprng/-/csprng-1.0.1.tgz",
+      "integrity": "sha512-uSvJdwQU5nK+Vdf6zxcWAY2A8r7uqe+gePwLWzJ+fsQehq18pc0I2hJKwypZ2aLM90+Er9u1xn4iLJPZ+xlL4g==",
       "engines": {
         "node": ">=8"
       }
     },
-    "node_modules/@sindresorhus/is": {
-      "version": "4.6.0",
-      "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz",
-      "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==",
-      "engines": {
-        "node": ">=10"
+    "node_modules/@lukeed/uuid": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/@lukeed/uuid/-/uuid-2.0.0.tgz",
+      "integrity": "sha512-dUz8OmYvlY5A9wXaroHIMSPASpSYRLCqbPvxGSyHguhtTQIy24lC+EGxQlwv71AhRCO55WOtgwhzQLpw27JaJQ==",
+      "dependencies": {
+        "@lukeed/csprng": "^1.0.0"
       },
-      "funding": {
-        "url": "https://github.com/sindresorhus/is?sponsor=1"
+      "engines": {
+        "node": ">=8"
       }
     },
-    "node_modules/@styled-icons/heroicons-outline": {
-      "version": "10.47.0",
-      "resolved": "https://registry.npmjs.org/@styled-icons/heroicons-outline/-/heroicons-outline-10.47.0.tgz",
-      "integrity": "sha512-C7bcJ/YPVKACoQLSBDM9DkgmrO1HmqAaru9kqYK2V+GaGUW5raf6dyTLo7GUYt/CJ7p3qWxsBz3SX6djzdaODQ==",
+    "node_modules/@malept/cross-spawn-promise": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/@malept/cross-spawn-promise/-/cross-spawn-promise-2.0.0.tgz",
+      "integrity": "sha512-1DpKU0Z5ThltBwjNySMC14g0CkbyhCaz9FkhxqNsZI6uAPJXFS8cMXlBKo26FJ8ZuW6S9GCMcR9IO5k2X5/9Fg==",
+      "funding": [
+        {
+          "type": "individual",
+          "url": "https://github.com/sponsors/malept"
+        },
+        {
+          "type": "tidelift",
+          "url": "https://tidelift.com/subscription/pkg/npm-.malept-cross-spawn-promise?utm_medium=referral&utm_source=npm_fund"
+        }
+      ],
       "dependencies": {
-        "@babel/runtime": "^7.20.7",
-        "@styled-icons/styled-icon": "^10.7.0"
-      },
-      "funding": {
-        "type": "GitHub",
-        "url": "https://github.com/sponsors/jacobwgillespie"
+        "cross-spawn": "^7.0.1"
       },
-      "peerDependencies": {
-        "react": "*",
-        "styled-components": "*"
+      "engines": {
+        "node": ">= 12.13.0"
       }
     },
-    "node_modules/@styled-icons/styled-icon": {
-      "version": "10.7.0",
-      "resolved": "https://registry.npmjs.org/@styled-icons/styled-icon/-/styled-icon-10.7.0.tgz",
-      "integrity": "sha512-SCrhCfRyoY8DY7gUkpz+B0RqUg/n1Zaqrr2+YKmK/AyeNfCcoHuP4R9N4H0p/NA1l7PTU10ZkAWSLi68phnAjw==",
+    "node_modules/@nestjs/axios": {
+      "version": "0.0.8",
+      "resolved": "https://registry.npmjs.org/@nestjs/axios/-/axios-0.0.8.tgz",
+      "integrity": "sha512-oJyfR9/h9tVk776il0829xyj3b2e81yTu6HjPraxynwNtMNGqZBHHmAQL24yMB3tVbBM0RvG3eUXH8+pRCGwlg==",
+      "dev": true,
       "dependencies": {
-        "@babel/runtime": "^7.19.0"
-      },
-      "funding": {
-        "type": "GitHub",
-        "url": "https://github.com/sponsors/jacobwgillespie"
+        "axios": "0.27.2"
       },
       "peerDependencies": {
-        "react": "*",
-        "styled-components": ">=4.1.0 <6"
+        "@nestjs/common": "^7.0.0 || ^8.0.0",
+        "reflect-metadata": "^0.1.12",
+        "rxjs": "^6.0.0 || ^7.0.0"
       }
     },
-    "node_modules/@swc/core": {
-      "version": "1.3.62",
-      "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.3.62.tgz",
-      "integrity": "sha512-J58hWY+/G8vOr4J6ZH9hLg0lMSijZtqIIf4HofZezGog/pVX6sJyBJ40dZ1ploFkDIlWTWvJyqtpesBKS73gkQ==",
-      "hasInstallScript": true,
-      "engines": {
-        "node": ">=10"
+    "node_modules/@nestjs/axios/node_modules/axios": {
+      "version": "0.27.2",
+      "resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz",
+      "integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==",
+      "dev": true,
+      "dependencies": {
+        "follow-redirects": "^1.14.9",
+        "form-data": "^4.0.0"
+      }
+    },
+    "node_modules/@nestjs/common": {
+      "version": "8.4.7",
+      "resolved": "https://registry.npmjs.org/@nestjs/common/-/common-8.4.7.tgz",
+      "integrity": "sha512-m/YsbcBal+gA5CFrDpqXqsSfylo+DIQrkFY3qhVIltsYRfu8ct8J9pqsTO6OPf3mvqdOpFGrV5sBjoyAzOBvsw==",
+      "dependencies": {
+        "axios": "0.27.2",
+        "iterare": "1.2.1",
+        "tslib": "2.4.0",
+        "uuid": "8.3.2"
       },
       "funding": {
         "type": "opencollective",
-        "url": "https://opencollective.com/swc"
-      },
-      "optionalDependencies": {
-        "@swc/core-darwin-arm64": "1.3.62",
-        "@swc/core-darwin-x64": "1.3.62",
-        "@swc/core-linux-arm-gnueabihf": "1.3.62",
-        "@swc/core-linux-arm64-gnu": "1.3.62",
-        "@swc/core-linux-arm64-musl": "1.3.62",
-        "@swc/core-linux-x64-gnu": "1.3.62",
-        "@swc/core-linux-x64-musl": "1.3.62",
-        "@swc/core-win32-arm64-msvc": "1.3.62",
-        "@swc/core-win32-ia32-msvc": "1.3.62",
-        "@swc/core-win32-x64-msvc": "1.3.62"
+        "url": "https://opencollective.com/nest"
       },
       "peerDependencies": {
-        "@swc/helpers": "^0.5.0"
+        "cache-manager": "*",
+        "class-transformer": "*",
+        "class-validator": "*",
+        "reflect-metadata": "^0.1.12",
+        "rxjs": "^7.1.0"
       },
       "peerDependenciesMeta": {
-        "@swc/helpers": {
+        "cache-manager": {
+          "optional": true
+        },
+        "class-transformer": {
+          "optional": true
+        },
+        "class-validator": {
           "optional": true
         }
       }
     },
-    "node_modules/@swc/core-darwin-arm64": {
-      "version": "1.3.62",
-      "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.62.tgz",
-      "integrity": "sha512-MmGilibITz68LEje6vJlKzc2gUUSgzvB3wGLSjEORikTNeM7P8jXVxE4A8fgZqDeudJUm9HVWrxCV+pHDSwXhA==",
-      "cpu": [
-        "arm64"
-      ],
-      "optional": true,
-      "os": [
-        "darwin"
-      ],
+    "node_modules/@nestjs/common/node_modules/axios": {
+      "version": "0.27.2",
+      "resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz",
+      "integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==",
+      "dependencies": {
+        "follow-redirects": "^1.14.9",
+        "form-data": "^4.0.0"
+      }
+    },
+    "node_modules/@nestjs/common/node_modules/tslib": {
+      "version": "2.4.0",
+      "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
+      "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ=="
+    },
+    "node_modules/@nodelib/fs.scandir": {
+      "version": "2.1.5",
+      "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
+      "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
+      "dependencies": {
+        "@nodelib/fs.stat": "2.0.5",
+        "run-parallel": "^1.1.9"
+      },
       "engines": {
-        "node": ">=10"
+        "node": ">= 8"
       }
     },
-    "node_modules/@swc/core-darwin-x64": {
-      "version": "1.3.62",
-      "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.3.62.tgz",
-      "integrity": "sha512-Xl93MMB3sCWVlYWuQIB+v6EQgzoiuQYK5tNt9lsHoIEVu2zLdkQjae+5FUHZb1VYqCXIiWcULFfVz0R4Sjb7JQ==",
-      "cpu": [
-        "x64"
-      ],
-      "optional": true,
-      "os": [
-        "darwin"
-      ],
+    "node_modules/@nodelib/fs.stat": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
+      "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
       "engines": {
-        "node": ">=10"
+        "node": ">= 8"
       }
     },
-    "node_modules/@swc/core-linux-arm-gnueabihf": {
-      "version": "1.3.62",
-      "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.62.tgz",
-      "integrity": "sha512-nJsp6O7kCtAjTTMcIjVB0g5y1JNiYAa5q630eiwrnaHUusEFoANDdORI3Z9vXeikMkng+6yIv9/V8Rb093xLjQ==",
-      "cpu": [
-        "arm"
-      ],
-      "optional": true,
-      "os": [
-        "linux"
-      ],
+    "node_modules/@nodelib/fs.walk": {
+      "version": "1.2.8",
+      "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
+      "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
+      "dependencies": {
+        "@nodelib/fs.scandir": "2.1.5",
+        "fastq": "^1.6.0"
+      },
       "engines": {
-        "node": ">=10"
+        "node": ">= 8"
       }
     },
-    "node_modules/@swc/core-linux-arm64-gnu": {
-      "version": "1.3.62",
-      "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.62.tgz",
-      "integrity": "sha512-XGsV93vpUAopDt5y6vPwbK1Nc/MlL55L77bAZUPIiosWD1cWWPHNtNSpriE6+I+JiMHe0pqtfS/SSTk6ZkFQVw==",
-      "cpu": [
-        "arm64"
-      ],
-      "optional": true,
-      "os": [
-        "linux"
-      ],
+    "node_modules/@npmcli/fs": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-2.1.2.tgz",
+      "integrity": "sha512-yOJKRvohFOaLqipNtwYB9WugyZKhC/DZC4VYPmpaCzDBrA8YpK3qHZ8/HGscMnE4GqbkLNuVcCnxkeQEdGt6LQ==",
+      "dependencies": {
+        "@gar/promisify": "^1.1.3",
+        "semver": "^7.3.5"
+      },
       "engines": {
-        "node": ">=10"
+        "node": "^12.13.0 || ^14.15.0 || >=16.0.0"
       }
     },
-    "node_modules/@swc/core-linux-arm64-musl": {
-      "version": "1.3.62",
-      "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.62.tgz",
-      "integrity": "sha512-ESUmJjSlTTkoBy9dMG49opcNn8BmviqStMhwyeD1G8XRnmRVCZZgoBOKdvCXmJhw8bQXDhZumeaTUB+OFUKVXg==",
-      "cpu": [
-        "arm64"
-      ],
-      "optional": true,
-      "os": [
-        "linux"
-      ],
+    "node_modules/@npmcli/move-file": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-2.0.1.tgz",
+      "integrity": "sha512-mJd2Z5TjYWq/ttPLLGqArdtnC74J6bOzg4rMDnN+p1xTacZ2yPRCk2y0oSWQtygLR9YVQXgOcONrwtnk3JupxQ==",
+      "deprecated": "This functionality has been moved to @npmcli/fs",
+      "dependencies": {
+        "mkdirp": "^1.0.4",
+        "rimraf": "^3.0.2"
+      },
       "engines": {
-        "node": ">=10"
+        "node": "^12.13.0 || ^14.15.0 || >=16.0.0"
       }
     },
-    "node_modules/@swc/core-linux-x64-gnu": {
-      "version": "1.3.62",
-      "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.62.tgz",
-      "integrity": "sha512-wnHJkt3ZBrax3SFnUHDcncG6mrSg9ZZjMhQV9Mc3JL1x1s1Gy9rGZCoBNnV/BUZWTemxIBcQbANRSDut/WO+9A==",
-      "cpu": [
-        "x64"
-      ],
-      "optional": true,
-      "os": [
-        "linux"
-      ],
+    "node_modules/@npmcli/move-file/node_modules/mkdirp": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
+      "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
+      "bin": {
+        "mkdirp": "bin/cmd.js"
+      },
       "engines": {
         "node": ">=10"
       }
     },
-    "node_modules/@swc/core-linux-x64-musl": {
-      "version": "1.3.62",
-      "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.62.tgz",
-      "integrity": "sha512-9oRbuTC/VshB66Rgwi3pTq3sPxSTIb8k9L1vJjES+dDMKa29DAjPtWCXG/pyZ00ufpFZgkGEuAHH5uqUcr1JQg==",
-      "cpu": [
-        "x64"
+    "node_modules/@nuxtjs/opencollective": {
+      "version": "0.3.2",
+      "resolved": "https://registry.npmjs.org/@nuxtjs/opencollective/-/opencollective-0.3.2.tgz",
+      "integrity": "sha512-um0xL3fO7Mf4fDxcqx9KryrB7zgRM5JSlvGN5AGkP6JLM5XEKyjeAiPbNxdXVXQ16isuAhYpvP88NgL2BGd6aA==",
+      "dev": true,
+      "dependencies": {
+        "chalk": "^4.1.0",
+        "consola": "^2.15.0",
+        "node-fetch": "^2.6.1"
+      },
+      "bin": {
+        "opencollective": "bin/opencollective.js"
+      },
+      "engines": {
+        "node": ">=8.0.0",
+        "npm": ">=5.0.0"
+      }
+    },
+    "node_modules/@openapitools/openapi-generator-cli": {
+      "version": "2.6.0",
+      "resolved": "https://registry.npmjs.org/@openapitools/openapi-generator-cli/-/openapi-generator-cli-2.6.0.tgz",
+      "integrity": "sha512-M/aOpR7G+Y1nMf+ofuar8pGszajgfhs1aSPSijkcr2tHTxKAI3sA3YYcOGbszxaNRKFyvOcDq+KP9pcJvKoCHg==",
+      "dev": true,
+      "hasInstallScript": true,
+      "dependencies": {
+        "@nestjs/axios": "0.0.8",
+        "@nestjs/common": "9.3.11",
+        "@nestjs/core": "9.3.11",
+        "@nuxtjs/opencollective": "0.3.2",
+        "chalk": "4.1.2",
+        "commander": "8.3.0",
+        "compare-versions": "4.1.4",
+        "concurrently": "6.5.1",
+        "console.table": "0.10.0",
+        "fs-extra": "10.1.0",
+        "glob": "7.1.6",
+        "inquirer": "8.2.5",
+        "lodash": "4.17.21",
+        "reflect-metadata": "0.1.13",
+        "rxjs": "7.8.0",
+        "tslib": "2.0.3"
+      },
+      "bin": {
+        "openapi-generator-cli": "main.js"
+      },
+      "engines": {
+        "node": ">=10.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/openapi_generator"
+      }
+    },
+    "node_modules/@openapitools/openapi-generator-cli/node_modules/@nestjs/common": {
+      "version": "9.3.11",
+      "resolved": "https://registry.npmjs.org/@nestjs/common/-/common-9.3.11.tgz",
+      "integrity": "sha512-IFZ2G/5UKWC2Uo7tJ4SxGed2+aiA+sJyWeWsGTogKVDhq90oxVBToh+uCDeI31HNUpqYGoWmkletfty42zUd8A==",
+      "dev": true,
+      "dependencies": {
+        "iterare": "1.2.1",
+        "tslib": "2.5.0",
+        "uid": "2.0.1"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/nest"
+      },
+      "peerDependencies": {
+        "cache-manager": "<=5",
+        "class-transformer": "*",
+        "class-validator": "*",
+        "reflect-metadata": "^0.1.12",
+        "rxjs": "^7.1.0"
+      },
+      "peerDependenciesMeta": {
+        "cache-manager": {
+          "optional": true
+        },
+        "class-transformer": {
+          "optional": true
+        },
+        "class-validator": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@openapitools/openapi-generator-cli/node_modules/@nestjs/common/node_modules/tslib": {
+      "version": "2.5.0",
+      "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz",
+      "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==",
+      "dev": true
+    },
+    "node_modules/@openapitools/openapi-generator-cli/node_modules/@nestjs/core": {
+      "version": "9.3.11",
+      "resolved": "https://registry.npmjs.org/@nestjs/core/-/core-9.3.11.tgz",
+      "integrity": "sha512-CI27a2JFd5rvvbgkalWqsiwQNhcP4EAG5BUK8usjp29wVp1kx30ghfBT8FLqIgmkRVo65A0IcEnWsxeXMntkxQ==",
+      "dev": true,
+      "hasInstallScript": true,
+      "dependencies": {
+        "@nuxtjs/opencollective": "0.3.2",
+        "fast-safe-stringify": "2.1.1",
+        "iterare": "1.2.1",
+        "path-to-regexp": "3.2.0",
+        "tslib": "2.5.0",
+        "uid": "2.0.1"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/nest"
+      },
+      "peerDependencies": {
+        "@nestjs/common": "^9.0.0",
+        "@nestjs/microservices": "^9.0.0",
+        "@nestjs/platform-express": "^9.0.0",
+        "@nestjs/websockets": "^9.0.0",
+        "reflect-metadata": "^0.1.12",
+        "rxjs": "^7.1.0"
+      },
+      "peerDependenciesMeta": {
+        "@nestjs/microservices": {
+          "optional": true
+        },
+        "@nestjs/platform-express": {
+          "optional": true
+        },
+        "@nestjs/websockets": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@openapitools/openapi-generator-cli/node_modules/@nestjs/core/node_modules/tslib": {
+      "version": "2.5.0",
+      "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz",
+      "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==",
+      "dev": true
+    },
+    "node_modules/@openapitools/openapi-generator-cli/node_modules/commander": {
+      "version": "8.3.0",
+      "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz",
+      "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==",
+      "dev": true,
+      "engines": {
+        "node": ">= 12"
+      }
+    },
+    "node_modules/@openapitools/openapi-generator-cli/node_modules/glob": {
+      "version": "7.1.6",
+      "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
+      "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
+      "dev": true,
+      "dependencies": {
+        "fs.realpath": "^1.0.0",
+        "inflight": "^1.0.4",
+        "inherits": "2",
+        "minimatch": "^3.0.4",
+        "once": "^1.3.0",
+        "path-is-absolute": "^1.0.0"
+      },
+      "engines": {
+        "node": "*"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/@openapitools/openapi-generator-cli/node_modules/tslib": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.3.tgz",
+      "integrity": "sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ==",
+      "dev": true
+    },
+    "node_modules/@reduxjs/toolkit": {
+      "version": "1.9.3",
+      "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-1.9.3.tgz",
+      "integrity": "sha512-GU2TNBQVofL09VGmuSioNPQIu6Ml0YLf4EJhgj0AvBadRlCGzUWet8372LjvO4fqKZF2vH1xU0htAa7BrK9pZg==",
+      "dependencies": {
+        "immer": "^9.0.16",
+        "redux": "^4.2.0",
+        "redux-thunk": "^2.4.2",
+        "reselect": "^4.1.7"
+      },
+      "peerDependencies": {
+        "react": "^16.9.0 || ^17.0.0 || ^18",
+        "react-redux": "^7.2.1 || ^8.0.2"
+      },
+      "peerDependenciesMeta": {
+        "react": {
+          "optional": true
+        },
+        "react-redux": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@segment/analytics-core": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/@segment/analytics-core/-/analytics-core-1.2.0.tgz",
+      "integrity": "sha512-2BSliLJi1RWq8+eE+UKcMEiC5WfZZp3SHIA/fGhFftOg2s1OkFaQRHuKFzdgbDuKZMEsRwqek3EITNGSThJ5rg==",
+      "dependencies": {
+        "@lukeed/uuid": "^2.0.0",
+        "dset": "^3.1.2",
+        "tslib": "^2.4.1"
+      }
+    },
+    "node_modules/@segment/analytics-core/node_modules/tslib": {
+      "version": "2.5.0",
+      "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz",
+      "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg=="
+    },
+    "node_modules/@segment/analytics-node": {
+      "version": "0.0.1-beta.16",
+      "resolved": "https://registry.npmjs.org/@segment/analytics-node/-/analytics-node-0.0.1-beta.16.tgz",
+      "integrity": "sha512-WYKvLQ1xyDNOzxZ9+ltF/ROB6MhsFeKaNlVAam3FKVczMg+gNa2KKvfOUA3wXxIhvDvWaZY7e7MWEXxxukl4+g==",
+      "dependencies": {
+        "@lukeed/uuid": "^2.0.0",
+        "@segment/analytics-core": "1.2.0",
+        "node-fetch": "^2.6.7",
+        "tslib": "^2.4.1"
+      },
+      "engines": {
+        "node": ">=14"
+      }
+    },
+    "node_modules/@segment/analytics-node/node_modules/tslib": {
+      "version": "2.5.0",
+      "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz",
+      "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg=="
+    },
+    "node_modules/@sentry-internal/tracing": {
+      "version": "7.57.0",
+      "resolved": "https://registry.npmjs.org/@sentry-internal/tracing/-/tracing-7.57.0.tgz",
+      "integrity": "sha512-tpViyDd8AhQGYYhI94xi2aaDopXOPfL2Apwrtb3qirWkomIQ2K86W1mPmkce+B0cFOnW2Dxv/ZTFKz6ghjK75A==",
+      "dependencies": {
+        "@sentry/core": "7.57.0",
+        "@sentry/types": "7.57.0",
+        "@sentry/utils": "7.57.0",
+        "tslib": "^2.4.1 || ^1.9.3"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@sentry/core": {
+      "version": "7.57.0",
+      "resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.57.0.tgz",
+      "integrity": "sha512-l014NudPH0vQlzybtXajPxYFfs9w762NoarjObC3gu76D1jzBBFzhdRelkGpDbSLNTIsKhEDDRpgAjBWJ9icfw==",
+      "dependencies": {
+        "@sentry/types": "7.57.0",
+        "@sentry/utils": "7.57.0",
+        "tslib": "^2.4.1 || ^1.9.3"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@sentry/node": {
+      "version": "7.57.0",
+      "resolved": "https://registry.npmjs.org/@sentry/node/-/node-7.57.0.tgz",
+      "integrity": "sha512-63mjyUVM6sfJFVQ5TGVRVGUsoEfESl5ABzIW1W0s9gUiQPaG8SOdaQJglb2VNrkMYxnRHgD8Q9LUh/qcmUyPGw==",
+      "dependencies": {
+        "@sentry-internal/tracing": "7.57.0",
+        "@sentry/core": "7.57.0",
+        "@sentry/types": "7.57.0",
+        "@sentry/utils": "7.57.0",
+        "cookie": "^0.4.1",
+        "https-proxy-agent": "^5.0.0",
+        "lru_map": "^0.3.3",
+        "tslib": "^2.4.1 || ^1.9.3"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@sentry/types": {
+      "version": "7.57.0",
+      "resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.57.0.tgz",
+      "integrity": "sha512-D7ifoUfxuVCUyktIr5Gc+jXUbtcUMmfHdTtTbf1XCZHua5mJceK9wtl3YCg3eq/HK2Ppd52BKnTzEcS5ZKQM+w==",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@sentry/utils": {
+      "version": "7.57.0",
+      "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.57.0.tgz",
+      "integrity": "sha512-YXrkMCiNklqkXctn4mKYkrzNCf/dfVcRUQrkXjeBC+PHXbcpPyaJgInNvztR7Skl8lE3JPGPN4v5XhLxK1bUUg==",
+      "dependencies": {
+        "@sentry/types": "7.57.0",
+        "tslib": "^2.4.1 || ^1.9.3"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@sinclair/typebox": {
+      "version": "0.25.24",
+      "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.25.24.tgz",
+      "integrity": "sha512-XJfwUVUKDHF5ugKwIcxEgc9k8b7HbznCp6eUfWgu710hMPNIO4aw4/zB5RogDQz8nd6gyCDpU9O/m6qYEWY6yQ==",
+      "dev": true
+    },
+    "node_modules/@sindresorhus/is": {
+      "version": "4.6.0",
+      "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz",
+      "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==",
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sindresorhus/is?sponsor=1"
+      }
+    },
+    "node_modules/@sinonjs/commons": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.0.tgz",
+      "integrity": "sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA==",
+      "dev": true,
+      "dependencies": {
+        "type-detect": "4.0.8"
+      }
+    },
+    "node_modules/@sinonjs/fake-timers": {
+      "version": "10.3.0",
+      "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz",
+      "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==",
+      "dev": true,
+      "dependencies": {
+        "@sinonjs/commons": "^3.0.0"
+      }
+    },
+    "node_modules/@styled-icons/heroicons-outline": {
+      "version": "10.47.0",
+      "resolved": "https://registry.npmjs.org/@styled-icons/heroicons-outline/-/heroicons-outline-10.47.0.tgz",
+      "integrity": "sha512-C7bcJ/YPVKACoQLSBDM9DkgmrO1HmqAaru9kqYK2V+GaGUW5raf6dyTLo7GUYt/CJ7p3qWxsBz3SX6djzdaODQ==",
+      "dependencies": {
+        "@babel/runtime": "^7.20.7",
+        "@styled-icons/styled-icon": "^10.7.0"
+      },
+      "funding": {
+        "type": "GitHub",
+        "url": "https://github.com/sponsors/jacobwgillespie"
+      },
+      "peerDependencies": {
+        "react": "*",
+        "styled-components": "*"
+      }
+    },
+    "node_modules/@styled-icons/styled-icon": {
+      "version": "10.7.0",
+      "resolved": "https://registry.npmjs.org/@styled-icons/styled-icon/-/styled-icon-10.7.0.tgz",
+      "integrity": "sha512-SCrhCfRyoY8DY7gUkpz+B0RqUg/n1Zaqrr2+YKmK/AyeNfCcoHuP4R9N4H0p/NA1l7PTU10ZkAWSLi68phnAjw==",
+      "dependencies": {
+        "@babel/runtime": "^7.19.0"
+      },
+      "funding": {
+        "type": "GitHub",
+        "url": "https://github.com/sponsors/jacobwgillespie"
+      },
+      "peerDependencies": {
+        "react": "*",
+        "styled-components": ">=4.1.0 <6"
+      }
+    },
+    "node_modules/@swc/core": {
+      "version": "1.3.62",
+      "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.3.62.tgz",
+      "integrity": "sha512-J58hWY+/G8vOr4J6ZH9hLg0lMSijZtqIIf4HofZezGog/pVX6sJyBJ40dZ1ploFkDIlWTWvJyqtpesBKS73gkQ==",
+      "hasInstallScript": true,
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/swc"
+      },
+      "optionalDependencies": {
+        "@swc/core-darwin-arm64": "1.3.62",
+        "@swc/core-darwin-x64": "1.3.62",
+        "@swc/core-linux-arm-gnueabihf": "1.3.62",
+        "@swc/core-linux-arm64-gnu": "1.3.62",
+        "@swc/core-linux-arm64-musl": "1.3.62",
+        "@swc/core-linux-x64-gnu": "1.3.62",
+        "@swc/core-linux-x64-musl": "1.3.62",
+        "@swc/core-win32-arm64-msvc": "1.3.62",
+        "@swc/core-win32-ia32-msvc": "1.3.62",
+        "@swc/core-win32-x64-msvc": "1.3.62"
+      },
+      "peerDependencies": {
+        "@swc/helpers": "^0.5.0"
+      },
+      "peerDependenciesMeta": {
+        "@swc/helpers": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@swc/core-darwin-arm64": {
+      "version": "1.3.62",
+      "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.62.tgz",
+      "integrity": "sha512-MmGilibITz68LEje6vJlKzc2gUUSgzvB3wGLSjEORikTNeM7P8jXVxE4A8fgZqDeudJUm9HVWrxCV+pHDSwXhA==",
+      "cpu": [
+        "arm64"
+      ],
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/@swc/core-darwin-x64": {
+      "version": "1.3.62",
+      "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.3.62.tgz",
+      "integrity": "sha512-Xl93MMB3sCWVlYWuQIB+v6EQgzoiuQYK5tNt9lsHoIEVu2zLdkQjae+5FUHZb1VYqCXIiWcULFfVz0R4Sjb7JQ==",
+      "cpu": [
+        "x64"
+      ],
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/@swc/core-linux-arm-gnueabihf": {
+      "version": "1.3.62",
+      "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.62.tgz",
+      "integrity": "sha512-nJsp6O7kCtAjTTMcIjVB0g5y1JNiYAa5q630eiwrnaHUusEFoANDdORI3Z9vXeikMkng+6yIv9/V8Rb093xLjQ==",
+      "cpu": [
+        "arm"
+      ],
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/@swc/core-linux-arm64-gnu": {
+      "version": "1.3.62",
+      "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.62.tgz",
+      "integrity": "sha512-XGsV93vpUAopDt5y6vPwbK1Nc/MlL55L77bAZUPIiosWD1cWWPHNtNSpriE6+I+JiMHe0pqtfS/SSTk6ZkFQVw==",
+      "cpu": [
+        "arm64"
+      ],
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/@swc/core-linux-arm64-musl": {
+      "version": "1.3.62",
+      "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.62.tgz",
+      "integrity": "sha512-ESUmJjSlTTkoBy9dMG49opcNn8BmviqStMhwyeD1G8XRnmRVCZZgoBOKdvCXmJhw8bQXDhZumeaTUB+OFUKVXg==",
+      "cpu": [
+        "arm64"
+      ],
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/@swc/core-linux-x64-gnu": {
+      "version": "1.3.62",
+      "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.62.tgz",
+      "integrity": "sha512-wnHJkt3ZBrax3SFnUHDcncG6mrSg9ZZjMhQV9Mc3JL1x1s1Gy9rGZCoBNnV/BUZWTemxIBcQbANRSDut/WO+9A==",
+      "cpu": [
+        "x64"
+      ],
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/@swc/core-linux-x64-musl": {
+      "version": "1.3.62",
+      "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.62.tgz",
+      "integrity": "sha512-9oRbuTC/VshB66Rgwi3pTq3sPxSTIb8k9L1vJjES+dDMKa29DAjPtWCXG/pyZ00ufpFZgkGEuAHH5uqUcr1JQg==",
+      "cpu": [
+        "x64"
       ],
       "optional": true,
       "os": [
         "linux"
       ],
       "engines": {
-        "node": ">=10"
+        "node": ">=10"
+      }
+    },
+    "node_modules/@swc/core-win32-arm64-msvc": {
+      "version": "1.3.62",
+      "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.62.tgz",
+      "integrity": "sha512-zv14vlF2VRrxS061XkfzGjCYnOrEo5glKJjLK5PwUKysIoVrx/L8nAbFxjkX5cObdlyoqo+ekelyBPAO+4bS0w==",
+      "cpu": [
+        "arm64"
+      ],
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/@swc/core-win32-ia32-msvc": {
+      "version": "1.3.62",
+      "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.62.tgz",
+      "integrity": "sha512-8MC/PZQSsOP2iA/81tAfNRqMWyEqTS/8zKUI67vPuLvpx6NAjRn3E9qBv7iFqH79iqZNzqSMo3awnLrKZyFbcw==",
+      "cpu": [
+        "ia32"
+      ],
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/@swc/core-win32-x64-msvc": {
+      "version": "1.3.62",
+      "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.62.tgz",
+      "integrity": "sha512-GJSmUJ95HKHZXAxiuPUmrcm/S3ivQvEzXhOZaIqYBIwUsm02vFZkClsV7eIKzWjso1t0+I/8MjrnUNaSWqh1rQ==",
+      "cpu": [
+        "x64"
+      ],
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/@szmarczak/http-timer": {
+      "version": "4.0.6",
+      "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz",
+      "integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==",
+      "dependencies": {
+        "defer-to-connect": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/@tootallnate/once": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz",
+      "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==",
+      "dev": true,
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/@types/babel__core": {
+      "version": "7.20.1",
+      "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.1.tgz",
+      "integrity": "sha512-aACu/U/omhdk15O4Nfb+fHgH/z3QsfQzpnvRZhYhThms83ZnAOZz7zZAWO7mn2yyNQaA4xTO8GLK3uqFU4bYYw==",
+      "dev": true,
+      "dependencies": {
+        "@babel/parser": "^7.20.7",
+        "@babel/types": "^7.20.7",
+        "@types/babel__generator": "*",
+        "@types/babel__template": "*",
+        "@types/babel__traverse": "*"
+      }
+    },
+    "node_modules/@types/babel__generator": {
+      "version": "7.6.4",
+      "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz",
+      "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==",
+      "dev": true,
+      "dependencies": {
+        "@babel/types": "^7.0.0"
+      }
+    },
+    "node_modules/@types/babel__template": {
+      "version": "7.4.1",
+      "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz",
+      "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==",
+      "dev": true,
+      "dependencies": {
+        "@babel/parser": "^7.1.0",
+        "@babel/types": "^7.0.0"
+      }
+    },
+    "node_modules/@types/babel__traverse": {
+      "version": "7.20.1",
+      "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.1.tgz",
+      "integrity": "sha512-MitHFXnhtgwsGZWtT68URpOvLN4EREih1u3QtQiN4VdAxWKRVvGCSvw/Qth0M0Qq3pJpnGOu5JaM/ydK7OGbqg==",
+      "dev": true,
+      "dependencies": {
+        "@babel/types": "^7.20.7"
+      }
+    },
+    "node_modules/@types/cacheable-request": {
+      "version": "6.0.3",
+      "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz",
+      "integrity": "sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==",
+      "dependencies": {
+        "@types/http-cache-semantics": "*",
+        "@types/keyv": "^3.1.4",
+        "@types/node": "*",
+        "@types/responselike": "^1.0.0"
+      }
+    },
+    "node_modules/@types/debug": {
+      "version": "4.1.8",
+      "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.8.tgz",
+      "integrity": "sha512-/vPO1EPOs306Cvhwv7KfVfYvOJqA/S/AXjaHQiJboCZzcNDb+TIJFN9/2C9DZ//ijSKWioNyUxD792QmDJ+HKQ==",
+      "dependencies": {
+        "@types/ms": "*"
+      }
+    },
+    "node_modules/@types/glob": {
+      "version": "8.0.0",
+      "resolved": "https://registry.npmjs.org/@types/glob/-/glob-8.0.0.tgz",
+      "integrity": "sha512-l6NQsDDyQUVeoTynNpC9uRvCUint/gSUXQA2euwmTuWGvPY5LSDUu6tkCtJB2SvGQlJQzLaKqcGZP4//7EDveA==",
+      "dev": true,
+      "dependencies": {
+        "@types/minimatch": "*",
+        "@types/node": "*"
+      }
+    },
+    "node_modules/@types/graceful-fs": {
+      "version": "4.1.6",
+      "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.6.tgz",
+      "integrity": "sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw==",
+      "dev": true,
+      "dependencies": {
+        "@types/node": "*"
+      }
+    },
+    "node_modules/@types/hast": {
+      "version": "2.3.4",
+      "resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.4.tgz",
+      "integrity": "sha512-wLEm0QvaoawEDoTRwzTXp4b4jpwiJDvR5KMnFnVodm3scufTlBOWRD6N1OBf9TZMhjlNsSfcO5V+7AF4+Vy+9g==",
+      "dependencies": {
+        "@types/unist": "*"
+      }
+    },
+    "node_modules/@types/hoist-non-react-statics": {
+      "version": "3.3.1",
+      "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz",
+      "integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==",
+      "dependencies": {
+        "@types/react": "*",
+        "hoist-non-react-statics": "^3.3.0"
+      }
+    },
+    "node_modules/@types/http-cache-semantics": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.1.tgz",
+      "integrity": "sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ=="
+    },
+    "node_modules/@types/istanbul-lib-coverage": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz",
+      "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==",
+      "dev": true
+    },
+    "node_modules/@types/istanbul-lib-report": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz",
+      "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==",
+      "dev": true,
+      "dependencies": {
+        "@types/istanbul-lib-coverage": "*"
+      }
+    },
+    "node_modules/@types/istanbul-reports": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz",
+      "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==",
+      "dev": true,
+      "dependencies": {
+        "@types/istanbul-lib-report": "*"
+      }
+    },
+    "node_modules/@types/jest": {
+      "version": "29.5.2",
+      "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.2.tgz",
+      "integrity": "sha512-mSoZVJF5YzGVCk+FsDxzDuH7s+SCkzrgKZzf0Z0T2WudhBUPoF6ktoTPC4R0ZoCPCV5xUvuU6ias5NvxcBcMMg==",
+      "dev": true,
+      "dependencies": {
+        "expect": "^29.0.0",
+        "pretty-format": "^29.0.0"
+      }
+    },
+    "node_modules/@types/json-schema": {
+      "version": "7.0.11",
+      "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz",
+      "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==",
+      "dev": true
+    },
+    "node_modules/@types/keyv": {
+      "version": "3.1.4",
+      "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz",
+      "integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==",
+      "dependencies": {
+        "@types/node": "*"
+      }
+    },
+    "node_modules/@types/lodash": {
+      "version": "4.14.191",
+      "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.191.tgz",
+      "integrity": "sha512-BdZ5BCCvho3EIXw6wUCXHe7rS53AIDPLE+JzwgT+OsJk53oBfbSmZZ7CX4VaRoN78N+TJpFi9QPlfIVNmJYWxQ==",
+      "dev": true
+    },
+    "node_modules/@types/mdast": {
+      "version": "3.0.11",
+      "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.11.tgz",
+      "integrity": "sha512-Y/uImid8aAwrEA24/1tcRZwpxX3pIFTSilcNDKSPn+Y2iDywSEachzRuvgAYYLR3wpGXAsMbv5lvKLDZLeYPAw==",
+      "dependencies": {
+        "@types/unist": "*"
+      }
+    },
+    "node_modules/@types/minimatch": {
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz",
+      "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==",
+      "dev": true
+    },
+    "node_modules/@types/mocha": {
+      "version": "10.0.1",
+      "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.1.tgz",
+      "integrity": "sha512-/fvYntiO1GeICvqbQ3doGDIP97vWmvFt83GKguJ6prmQM2iXZfFcq6YE8KteFyRtX2/h5Hf91BYvPodJKFYv5Q==",
+      "dev": true
+    },
+    "node_modules/@types/ms": {
+      "version": "0.7.31",
+      "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.31.tgz",
+      "integrity": "sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA=="
+    },
+    "node_modules/@types/node": {
+      "version": "16.18.11",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.11.tgz",
+      "integrity": "sha512-3oJbGBUWuS6ahSnEq1eN2XrCyf4YsWI8OyCvo7c64zQJNplk3mO84t53o8lfTk+2ji59g5ycfc6qQ3fdHliHuA=="
+    },
+    "node_modules/@types/node-fetch": {
+      "version": "2.6.2",
+      "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.2.tgz",
+      "integrity": "sha512-DHqhlq5jeESLy19TYhLakJ07kNumXWjcDdxXsLUMJZ6ue8VZJj4kLPQVE/2mdHh3xZziNF1xppu5lwmS53HR+A==",
+      "dev": true,
+      "dependencies": {
+        "@types/node": "*",
+        "form-data": "^3.0.0"
+      }
+    },
+    "node_modules/@types/node-fetch/node_modules/form-data": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz",
+      "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==",
+      "dev": true,
+      "dependencies": {
+        "asynckit": "^0.4.0",
+        "combined-stream": "^1.0.8",
+        "mime-types": "^2.1.12"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/@types/prettier": {
+      "version": "2.7.2",
+      "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.2.tgz",
+      "integrity": "sha512-KufADq8uQqo1pYKVIYzfKbJfBAc0sOeXqGbFaSpv8MRmC/zXgowNZmFcbngndGk922QDmOASEXUZCaY48gs4cg==",
+      "dev": true
+    },
+    "node_modules/@types/prop-types": {
+      "version": "15.7.5",
+      "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz",
+      "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w=="
+    },
+    "node_modules/@types/react": {
+      "version": "18.0.28",
+      "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.28.tgz",
+      "integrity": "sha512-RD0ivG1kEztNBdoAK7lekI9M+azSnitIn85h4iOiaLjaTrMjzslhaqCGaI4IyCJ1RljWiLCEu4jyrLLgqxBTew==",
+      "dependencies": {
+        "@types/prop-types": "*",
+        "@types/scheduler": "*",
+        "csstype": "^3.0.2"
+      }
+    },
+    "node_modules/@types/react-dom": {
+      "version": "18.2.4",
+      "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.4.tgz",
+      "integrity": "sha512-G2mHoTMTL4yoydITgOGwWdWMVd8sNgyEP85xVmMKAPUBwQWm9wBPQUmvbeF4V3WBY1P7mmL4BkjQ0SqUpf1snw==",
+      "devOptional": true,
+      "dependencies": {
+        "@types/react": "*"
+      }
+    },
+    "node_modules/@types/responselike": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.0.tgz",
+      "integrity": "sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==",
+      "dependencies": {
+        "@types/node": "*"
+      }
+    },
+    "node_modules/@types/scheduler": {
+      "version": "0.16.2",
+      "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz",
+      "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew=="
+    },
+    "node_modules/@types/semver": {
+      "version": "7.3.13",
+      "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz",
+      "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==",
+      "dev": true
+    },
+    "node_modules/@types/stack-utils": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz",
+      "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==",
+      "dev": true
+    },
+    "node_modules/@types/styled-components": {
+      "version": "5.1.26",
+      "resolved": "https://registry.npmjs.org/@types/styled-components/-/styled-components-5.1.26.tgz",
+      "integrity": "sha512-KuKJ9Z6xb93uJiIyxo/+ksS7yLjS1KzG6iv5i78dhVg/X3u5t1H7juRWqVmodIdz6wGVaIApo1u01kmFRdJHVw==",
+      "dev": true,
+      "dependencies": {
+        "@types/hoist-non-react-statics": "*",
+        "@types/react": "*",
+        "csstype": "^3.0.2"
+      }
+    },
+    "node_modules/@types/unist": {
+      "version": "2.0.6",
+      "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.6.tgz",
+      "integrity": "sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ=="
+    },
+    "node_modules/@types/use-sync-external-store": {
+      "version": "0.0.3",
+      "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz",
+      "integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA=="
+    },
+    "node_modules/@types/vscode": {
+      "version": "1.67.0",
+      "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.67.0.tgz",
+      "integrity": "sha512-GH8BDf8cw9AC9080uneJfulhSa7KHSMI2s/CyKePXoGNos9J486w2V4YKoeNUqIEkW4hKoEAWp6/cXTwyGj47g==",
+      "dev": true
+    },
+    "node_modules/@types/ws": {
+      "version": "8.5.4",
+      "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.4.tgz",
+      "integrity": "sha512-zdQDHKUgcX/zBc4GrwsE/7dVdAD8JR4EuiAXiiUhhfyIJXXb2+PrGshFyeXWQPMmmZ2XxgaqclgpIC7eTXc1mg==",
+      "dev": true,
+      "dependencies": {
+        "@types/node": "*"
+      }
+    },
+    "node_modules/@types/yargs": {
+      "version": "17.0.24",
+      "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz",
+      "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==",
+      "dev": true,
+      "dependencies": {
+        "@types/yargs-parser": "*"
+      }
+    },
+    "node_modules/@types/yargs-parser": {
+      "version": "21.0.0",
+      "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz",
+      "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==",
+      "dev": true
+    },
+    "node_modules/@typescript-eslint/eslint-plugin": {
+      "version": "5.48.2",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.48.2.tgz",
+      "integrity": "sha512-sR0Gja9Ky1teIq4qJOl0nC+Tk64/uYdX+mi+5iB//MH8gwyx8e3SOyhEzeLZEFEEfCaLf8KJq+Bd/6je1t+CAg==",
+      "dev": true,
+      "dependencies": {
+        "@typescript-eslint/scope-manager": "5.48.2",
+        "@typescript-eslint/type-utils": "5.48.2",
+        "@typescript-eslint/utils": "5.48.2",
+        "debug": "^4.3.4",
+        "ignore": "^5.2.0",
+        "natural-compare-lite": "^1.4.0",
+        "regexpp": "^3.2.0",
+        "semver": "^7.3.7",
+        "tsutils": "^3.21.0"
+      },
+      "engines": {
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/typescript-eslint"
+      },
+      "peerDependencies": {
+        "@typescript-eslint/parser": "^5.0.0",
+        "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0"
+      },
+      "peerDependenciesMeta": {
+        "typescript": {
+          "optional": true
+        }
       }
     },
-    "node_modules/@swc/core-win32-arm64-msvc": {
-      "version": "1.3.62",
-      "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.62.tgz",
-      "integrity": "sha512-zv14vlF2VRrxS061XkfzGjCYnOrEo5glKJjLK5PwUKysIoVrx/L8nAbFxjkX5cObdlyoqo+ekelyBPAO+4bS0w==",
-      "cpu": [
-        "arm64"
-      ],
-      "optional": true,
-      "os": [
-        "win32"
-      ],
+    "node_modules/@typescript-eslint/parser": {
+      "version": "5.48.2",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.48.2.tgz",
+      "integrity": "sha512-38zMsKsG2sIuM5Oi/olurGwYJXzmtdsHhn5mI/pQogP+BjYVkK5iRazCQ8RGS0V+YLk282uWElN70zAAUmaYHw==",
+      "dev": true,
+      "dependencies": {
+        "@typescript-eslint/scope-manager": "5.48.2",
+        "@typescript-eslint/types": "5.48.2",
+        "@typescript-eslint/typescript-estree": "5.48.2",
+        "debug": "^4.3.4"
+      },
       "engines": {
-        "node": ">=10"
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/typescript-eslint"
+      },
+      "peerDependencies": {
+        "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0"
+      },
+      "peerDependenciesMeta": {
+        "typescript": {
+          "optional": true
+        }
       }
     },
-    "node_modules/@swc/core-win32-ia32-msvc": {
-      "version": "1.3.62",
-      "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.62.tgz",
-      "integrity": "sha512-8MC/PZQSsOP2iA/81tAfNRqMWyEqTS/8zKUI67vPuLvpx6NAjRn3E9qBv7iFqH79iqZNzqSMo3awnLrKZyFbcw==",
-      "cpu": [
-        "ia32"
-      ],
-      "optional": true,
-      "os": [
-        "win32"
-      ],
+    "node_modules/@typescript-eslint/scope-manager": {
+      "version": "5.48.2",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.48.2.tgz",
+      "integrity": "sha512-zEUFfonQid5KRDKoI3O+uP1GnrFd4tIHlvs+sTJXiWuypUWMuDaottkJuR612wQfOkjYbsaskSIURV9xo4f+Fw==",
+      "dev": true,
+      "dependencies": {
+        "@typescript-eslint/types": "5.48.2",
+        "@typescript-eslint/visitor-keys": "5.48.2"
+      },
       "engines": {
-        "node": ">=10"
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/typescript-eslint"
       }
     },
-    "node_modules/@swc/core-win32-x64-msvc": {
-      "version": "1.3.62",
-      "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.62.tgz",
-      "integrity": "sha512-GJSmUJ95HKHZXAxiuPUmrcm/S3ivQvEzXhOZaIqYBIwUsm02vFZkClsV7eIKzWjso1t0+I/8MjrnUNaSWqh1rQ==",
-      "cpu": [
-        "x64"
-      ],
-      "optional": true,
-      "os": [
-        "win32"
-      ],
+    "node_modules/@typescript-eslint/type-utils": {
+      "version": "5.48.2",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.48.2.tgz",
+      "integrity": "sha512-QVWx7J5sPMRiOMJp5dYshPxABRoZV1xbRirqSk8yuIIsu0nvMTZesKErEA3Oix1k+uvsk8Cs8TGJ6kQ0ndAcew==",
+      "dev": true,
+      "dependencies": {
+        "@typescript-eslint/typescript-estree": "5.48.2",
+        "@typescript-eslint/utils": "5.48.2",
+        "debug": "^4.3.4",
+        "tsutils": "^3.21.0"
+      },
       "engines": {
-        "node": ">=10"
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/typescript-eslint"
+      },
+      "peerDependencies": {
+        "eslint": "*"
+      },
+      "peerDependenciesMeta": {
+        "typescript": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@typescript-eslint/types": {
+      "version": "5.48.2",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.48.2.tgz",
+      "integrity": "sha512-hE7dA77xxu7ByBc6KCzikgfRyBCTst6dZQpwaTy25iMYOnbNljDT4hjhrGEJJ0QoMjrfqrx+j1l1B9/LtKeuqA==",
+      "dev": true,
+      "engines": {
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/typescript-eslint"
+      }
+    },
+    "node_modules/@typescript-eslint/typescript-estree": {
+      "version": "5.48.2",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.48.2.tgz",
+      "integrity": "sha512-bibvD3z6ilnoVxUBFEgkO0k0aFvUc4Cttt0dAreEr+nrAHhWzkO83PEVVuieK3DqcgL6VAK5dkzK8XUVja5Zcg==",
+      "dev": true,
+      "dependencies": {
+        "@typescript-eslint/types": "5.48.2",
+        "@typescript-eslint/visitor-keys": "5.48.2",
+        "debug": "^4.3.4",
+        "globby": "^11.1.0",
+        "is-glob": "^4.0.3",
+        "semver": "^7.3.7",
+        "tsutils": "^3.21.0"
+      },
+      "engines": {
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/typescript-eslint"
+      },
+      "peerDependenciesMeta": {
+        "typescript": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@typescript-eslint/utils": {
+      "version": "5.48.2",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.48.2.tgz",
+      "integrity": "sha512-2h18c0d7jgkw6tdKTlNaM7wyopbLRBiit8oAxoP89YnuBOzCZ8g8aBCaCqq7h208qUTroL7Whgzam7UY3HVLow==",
+      "dev": true,
+      "dependencies": {
+        "@types/json-schema": "^7.0.9",
+        "@types/semver": "^7.3.12",
+        "@typescript-eslint/scope-manager": "5.48.2",
+        "@typescript-eslint/types": "5.48.2",
+        "@typescript-eslint/typescript-estree": "5.48.2",
+        "eslint-scope": "^5.1.1",
+        "eslint-utils": "^3.0.0",
+        "semver": "^7.3.7"
+      },
+      "engines": {
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/typescript-eslint"
+      },
+      "peerDependencies": {
+        "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0"
+      }
+    },
+    "node_modules/@typescript-eslint/visitor-keys": {
+      "version": "5.48.2",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.48.2.tgz",
+      "integrity": "sha512-z9njZLSkwmjFWUelGEwEbdf4NwKvfHxvGC0OcGN1Hp/XNDIcJ7D5DpPNPv6x6/mFvc1tQHsaWmpD/a4gOvvCJQ==",
+      "dev": true,
+      "dependencies": {
+        "@typescript-eslint/types": "5.48.2",
+        "eslint-visitor-keys": "^3.3.0"
+      },
+      "engines": {
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/typescript-eslint"
+      }
+    },
+    "node_modules/@vitejs/plugin-react-swc": {
+      "version": "3.3.2",
+      "resolved": "https://registry.npmjs.org/@vitejs/plugin-react-swc/-/plugin-react-swc-3.3.2.tgz",
+      "integrity": "sha512-VJFWY5sfoZerQRvJrh518h3AcQt6f/yTuWn4/TRB+dqmYU0NX1qz7qM5Wfd+gOQqUzQW4gxKqKN3KpE/P3+zrA==",
+      "dependencies": {
+        "@swc/core": "^1.3.61"
+      },
+      "peerDependencies": {
+        "vite": "^4"
+      }
+    },
+    "node_modules/@vscode/test-electron": {
+      "version": "2.2.2",
+      "resolved": "https://registry.npmjs.org/@vscode/test-electron/-/test-electron-2.2.2.tgz",
+      "integrity": "sha512-s5d2VtMySvff0UgqkJ0BMCr1es+qREE194EAodGIefq518W53ifvv69e80l9e2MrYJEqUUKwukE/w3H9o15YEw==",
+      "dev": true,
+      "dependencies": {
+        "http-proxy-agent": "^4.0.1",
+        "https-proxy-agent": "^5.0.0",
+        "rimraf": "^3.0.2",
+        "unzipper": "^0.10.11"
+      },
+      "engines": {
+        "node": ">=16"
+      }
+    },
+    "node_modules/abbrev": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
+      "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q=="
+    },
+    "node_modules/acorn": {
+      "version": "8.8.1",
+      "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz",
+      "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==",
+      "dev": true,
+      "bin": {
+        "acorn": "bin/acorn"
+      },
+      "engines": {
+        "node": ">=0.4.0"
+      }
+    },
+    "node_modules/acorn-jsx": {
+      "version": "5.3.2",
+      "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
+      "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
+      "dev": true,
+      "peerDependencies": {
+        "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
       }
     },
-    "node_modules/@szmarczak/http-timer": {
-      "version": "4.0.6",
-      "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz",
-      "integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==",
+    "node_modules/agent-base": {
+      "version": "6.0.2",
+      "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
+      "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
       "dependencies": {
-        "defer-to-connect": "^2.0.0"
+        "debug": "4"
       },
       "engines": {
-        "node": ">=10"
+        "node": ">= 6.0.0"
       }
     },
-    "node_modules/@tootallnate/once": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz",
-      "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==",
-      "dev": true,
+    "node_modules/agentkeepalive": {
+      "version": "4.2.1",
+      "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.2.1.tgz",
+      "integrity": "sha512-Zn4cw2NEqd+9fiSVWMscnjyQ1a8Yfoc5oBajLeo5w+YBHgDUcEBY2hS4YpTz6iN5f/2zQiktcuM6tS8x1p9dpA==",
+      "dependencies": {
+        "debug": "^4.1.0",
+        "depd": "^1.1.2",
+        "humanize-ms": "^1.2.1"
+      },
       "engines": {
-        "node": ">= 6"
+        "node": ">= 8.0.0"
       }
     },
-    "node_modules/@types/cacheable-request": {
-      "version": "6.0.3",
-      "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz",
-      "integrity": "sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==",
+    "node_modules/aggregate-error": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz",
+      "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==",
       "dependencies": {
-        "@types/http-cache-semantics": "*",
-        "@types/keyv": "^3.1.4",
-        "@types/node": "*",
-        "@types/responselike": "^1.0.0"
+        "clean-stack": "^2.0.0",
+        "indent-string": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
       }
     },
-    "node_modules/@types/debug": {
-      "version": "4.1.8",
-      "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.8.tgz",
-      "integrity": "sha512-/vPO1EPOs306Cvhwv7KfVfYvOJqA/S/AXjaHQiJboCZzcNDb+TIJFN9/2C9DZ//ijSKWioNyUxD792QmDJ+HKQ==",
+    "node_modules/ajv": {
+      "version": "6.12.6",
+      "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
+      "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
+      "dev": true,
       "dependencies": {
-        "@types/ms": "*"
+        "fast-deep-equal": "^3.1.1",
+        "fast-json-stable-stringify": "^2.0.0",
+        "json-schema-traverse": "^0.4.1",
+        "uri-js": "^4.2.2"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/epoberezkin"
       }
     },
-    "node_modules/@types/glob": {
-      "version": "8.0.0",
-      "resolved": "https://registry.npmjs.org/@types/glob/-/glob-8.0.0.tgz",
-      "integrity": "sha512-l6NQsDDyQUVeoTynNpC9uRvCUint/gSUXQA2euwmTuWGvPY5LSDUu6tkCtJB2SvGQlJQzLaKqcGZP4//7EDveA==",
+    "node_modules/ansi-colors": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz",
+      "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==",
       "dev": true,
-      "dependencies": {
-        "@types/minimatch": "*",
-        "@types/node": "*"
+      "engines": {
+        "node": ">=6"
       }
     },
-    "node_modules/@types/hast": {
-      "version": "2.3.4",
-      "resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.4.tgz",
-      "integrity": "sha512-wLEm0QvaoawEDoTRwzTXp4b4jpwiJDvR5KMnFnVodm3scufTlBOWRD6N1OBf9TZMhjlNsSfcO5V+7AF4+Vy+9g==",
+    "node_modules/ansi-escapes": {
+      "version": "4.3.2",
+      "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz",
+      "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==",
+      "dev": true,
       "dependencies": {
-        "@types/unist": "*"
+        "type-fest": "^0.21.3"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
       }
     },
-    "node_modules/@types/hoist-non-react-statics": {
-      "version": "3.3.1",
-      "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz",
-      "integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==",
-      "dependencies": {
-        "@types/react": "*",
-        "hoist-non-react-statics": "^3.3.0"
+    "node_modules/ansi-escapes/node_modules/type-fest": {
+      "version": "0.21.3",
+      "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz",
+      "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==",
+      "dev": true,
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
       }
     },
-    "node_modules/@types/http-cache-semantics": {
-      "version": "4.0.1",
-      "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.1.tgz",
-      "integrity": "sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ=="
-    },
-    "node_modules/@types/json-schema": {
-      "version": "7.0.11",
-      "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz",
-      "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==",
-      "dev": true
-    },
-    "node_modules/@types/keyv": {
-      "version": "3.1.4",
-      "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz",
-      "integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==",
-      "dependencies": {
-        "@types/node": "*"
+    "node_modules/ansi-regex": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz",
+      "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==",
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-regex?sponsor=1"
       }
     },
-    "node_modules/@types/lodash": {
-      "version": "4.14.191",
-      "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.191.tgz",
-      "integrity": "sha512-BdZ5BCCvho3EIXw6wUCXHe7rS53AIDPLE+JzwgT+OsJk53oBfbSmZZ7CX4VaRoN78N+TJpFi9QPlfIVNmJYWxQ==",
-      "dev": true
-    },
-    "node_modules/@types/mdast": {
-      "version": "3.0.11",
-      "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.11.tgz",
-      "integrity": "sha512-Y/uImid8aAwrEA24/1tcRZwpxX3pIFTSilcNDKSPn+Y2iDywSEachzRuvgAYYLR3wpGXAsMbv5lvKLDZLeYPAw==",
+    "node_modules/ansi-styles": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
       "dependencies": {
-        "@types/unist": "*"
+        "color-convert": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
       }
     },
-    "node_modules/@types/minimatch": {
-      "version": "5.1.2",
-      "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz",
-      "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==",
-      "dev": true
-    },
-    "node_modules/@types/mocha": {
-      "version": "10.0.1",
-      "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.1.tgz",
-      "integrity": "sha512-/fvYntiO1GeICvqbQ3doGDIP97vWmvFt83GKguJ6prmQM2iXZfFcq6YE8KteFyRtX2/h5Hf91BYvPodJKFYv5Q==",
-      "dev": true
-    },
-    "node_modules/@types/ms": {
-      "version": "0.7.31",
-      "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.31.tgz",
-      "integrity": "sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA=="
-    },
-    "node_modules/@types/node": {
-      "version": "16.18.11",
-      "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.11.tgz",
-      "integrity": "sha512-3oJbGBUWuS6ahSnEq1eN2XrCyf4YsWI8OyCvo7c64zQJNplk3mO84t53o8lfTk+2ji59g5ycfc6qQ3fdHliHuA=="
-    },
-    "node_modules/@types/node-fetch": {
-      "version": "2.6.2",
-      "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.2.tgz",
-      "integrity": "sha512-DHqhlq5jeESLy19TYhLakJ07kNumXWjcDdxXsLUMJZ6ue8VZJj4kLPQVE/2mdHh3xZziNF1xppu5lwmS53HR+A==",
-      "dev": true,
-      "dependencies": {
-        "@types/node": "*",
-        "form-data": "^3.0.0"
-      }
+    "node_modules/any-promise": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz",
+      "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A=="
     },
-    "node_modules/@types/node-fetch/node_modules/form-data": {
-      "version": "3.0.1",
-      "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz",
-      "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==",
-      "dev": true,
+    "node_modules/anymatch": {
+      "version": "3.1.3",
+      "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
+      "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
       "dependencies": {
-        "asynckit": "^0.4.0",
-        "combined-stream": "^1.0.8",
-        "mime-types": "^2.1.12"
+        "normalize-path": "^3.0.0",
+        "picomatch": "^2.0.4"
       },
       "engines": {
-        "node": ">= 6"
+        "node": ">= 8"
       }
     },
-    "node_modules/@types/prettier": {
-      "version": "2.7.2",
-      "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.2.tgz",
-      "integrity": "sha512-KufADq8uQqo1pYKVIYzfKbJfBAc0sOeXqGbFaSpv8MRmC/zXgowNZmFcbngndGk922QDmOASEXUZCaY48gs4cg==",
-      "dev": true
-    },
-    "node_modules/@types/prop-types": {
-      "version": "15.7.5",
-      "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz",
-      "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w=="
-    },
-    "node_modules/@types/react": {
-      "version": "18.0.28",
-      "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.28.tgz",
-      "integrity": "sha512-RD0ivG1kEztNBdoAK7lekI9M+azSnitIn85h4iOiaLjaTrMjzslhaqCGaI4IyCJ1RljWiLCEu4jyrLLgqxBTew==",
-      "dependencies": {
-        "@types/prop-types": "*",
-        "@types/scheduler": "*",
-        "csstype": "^3.0.2"
-      }
+    "node_modules/aproba": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz",
+      "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ=="
     },
-    "node_modules/@types/react-dom": {
-      "version": "18.2.4",
-      "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.4.tgz",
-      "integrity": "sha512-G2mHoTMTL4yoydITgOGwWdWMVd8sNgyEP85xVmMKAPUBwQWm9wBPQUmvbeF4V3WBY1P7mmL4BkjQ0SqUpf1snw==",
-      "devOptional": true,
+    "node_modules/are-we-there-yet": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz",
+      "integrity": "sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==",
       "dependencies": {
-        "@types/react": "*"
+        "delegates": "^1.0.0",
+        "readable-stream": "^3.6.0"
+      },
+      "engines": {
+        "node": "^12.13.0 || ^14.15.0 || >=16.0.0"
       }
     },
-    "node_modules/@types/responselike": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.0.tgz",
-      "integrity": "sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==",
+    "node_modules/are-we-there-yet/node_modules/readable-stream": {
+      "version": "3.6.0",
+      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
+      "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
       "dependencies": {
-        "@types/node": "*"
+        "inherits": "^2.0.3",
+        "string_decoder": "^1.1.1",
+        "util-deprecate": "^1.0.1"
+      },
+      "engines": {
+        "node": ">= 6"
       }
     },
-    "node_modules/@types/scheduler": {
-      "version": "0.16.2",
-      "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz",
-      "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew=="
+    "node_modules/arg": {
+      "version": "5.0.2",
+      "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz",
+      "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg=="
     },
-    "node_modules/@types/semver": {
-      "version": "7.3.13",
-      "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz",
-      "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==",
+    "node_modules/argparse": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+      "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
       "dev": true
     },
-    "node_modules/@types/styled-components": {
-      "version": "5.1.26",
-      "resolved": "https://registry.npmjs.org/@types/styled-components/-/styled-components-5.1.26.tgz",
-      "integrity": "sha512-KuKJ9Z6xb93uJiIyxo/+ksS7yLjS1KzG6iv5i78dhVg/X3u5t1H7juRWqVmodIdz6wGVaIApo1u01kmFRdJHVw==",
+    "node_modules/array-union": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
+      "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
       "dev": true,
-      "dependencies": {
-        "@types/hoist-non-react-statics": "*",
-        "@types/react": "*",
-        "csstype": "^3.0.2"
+      "engines": {
+        "node": ">=8"
       }
     },
-    "node_modules/@types/unist": {
-      "version": "2.0.6",
-      "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.6.tgz",
-      "integrity": "sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ=="
+    "node_modules/arrify": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/arrify/-/arrify-3.0.0.tgz",
+      "integrity": "sha512-tLkvA81vQG/XqE2mjDkGQHoOINtMHtysSnemrmoGe6PydDPMRbVugqyk4A6V/WDWEfm3l+0d8anA9r8cv/5Jaw==",
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
     },
-    "node_modules/@types/use-sync-external-store": {
-      "version": "0.0.3",
-      "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz",
-      "integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA=="
+    "node_modules/asynckit": {
+      "version": "0.4.0",
+      "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
+      "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
     },
-    "node_modules/@types/vscode": {
-      "version": "1.60.0",
-      "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.60.0.tgz",
-      "integrity": "sha512-wZt3VTmzYrgZ0l/3QmEbCq4KAJ71K3/hmMQ/nfpv84oH8e81KKwPEoQ5v8dNCxfHFVJ1JabHKmCvqdYOoVm1Ow==",
-      "dev": true
+    "node_modules/axios": {
+      "version": "1.2.5",
+      "resolved": "https://registry.npmjs.org/axios/-/axios-1.2.5.tgz",
+      "integrity": "sha512-9pU/8mmjSSOb4CXVsvGIevN+MlO/t9OWtKadTaLuN85Gge3HGorUckgp8A/2FH4V4hJ7JuQ3LIeI7KAV9ITZrQ==",
+      "dependencies": {
+        "follow-redirects": "^1.15.0",
+        "form-data": "^4.0.0",
+        "proxy-from-env": "^1.1.0"
+      }
     },
-    "node_modules/@types/ws": {
-      "version": "8.5.4",
-      "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.4.tgz",
-      "integrity": "sha512-zdQDHKUgcX/zBc4GrwsE/7dVdAD8JR4EuiAXiiUhhfyIJXXb2+PrGshFyeXWQPMmmZ2XxgaqclgpIC7eTXc1mg==",
+    "node_modules/azure-devops-node-api": {
+      "version": "11.2.0",
+      "resolved": "https://registry.npmjs.org/azure-devops-node-api/-/azure-devops-node-api-11.2.0.tgz",
+      "integrity": "sha512-XdiGPhrpaT5J8wdERRKs5g8E0Zy1pvOYTli7z9E8nmOn3YGp4FhtjhrOyFmX/8veWCwdI69mCHKJw6l+4J/bHA==",
       "dev": true,
       "dependencies": {
-        "@types/node": "*"
+        "tunnel": "0.0.6",
+        "typed-rest-client": "^1.8.4"
       }
     },
-    "node_modules/@typescript-eslint/eslint-plugin": {
-      "version": "5.48.2",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.48.2.tgz",
-      "integrity": "sha512-sR0Gja9Ky1teIq4qJOl0nC+Tk64/uYdX+mi+5iB//MH8gwyx8e3SOyhEzeLZEFEEfCaLf8KJq+Bd/6je1t+CAg==",
+    "node_modules/babel-jest": {
+      "version": "29.5.0",
+      "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.5.0.tgz",
+      "integrity": "sha512-mA4eCDh5mSo2EcA9xQjVTpmbbNk32Zb3Q3QFQsNhaK56Q+yoXowzFodLux30HRgyOho5rsQ6B0P9QpMkvvnJ0Q==",
       "dev": true,
       "dependencies": {
-        "@typescript-eslint/scope-manager": "5.48.2",
-        "@typescript-eslint/type-utils": "5.48.2",
-        "@typescript-eslint/utils": "5.48.2",
-        "debug": "^4.3.4",
-        "ignore": "^5.2.0",
-        "natural-compare-lite": "^1.4.0",
-        "regexpp": "^3.2.0",
-        "semver": "^7.3.7",
-        "tsutils": "^3.21.0"
+        "@jest/transform": "^29.5.0",
+        "@types/babel__core": "^7.1.14",
+        "babel-plugin-istanbul": "^6.1.1",
+        "babel-preset-jest": "^29.5.0",
+        "chalk": "^4.0.0",
+        "graceful-fs": "^4.2.9",
+        "slash": "^3.0.0"
       },
       "engines": {
-        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
-      },
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/typescript-eslint"
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
       },
       "peerDependencies": {
-        "@typescript-eslint/parser": "^5.0.0",
-        "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0"
-      },
-      "peerDependenciesMeta": {
-        "typescript": {
-          "optional": true
-        }
+        "@babel/core": "^7.8.0"
       }
     },
-    "node_modules/@typescript-eslint/parser": {
-      "version": "5.48.2",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.48.2.tgz",
-      "integrity": "sha512-38zMsKsG2sIuM5Oi/olurGwYJXzmtdsHhn5mI/pQogP+BjYVkK5iRazCQ8RGS0V+YLk282uWElN70zAAUmaYHw==",
+    "node_modules/babel-plugin-istanbul": {
+      "version": "6.1.1",
+      "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz",
+      "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==",
       "dev": true,
       "dependencies": {
-        "@typescript-eslint/scope-manager": "5.48.2",
-        "@typescript-eslint/types": "5.48.2",
-        "@typescript-eslint/typescript-estree": "5.48.2",
-        "debug": "^4.3.4"
+        "@babel/helper-plugin-utils": "^7.0.0",
+        "@istanbuljs/load-nyc-config": "^1.0.0",
+        "@istanbuljs/schema": "^0.1.2",
+        "istanbul-lib-instrument": "^5.0.4",
+        "test-exclude": "^6.0.0"
       },
       "engines": {
-        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
-      },
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/typescript-eslint"
-      },
-      "peerDependencies": {
-        "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0"
-      },
-      "peerDependenciesMeta": {
-        "typescript": {
-          "optional": true
-        }
+        "node": ">=8"
       }
     },
-    "node_modules/@typescript-eslint/scope-manager": {
-      "version": "5.48.2",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.48.2.tgz",
-      "integrity": "sha512-zEUFfonQid5KRDKoI3O+uP1GnrFd4tIHlvs+sTJXiWuypUWMuDaottkJuR612wQfOkjYbsaskSIURV9xo4f+Fw==",
+    "node_modules/babel-plugin-jest-hoist": {
+      "version": "29.5.0",
+      "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.5.0.tgz",
+      "integrity": "sha512-zSuuuAlTMT4mzLj2nPnUm6fsE6270vdOfnpbJ+RmruU75UhLFvL0N2NgI7xpeS7NaB6hGqmd5pVpGTDYvi4Q3w==",
       "dev": true,
       "dependencies": {
-        "@typescript-eslint/types": "5.48.2",
-        "@typescript-eslint/visitor-keys": "5.48.2"
+        "@babel/template": "^7.3.3",
+        "@babel/types": "^7.3.3",
+        "@types/babel__core": "^7.1.14",
+        "@types/babel__traverse": "^7.0.6"
       },
       "engines": {
-        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
-      },
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/typescript-eslint"
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
       }
     },
-    "node_modules/@typescript-eslint/type-utils": {
-      "version": "5.48.2",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.48.2.tgz",
-      "integrity": "sha512-QVWx7J5sPMRiOMJp5dYshPxABRoZV1xbRirqSk8yuIIsu0nvMTZesKErEA3Oix1k+uvsk8Cs8TGJ6kQ0ndAcew==",
-      "dev": true,
+    "node_modules/babel-plugin-styled-components": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/babel-plugin-styled-components/-/babel-plugin-styled-components-2.1.1.tgz",
+      "integrity": "sha512-c8lJlszObVQPguHkI+akXv8+Jgb9Ccujx0EetL7oIvwU100LxO6XAGe45qry37wUL40a5U9f23SYrivro2XKhA==",
+      "peer": true,
       "dependencies": {
-        "@typescript-eslint/typescript-estree": "5.48.2",
-        "@typescript-eslint/utils": "5.48.2",
-        "debug": "^4.3.4",
-        "tsutils": "^3.21.0"
-      },
-      "engines": {
-        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
-      },
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/typescript-eslint"
+        "@babel/helper-annotate-as-pure": "^7.16.0",
+        "@babel/helper-module-imports": "^7.16.0",
+        "babel-plugin-syntax-jsx": "^6.18.0",
+        "lodash": "^4.17.21",
+        "picomatch": "^2.3.0"
       },
       "peerDependencies": {
-        "eslint": "*"
-      },
-      "peerDependenciesMeta": {
-        "typescript": {
-          "optional": true
-        }
+        "styled-components": ">= 2"
       }
     },
-    "node_modules/@typescript-eslint/types": {
-      "version": "5.48.2",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.48.2.tgz",
-      "integrity": "sha512-hE7dA77xxu7ByBc6KCzikgfRyBCTst6dZQpwaTy25iMYOnbNljDT4hjhrGEJJ0QoMjrfqrx+j1l1B9/LtKeuqA==",
-      "dev": true,
-      "engines": {
-        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+    "node_modules/babel-plugin-syntax-jsx": {
+      "version": "6.18.0",
+      "resolved": "https://registry.npmjs.org/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz",
+      "integrity": "sha512-qrPaCSo9c8RHNRHIotaufGbuOBN8rtdC4QrrFFc43vyWCCz7Kl7GL1PGaXtMGQZUXrkCjNEgxDfmAuAabr/rlw==",
+      "peer": true
+    },
+    "node_modules/babel-preset-current-node-syntax": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz",
+      "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==",
+      "dev": true,
+      "dependencies": {
+        "@babel/plugin-syntax-async-generators": "^7.8.4",
+        "@babel/plugin-syntax-bigint": "^7.8.3",
+        "@babel/plugin-syntax-class-properties": "^7.8.3",
+        "@babel/plugin-syntax-import-meta": "^7.8.3",
+        "@babel/plugin-syntax-json-strings": "^7.8.3",
+        "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3",
+        "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3",
+        "@babel/plugin-syntax-numeric-separator": "^7.8.3",
+        "@babel/plugin-syntax-object-rest-spread": "^7.8.3",
+        "@babel/plugin-syntax-optional-catch-binding": "^7.8.3",
+        "@babel/plugin-syntax-optional-chaining": "^7.8.3",
+        "@babel/plugin-syntax-top-level-await": "^7.8.3"
       },
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/typescript-eslint"
+      "peerDependencies": {
+        "@babel/core": "^7.0.0"
       }
     },
-    "node_modules/@typescript-eslint/typescript-estree": {
-      "version": "5.48.2",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.48.2.tgz",
-      "integrity": "sha512-bibvD3z6ilnoVxUBFEgkO0k0aFvUc4Cttt0dAreEr+nrAHhWzkO83PEVVuieK3DqcgL6VAK5dkzK8XUVja5Zcg==",
+    "node_modules/babel-preset-jest": {
+      "version": "29.5.0",
+      "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.5.0.tgz",
+      "integrity": "sha512-JOMloxOqdiBSxMAzjRaH023/vvcaSaec49zvg+2LmNsktC7ei39LTJGw02J+9uUtTZUq6xbLyJ4dxe9sSmIuAg==",
       "dev": true,
       "dependencies": {
-        "@typescript-eslint/types": "5.48.2",
-        "@typescript-eslint/visitor-keys": "5.48.2",
-        "debug": "^4.3.4",
-        "globby": "^11.1.0",
-        "is-glob": "^4.0.3",
-        "semver": "^7.3.7",
-        "tsutils": "^3.21.0"
+        "babel-plugin-jest-hoist": "^29.5.0",
+        "babel-preset-current-node-syntax": "^1.0.0"
       },
       "engines": {
-        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
       },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0"
+      }
+    },
+    "node_modules/bail": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz",
+      "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==",
       "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/typescript-eslint"
-      },
-      "peerDependenciesMeta": {
-        "typescript": {
-          "optional": true
+        "type": "github",
+        "url": "https://github.com/sponsors/wooorm"
+      }
+    },
+    "node_modules/balanced-match": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+      "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
+    },
+    "node_modules/base64-js": {
+      "version": "1.5.1",
+      "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
+      "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
         }
+      ]
+    },
+    "node_modules/big-integer": {
+      "version": "1.6.51",
+      "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz",
+      "integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.6"
       }
     },
-    "node_modules/@typescript-eslint/utils": {
-      "version": "5.48.2",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.48.2.tgz",
-      "integrity": "sha512-2h18c0d7jgkw6tdKTlNaM7wyopbLRBiit8oAxoP89YnuBOzCZ8g8aBCaCqq7h208qUTroL7Whgzam7UY3HVLow==",
+    "node_modules/binary": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/binary/-/binary-0.3.0.tgz",
+      "integrity": "sha512-D4H1y5KYwpJgK8wk1Cue5LLPgmwHKYSChkbspQg5JtVuR5ulGckxfR62H3AE9UDkdMC8yyXlqYihuz3Aqg2XZg==",
       "dev": true,
       "dependencies": {
-        "@types/json-schema": "^7.0.9",
-        "@types/semver": "^7.3.12",
-        "@typescript-eslint/scope-manager": "5.48.2",
-        "@typescript-eslint/types": "5.48.2",
-        "@typescript-eslint/typescript-estree": "5.48.2",
-        "eslint-scope": "^5.1.1",
-        "eslint-utils": "^3.0.0",
-        "semver": "^7.3.7"
+        "buffers": "~0.1.1",
+        "chainsaw": "~0.1.0"
       },
       "engines": {
-        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
-      },
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/typescript-eslint"
-      },
-      "peerDependencies": {
-        "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0"
+        "node": "*"
       }
     },
-    "node_modules/@typescript-eslint/visitor-keys": {
-      "version": "5.48.2",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.48.2.tgz",
-      "integrity": "sha512-z9njZLSkwmjFWUelGEwEbdf4NwKvfHxvGC0OcGN1Hp/XNDIcJ7D5DpPNPv6x6/mFvc1tQHsaWmpD/a4gOvvCJQ==",
-      "dev": true,
+    "node_modules/binary-extensions": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
+      "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/bl": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
+      "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==",
       "dependencies": {
-        "@typescript-eslint/types": "5.48.2",
-        "eslint-visitor-keys": "^3.3.0"
+        "buffer": "^5.5.0",
+        "inherits": "^2.0.4",
+        "readable-stream": "^3.4.0"
+      }
+    },
+    "node_modules/bl/node_modules/readable-stream": {
+      "version": "3.6.0",
+      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
+      "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+      "dependencies": {
+        "inherits": "^2.0.3",
+        "string_decoder": "^1.1.1",
+        "util-deprecate": "^1.0.1"
       },
       "engines": {
-        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
-      },
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/typescript-eslint"
+        "node": ">= 6"
       }
     },
-    "node_modules/@vitejs/plugin-react-swc": {
-      "version": "3.3.2",
-      "resolved": "https://registry.npmjs.org/@vitejs/plugin-react-swc/-/plugin-react-swc-3.3.2.tgz",
-      "integrity": "sha512-VJFWY5sfoZerQRvJrh518h3AcQt6f/yTuWn4/TRB+dqmYU0NX1qz7qM5Wfd+gOQqUzQW4gxKqKN3KpE/P3+zrA==",
+    "node_modules/bluebird": {
+      "version": "3.4.7",
+      "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.7.tgz",
+      "integrity": "sha512-iD3898SR7sWVRHbiQv+sHUtHnMvC1o3nW5rAcqnq3uOn07DSAppZYUkIGslDz6gXC7HfunPe7YVBgoEJASPcHA==",
+      "dev": true
+    },
+    "node_modules/boolbase": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
+      "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==",
+      "dev": true
+    },
+    "node_modules/brace-expansion": {
+      "version": "1.1.11",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+      "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
       "dependencies": {
-        "@swc/core": "^1.3.61"
-      },
-      "peerDependencies": {
-        "vite": "^4"
+        "balanced-match": "^1.0.0",
+        "concat-map": "0.0.1"
       }
     },
-    "node_modules/@vscode/test-electron": {
-      "version": "2.2.2",
-      "resolved": "https://registry.npmjs.org/@vscode/test-electron/-/test-electron-2.2.2.tgz",
-      "integrity": "sha512-s5d2VtMySvff0UgqkJ0BMCr1es+qREE194EAodGIefq518W53ifvv69e80l9e2MrYJEqUUKwukE/w3H9o15YEw==",
-      "dev": true,
+    "node_modules/braces": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
+      "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
       "dependencies": {
-        "http-proxy-agent": "^4.0.1",
-        "https-proxy-agent": "^5.0.0",
-        "rimraf": "^3.0.2",
-        "unzipper": "^0.10.11"
+        "fill-range": "^7.0.1"
       },
       "engines": {
-        "node": ">=16"
+        "node": ">=8"
       }
     },
-    "node_modules/abbrev": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
-      "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q=="
+    "node_modules/browser-stdout": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz",
+      "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==",
+      "dev": true
     },
-    "node_modules/acorn": {
-      "version": "8.8.1",
-      "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz",
-      "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==",
+    "node_modules/browserslist": {
+      "version": "4.21.9",
+      "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.9.tgz",
+      "integrity": "sha512-M0MFoZzbUrRU4KNfCrDLnvyE7gub+peetoTid3TBIqtunaDJyXlwhakT+/VkvSXcfIzFfK/nkCs4nmyTmxdNSg==",
       "dev": true,
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/browserslist"
+        },
+        {
+          "type": "tidelift",
+          "url": "https://tidelift.com/funding/github/npm/browserslist"
+        },
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
+      "dependencies": {
+        "caniuse-lite": "^1.0.30001503",
+        "electron-to-chromium": "^1.4.431",
+        "node-releases": "^2.0.12",
+        "update-browserslist-db": "^1.0.11"
+      },
       "bin": {
-        "acorn": "bin/acorn"
+        "browserslist": "cli.js"
       },
       "engines": {
-        "node": ">=0.4.0"
+        "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
       }
     },
-    "node_modules/acorn-jsx": {
-      "version": "5.3.2",
-      "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
-      "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
+    "node_modules/bs-logger": {
+      "version": "0.2.6",
+      "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz",
+      "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==",
       "dev": true,
-      "peerDependencies": {
-        "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
-      }
-    },
-    "node_modules/agent-base": {
-      "version": "6.0.2",
-      "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
-      "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
       "dependencies": {
-        "debug": "4"
+        "fast-json-stable-stringify": "2.x"
       },
       "engines": {
-        "node": ">= 6.0.0"
+        "node": ">= 6"
       }
     },
-    "node_modules/agentkeepalive": {
-      "version": "4.2.1",
-      "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.2.1.tgz",
-      "integrity": "sha512-Zn4cw2NEqd+9fiSVWMscnjyQ1a8Yfoc5oBajLeo5w+YBHgDUcEBY2hS4YpTz6iN5f/2zQiktcuM6tS8x1p9dpA==",
+    "node_modules/bser": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz",
+      "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==",
+      "dev": true,
       "dependencies": {
-        "debug": "^4.1.0",
-        "depd": "^1.1.2",
-        "humanize-ms": "^1.2.1"
-      },
-      "engines": {
-        "node": ">= 8.0.0"
+        "node-int64": "^0.4.0"
       }
     },
-    "node_modules/aggregate-error": {
-      "version": "3.1.0",
-      "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz",
-      "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==",
+    "node_modules/buffer": {
+      "version": "5.7.1",
+      "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
+      "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ],
       "dependencies": {
-        "clean-stack": "^2.0.0",
-        "indent-string": "^4.0.0"
-      },
-      "engines": {
-        "node": ">=8"
+        "base64-js": "^1.3.1",
+        "ieee754": "^1.1.13"
       }
     },
-    "node_modules/ajv": {
-      "version": "6.12.6",
-      "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
-      "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
+    "node_modules/buffer-crc32": {
+      "version": "0.2.13",
+      "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
+      "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==",
       "dev": true,
-      "dependencies": {
-        "fast-deep-equal": "^3.1.1",
-        "fast-json-stable-stringify": "^2.0.0",
-        "json-schema-traverse": "^0.4.1",
-        "uri-js": "^4.2.2"
-      },
-      "funding": {
-        "type": "github",
-        "url": "https://github.com/sponsors/epoberezkin"
+      "engines": {
+        "node": "*"
       }
     },
-    "node_modules/ansi-colors": {
-      "version": "4.1.1",
-      "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz",
-      "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==",
+    "node_modules/buffer-from": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
+      "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
+      "dev": true
+    },
+    "node_modules/buffer-indexof-polyfill": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/buffer-indexof-polyfill/-/buffer-indexof-polyfill-1.0.2.tgz",
+      "integrity": "sha512-I7wzHwA3t1/lwXQh+A5PbNvJxgfo5r3xulgpYDB5zckTu/Z9oUK9biouBKQUjEqzaz3HnAT6TYoovmE+GqSf7A==",
       "dev": true,
       "engines": {
-        "node": ">=6"
+        "node": ">=0.10"
       }
     },
-    "node_modules/ansi-escapes": {
-      "version": "4.3.2",
-      "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz",
-      "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==",
+    "node_modules/buffers": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz",
+      "integrity": "sha512-9q/rDEGSb/Qsvv2qvzIzdluL5k7AaJOTrw23z9reQthrbF7is4CtlT0DXyO1oei2DCp4uojjzQ7igaSHp1kAEQ==",
       "dev": true,
-      "dependencies": {
-        "type-fest": "^0.21.3"
-      },
       "engines": {
-        "node": ">=8"
+        "node": ">=0.2.0"
+      }
+    },
+    "node_modules/cacache": {
+      "version": "16.1.3",
+      "resolved": "https://registry.npmjs.org/cacache/-/cacache-16.1.3.tgz",
+      "integrity": "sha512-/+Emcj9DAXxX4cwlLmRI9c166RuL3w30zp4R7Joiv2cQTtTtA+jeuCAjH3ZlGnYS3tKENSrKhAzVVP9GVyzeYQ==",
+      "dependencies": {
+        "@npmcli/fs": "^2.1.0",
+        "@npmcli/move-file": "^2.0.0",
+        "chownr": "^2.0.0",
+        "fs-minipass": "^2.1.0",
+        "glob": "^8.0.1",
+        "infer-owner": "^1.0.4",
+        "lru-cache": "^7.7.1",
+        "minipass": "^3.1.6",
+        "minipass-collect": "^1.0.2",
+        "minipass-flush": "^1.0.5",
+        "minipass-pipeline": "^1.2.4",
+        "mkdirp": "^1.0.4",
+        "p-map": "^4.0.0",
+        "promise-inflight": "^1.0.1",
+        "rimraf": "^3.0.2",
+        "ssri": "^9.0.0",
+        "tar": "^6.1.11",
+        "unique-filename": "^2.0.0"
       },
-      "funding": {
-        "url": "https://github.com/sponsors/sindresorhus"
-      }
-    },
-    "node_modules/ansi-escapes/node_modules/type-fest": {
-      "version": "0.21.3",
-      "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz",
-      "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==",
-      "dev": true,
       "engines": {
-        "node": ">=10"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/sindresorhus"
+        "node": "^12.13.0 || ^14.15.0 || >=16.0.0"
       }
     },
-    "node_modules/ansi-regex": {
-      "version": "6.0.1",
-      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz",
-      "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==",
+    "node_modules/cacache/node_modules/lru-cache": {
+      "version": "7.14.1",
+      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.14.1.tgz",
+      "integrity": "sha512-ysxwsnTKdAx96aTRdhDOCQfDgbHnt8SK0KY8SEjO0wHinhWOFTESbjVCMPbU1uGXg/ch4lifqx0wfjOawU2+WA==",
       "engines": {
         "node": ">=12"
-      },
-      "funding": {
-        "url": "https://github.com/chalk/ansi-regex?sponsor=1"
       }
     },
-    "node_modules/ansi-styles": {
-      "version": "4.3.0",
-      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
-      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
-      "dependencies": {
-        "color-convert": "^2.0.1"
+    "node_modules/cacache/node_modules/mkdirp": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
+      "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
+      "bin": {
+        "mkdirp": "bin/cmd.js"
       },
       "engines": {
-        "node": ">=8"
-      },
-      "funding": {
-        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+        "node": ">=10"
       }
     },
-    "node_modules/any-promise": {
-      "version": "1.3.0",
-      "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz",
-      "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A=="
-    },
-    "node_modules/anymatch": {
-      "version": "3.1.3",
-      "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
-      "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
-      "dependencies": {
-        "normalize-path": "^3.0.0",
-        "picomatch": "^2.0.4"
-      },
+    "node_modules/cacheable-lookup": {
+      "version": "5.0.4",
+      "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz",
+      "integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==",
       "engines": {
-        "node": ">= 8"
+        "node": ">=10.6.0"
       }
     },
-    "node_modules/aproba": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz",
-      "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ=="
-    },
-    "node_modules/are-we-there-yet": {
-      "version": "3.0.1",
-      "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz",
-      "integrity": "sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==",
+    "node_modules/cacheable-request": {
+      "version": "7.0.2",
+      "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.2.tgz",
+      "integrity": "sha512-pouW8/FmiPQbuGpkXQ9BAPv/Mo5xDGANgSNXzTzJ8DrKGuXOssM4wIQRjfanNRh3Yu5cfYPvcorqbhg2KIJtew==",
       "dependencies": {
-        "delegates": "^1.0.0",
-        "readable-stream": "^3.6.0"
+        "clone-response": "^1.0.2",
+        "get-stream": "^5.1.0",
+        "http-cache-semantics": "^4.0.0",
+        "keyv": "^4.0.0",
+        "lowercase-keys": "^2.0.0",
+        "normalize-url": "^6.0.1",
+        "responselike": "^2.0.0"
       },
       "engines": {
-        "node": "^12.13.0 || ^14.15.0 || >=16.0.0"
+        "node": ">=8"
       }
     },
-    "node_modules/are-we-there-yet/node_modules/readable-stream": {
-      "version": "3.6.0",
-      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
-      "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+    "node_modules/call-bind": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
+      "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
+      "dev": true,
       "dependencies": {
-        "inherits": "^2.0.3",
-        "string_decoder": "^1.1.1",
-        "util-deprecate": "^1.0.1"
+        "function-bind": "^1.1.1",
+        "get-intrinsic": "^1.0.2"
       },
-      "engines": {
-        "node": ">= 6"
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
       }
     },
-    "node_modules/arg": {
-      "version": "5.0.2",
-      "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz",
-      "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg=="
-    },
-    "node_modules/argparse": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
-      "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
+    "node_modules/call-me-maybe": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.2.tgz",
+      "integrity": "sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ==",
       "dev": true
     },
-    "node_modules/array-union": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
-      "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
+    "node_modules/callsites": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
+      "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
       "dev": true,
       "engines": {
-        "node": ">=8"
+        "node": ">=6"
       }
     },
-    "node_modules/arrify": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/arrify/-/arrify-3.0.0.tgz",
-      "integrity": "sha512-tLkvA81vQG/XqE2mjDkGQHoOINtMHtysSnemrmoGe6PydDPMRbVugqyk4A6V/WDWEfm3l+0d8anA9r8cv/5Jaw==",
+    "node_modules/camelcase": {
+      "version": "6.3.0",
+      "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz",
+      "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==",
+      "dev": true,
       "engines": {
-        "node": ">=12"
+        "node": ">=10"
       },
       "funding": {
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
-    "node_modules/asynckit": {
-      "version": "0.4.0",
-      "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
-      "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
-    },
-    "node_modules/axios": {
-      "version": "1.2.5",
-      "resolved": "https://registry.npmjs.org/axios/-/axios-1.2.5.tgz",
-      "integrity": "sha512-9pU/8mmjSSOb4CXVsvGIevN+MlO/t9OWtKadTaLuN85Gge3HGorUckgp8A/2FH4V4hJ7JuQ3LIeI7KAV9ITZrQ==",
-      "dependencies": {
-        "follow-redirects": "^1.15.0",
-        "form-data": "^4.0.0",
-        "proxy-from-env": "^1.1.0"
-      }
-    },
-    "node_modules/azure-devops-node-api": {
-      "version": "11.2.0",
-      "resolved": "https://registry.npmjs.org/azure-devops-node-api/-/azure-devops-node-api-11.2.0.tgz",
-      "integrity": "sha512-XdiGPhrpaT5J8wdERRKs5g8E0Zy1pvOYTli7z9E8nmOn3YGp4FhtjhrOyFmX/8veWCwdI69mCHKJw6l+4J/bHA==",
-      "dev": true,
-      "dependencies": {
-        "tunnel": "0.0.6",
-        "typed-rest-client": "^1.8.4"
+    "node_modules/camelcase-css": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz",
+      "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==",
+      "engines": {
+        "node": ">= 6"
       }
     },
-    "node_modules/babel-plugin-styled-components": {
-      "version": "2.1.1",
-      "resolved": "https://registry.npmjs.org/babel-plugin-styled-components/-/babel-plugin-styled-components-2.1.1.tgz",
-      "integrity": "sha512-c8lJlszObVQPguHkI+akXv8+Jgb9Ccujx0EetL7oIvwU100LxO6XAGe45qry37wUL40a5U9f23SYrivro2XKhA==",
+    "node_modules/camelize": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.1.tgz",
+      "integrity": "sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==",
       "peer": true,
-      "dependencies": {
-        "@babel/helper-annotate-as-pure": "^7.16.0",
-        "@babel/helper-module-imports": "^7.16.0",
-        "babel-plugin-syntax-jsx": "^6.18.0",
-        "lodash": "^4.17.21",
-        "picomatch": "^2.3.0"
-      },
-      "peerDependencies": {
-        "styled-components": ">= 2"
-      }
-    },
-    "node_modules/babel-plugin-syntax-jsx": {
-      "version": "6.18.0",
-      "resolved": "https://registry.npmjs.org/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz",
-      "integrity": "sha512-qrPaCSo9c8RHNRHIotaufGbuOBN8rtdC4QrrFFc43vyWCCz7Kl7GL1PGaXtMGQZUXrkCjNEgxDfmAuAabr/rlw==",
-      "peer": true
-    },
-    "node_modules/bail": {
-      "version": "2.0.2",
-      "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz",
-      "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==",
       "funding": {
-        "type": "github",
-        "url": "https://github.com/sponsors/wooorm"
+        "url": "https://github.com/sponsors/ljharb"
       }
     },
-    "node_modules/balanced-match": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
-      "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
-    },
-    "node_modules/base64-js": {
-      "version": "1.5.1",
-      "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
-      "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
+    "node_modules/caniuse-lite": {
+      "version": "1.0.30001511",
+      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001511.tgz",
+      "integrity": "sha512-NaWPJawcoedlghN4P7bDNeADD7K+rZaY6V8ZcME7PkEZo/nfOg+lnrUgRWiKbNxcQ4/toFKSxnS4WdbyPZnKkw==",
+      "dev": true,
       "funding": [
         {
-          "type": "github",
-          "url": "https://github.com/sponsors/feross"
+          "type": "opencollective",
+          "url": "https://opencollective.com/browserslist"
         },
         {
-          "type": "patreon",
-          "url": "https://www.patreon.com/feross"
+          "type": "tidelift",
+          "url": "https://tidelift.com/funding/github/npm/caniuse-lite"
         },
         {
-          "type": "consulting",
-          "url": "https://feross.org/support"
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
         }
       ]
     },
-    "node_modules/big-integer": {
-      "version": "1.6.51",
-      "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz",
-      "integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==",
-      "dev": true,
-      "engines": {
-        "node": ">=0.6"
-      }
-    },
-    "node_modules/binary": {
-      "version": "0.3.0",
-      "resolved": "https://registry.npmjs.org/binary/-/binary-0.3.0.tgz",
-      "integrity": "sha512-D4H1y5KYwpJgK8wk1Cue5LLPgmwHKYSChkbspQg5JtVuR5ulGckxfR62H3AE9UDkdMC8yyXlqYihuz3Aqg2XZg==",
+    "node_modules/chainsaw": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz",
+      "integrity": "sha512-75kWfWt6MEKNC8xYXIdRpDehRYY/tNSgwKaJq+dbbDcxORuVrrQ+SEHoWsniVn9XPYfP4gmdWIeDk/4YNp1rNQ==",
       "dev": true,
       "dependencies": {
-        "buffers": "~0.1.1",
-        "chainsaw": "~0.1.0"
+        "traverse": ">=0.3.0 <0.4"
       },
       "engines": {
         "node": "*"
       }
     },
-    "node_modules/binary-extensions": {
-      "version": "2.2.0",
-      "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
-      "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
+    "node_modules/chalk": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+      "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+      "dependencies": {
+        "ansi-styles": "^4.1.0",
+        "supports-color": "^7.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/chalk?sponsor=1"
+      }
+    },
+    "node_modules/char-regex": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz",
+      "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==",
+      "dev": true,
       "engines": {
-        "node": ">=8"
+        "node": ">=10"
       }
     },
-    "node_modules/bl": {
-      "version": "4.1.0",
-      "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
-      "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==",
-      "dependencies": {
-        "buffer": "^5.5.0",
-        "inherits": "^2.0.4",
-        "readable-stream": "^3.4.0"
+    "node_modules/character-entities": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz",
+      "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/wooorm"
       }
     },
-    "node_modules/bl/node_modules/readable-stream": {
-      "version": "3.6.0",
-      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
-      "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+    "node_modules/chardet": {
+      "version": "0.7.0",
+      "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz",
+      "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==",
+      "dev": true
+    },
+    "node_modules/cheerio": {
+      "version": "1.0.0-rc.12",
+      "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz",
+      "integrity": "sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==",
+      "dev": true,
       "dependencies": {
-        "inherits": "^2.0.3",
-        "string_decoder": "^1.1.1",
-        "util-deprecate": "^1.0.1"
+        "cheerio-select": "^2.1.0",
+        "dom-serializer": "^2.0.0",
+        "domhandler": "^5.0.3",
+        "domutils": "^3.0.1",
+        "htmlparser2": "^8.0.1",
+        "parse5": "^7.0.0",
+        "parse5-htmlparser2-tree-adapter": "^7.0.0"
       },
       "engines": {
         "node": ">= 6"
+      },
+      "funding": {
+        "url": "https://github.com/cheeriojs/cheerio?sponsor=1"
       }
     },
-    "node_modules/bluebird": {
-      "version": "3.4.7",
-      "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.7.tgz",
-      "integrity": "sha512-iD3898SR7sWVRHbiQv+sHUtHnMvC1o3nW5rAcqnq3uOn07DSAppZYUkIGslDz6gXC7HfunPe7YVBgoEJASPcHA==",
-      "dev": true
-    },
-    "node_modules/boolbase": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
-      "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==",
-      "dev": true
+    "node_modules/cheerio-select": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz",
+      "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==",
+      "dev": true,
+      "dependencies": {
+        "boolbase": "^1.0.0",
+        "css-select": "^5.1.0",
+        "css-what": "^6.1.0",
+        "domelementtype": "^2.3.0",
+        "domhandler": "^5.0.3",
+        "domutils": "^3.0.1"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/fb55"
+      }
     },
-    "node_modules/brace-expansion": {
-      "version": "1.1.11",
-      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
-      "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+    "node_modules/chokidar": {
+      "version": "3.5.3",
+      "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
+      "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
+      "funding": [
+        {
+          "type": "individual",
+          "url": "https://paulmillr.com/funding/"
+        }
+      ],
       "dependencies": {
-        "balanced-match": "^1.0.0",
-        "concat-map": "0.0.1"
+        "anymatch": "~3.1.2",
+        "braces": "~3.0.2",
+        "glob-parent": "~5.1.2",
+        "is-binary-path": "~2.1.0",
+        "is-glob": "~4.0.1",
+        "normalize-path": "~3.0.0",
+        "readdirp": "~3.6.0"
+      },
+      "engines": {
+        "node": ">= 8.10.0"
+      },
+      "optionalDependencies": {
+        "fsevents": "~2.3.2"
       }
     },
-    "node_modules/braces": {
-      "version": "3.0.2",
-      "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
-      "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
+    "node_modules/chokidar/node_modules/glob-parent": {
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+      "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
       "dependencies": {
-        "fill-range": "^7.0.1"
+        "is-glob": "^4.0.1"
       },
       "engines": {
-        "node": ">=8"
+        "node": ">= 6"
       }
     },
-    "node_modules/browser-stdout": {
-      "version": "1.3.1",
-      "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz",
-      "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==",
-      "dev": true
+    "node_modules/chownr": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz",
+      "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==",
+      "engines": {
+        "node": ">=10"
+      }
     },
-    "node_modules/buffer": {
-      "version": "5.7.1",
-      "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
-      "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
+    "node_modules/ci-info": {
+      "version": "3.8.0",
+      "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz",
+      "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==",
+      "dev": true,
       "funding": [
         {
           "type": "github",
-          "url": "https://github.com/sponsors/feross"
-        },
-        {
-          "type": "patreon",
-          "url": "https://www.patreon.com/feross"
-        },
-        {
-          "type": "consulting",
-          "url": "https://feross.org/support"
+          "url": "https://github.com/sponsors/sibiraj-s"
         }
       ],
-      "dependencies": {
-        "base64-js": "^1.3.1",
-        "ieee754": "^1.1.13"
-      }
-    },
-    "node_modules/buffer-crc32": {
-      "version": "0.2.13",
-      "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
-      "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==",
-      "dev": true,
       "engines": {
-        "node": "*"
+        "node": ">=8"
       }
     },
-    "node_modules/buffer-indexof-polyfill": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/buffer-indexof-polyfill/-/buffer-indexof-polyfill-1.0.2.tgz",
-      "integrity": "sha512-I7wzHwA3t1/lwXQh+A5PbNvJxgfo5r3xulgpYDB5zckTu/Z9oUK9biouBKQUjEqzaz3HnAT6TYoovmE+GqSf7A==",
-      "dev": true,
+    "node_modules/cjs-module-lexer": {
+      "version": "1.2.3",
+      "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz",
+      "integrity": "sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==",
+      "dev": true
+    },
+    "node_modules/clean-stack": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz",
+      "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==",
       "engines": {
-        "node": ">=0.10"
+        "node": ">=6"
       }
     },
-    "node_modules/buffers": {
-      "version": "0.1.1",
-      "resolved": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz",
-      "integrity": "sha512-9q/rDEGSb/Qsvv2qvzIzdluL5k7AaJOTrw23z9reQthrbF7is4CtlT0DXyO1oei2DCp4uojjzQ7igaSHp1kAEQ==",
+    "node_modules/cli-color": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/cli-color/-/cli-color-2.0.3.tgz",
+      "integrity": "sha512-OkoZnxyC4ERN3zLzZaY9Emb7f/MhBOIpePv0Ycok0fJYT+Ouo00UBEIwsVsr0yoow++n5YWlSUgST9GKhNHiRQ==",
       "dev": true,
+      "dependencies": {
+        "d": "^1.0.1",
+        "es5-ext": "^0.10.61",
+        "es6-iterator": "^2.0.3",
+        "memoizee": "^0.4.15",
+        "timers-ext": "^0.1.7"
+      },
       "engines": {
-        "node": ">=0.2.0"
+        "node": ">=0.10"
       }
     },
-    "node_modules/cacache": {
-      "version": "16.1.3",
-      "resolved": "https://registry.npmjs.org/cacache/-/cacache-16.1.3.tgz",
-      "integrity": "sha512-/+Emcj9DAXxX4cwlLmRI9c166RuL3w30zp4R7Joiv2cQTtTtA+jeuCAjH3ZlGnYS3tKENSrKhAzVVP9GVyzeYQ==",
+    "node_modules/cli-cursor": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz",
+      "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==",
       "dependencies": {
-        "@npmcli/fs": "^2.1.0",
-        "@npmcli/move-file": "^2.0.0",
-        "chownr": "^2.0.0",
-        "fs-minipass": "^2.1.0",
-        "glob": "^8.0.1",
-        "infer-owner": "^1.0.4",
-        "lru-cache": "^7.7.1",
-        "minipass": "^3.1.6",
-        "minipass-collect": "^1.0.2",
-        "minipass-flush": "^1.0.5",
-        "minipass-pipeline": "^1.2.4",
-        "mkdirp": "^1.0.4",
-        "p-map": "^4.0.0",
-        "promise-inflight": "^1.0.1",
-        "rimraf": "^3.0.2",
-        "ssri": "^9.0.0",
-        "tar": "^6.1.11",
-        "unique-filename": "^2.0.0"
+        "restore-cursor": "^3.1.0"
       },
       "engines": {
-        "node": "^12.13.0 || ^14.15.0 || >=16.0.0"
+        "node": ">=8"
       }
     },
-    "node_modules/cacache/node_modules/lru-cache": {
-      "version": "7.14.1",
-      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.14.1.tgz",
-      "integrity": "sha512-ysxwsnTKdAx96aTRdhDOCQfDgbHnt8SK0KY8SEjO0wHinhWOFTESbjVCMPbU1uGXg/ch4lifqx0wfjOawU2+WA==",
+    "node_modules/cli-spinners": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.7.0.tgz",
+      "integrity": "sha512-qu3pN8Y3qHNgE2AFweciB1IfMnmZ/fsNTEE+NOFjmGB2F/7rLhnhzppvpCnN4FovtP26k8lHyy9ptEbNwWFLzw==",
       "engines": {
-        "node": ">=12"
+        "node": ">=6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
       }
     },
-    "node_modules/cacache/node_modules/mkdirp": {
-      "version": "1.0.4",
-      "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
-      "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
-      "bin": {
-        "mkdirp": "bin/cmd.js"
-      },
+    "node_modules/cli-width": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz",
+      "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==",
+      "dev": true,
       "engines": {
-        "node": ">=10"
+        "node": ">= 10"
       }
     },
-    "node_modules/cacheable-lookup": {
-      "version": "5.0.4",
-      "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz",
-      "integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==",
+    "node_modules/cliui": {
+      "version": "7.0.4",
+      "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
+      "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
+      "dev": true,
+      "dependencies": {
+        "string-width": "^4.2.0",
+        "strip-ansi": "^6.0.0",
+        "wrap-ansi": "^7.0.0"
+      }
+    },
+    "node_modules/cliui/node_modules/ansi-regex": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+      "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+      "dev": true,
       "engines": {
-        "node": ">=10.6.0"
+        "node": ">=8"
       }
     },
-    "node_modules/cacheable-request": {
-      "version": "7.0.2",
-      "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.2.tgz",
-      "integrity": "sha512-pouW8/FmiPQbuGpkXQ9BAPv/Mo5xDGANgSNXzTzJ8DrKGuXOssM4wIQRjfanNRh3Yu5cfYPvcorqbhg2KIJtew==",
+    "node_modules/cliui/node_modules/strip-ansi": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+      "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+      "dev": true,
       "dependencies": {
-        "clone-response": "^1.0.2",
-        "get-stream": "^5.1.0",
-        "http-cache-semantics": "^4.0.0",
-        "keyv": "^4.0.0",
-        "lowercase-keys": "^2.0.0",
-        "normalize-url": "^6.0.1",
-        "responselike": "^2.0.0"
+        "ansi-regex": "^5.0.1"
       },
       "engines": {
         "node": ">=8"
       }
     },
-    "node_modules/call-bind": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
-      "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
-      "dev": true,
+    "node_modules/clone": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz",
+      "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==",
+      "engines": {
+        "node": ">=0.8"
+      }
+    },
+    "node_modules/clone-response": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz",
+      "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==",
       "dependencies": {
-        "function-bind": "^1.1.1",
-        "get-intrinsic": "^1.0.2"
+        "mimic-response": "^1.0.0"
       },
       "funding": {
-        "url": "https://github.com/sponsors/ljharb"
+        "url": "https://github.com/sponsors/sindresorhus"
       }
     },
-    "node_modules/call-me-maybe": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.2.tgz",
-      "integrity": "sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ==",
-      "dev": true
-    },
-    "node_modules/callsites": {
-      "version": "3.1.0",
-      "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
-      "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
+    "node_modules/co": {
+      "version": "4.6.0",
+      "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
+      "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==",
       "dev": true,
       "engines": {
-        "node": ">=6"
+        "iojs": ">= 1.0.0",
+        "node": ">= 0.12.0"
       }
     },
-    "node_modules/camelcase": {
-      "version": "6.3.0",
-      "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz",
-      "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==",
-      "dev": true,
+    "node_modules/collect-v8-coverage": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz",
+      "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==",
+      "dev": true
+    },
+    "node_modules/color-convert": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "dependencies": {
+        "color-name": "~1.1.4"
+      },
       "engines": {
-        "node": ">=10"
+        "node": ">=7.0.0"
+      }
+    },
+    "node_modules/color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
+    },
+    "node_modules/color-support": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz",
+      "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==",
+      "bin": {
+        "color-support": "bin.js"
+      }
+    },
+    "node_modules/combined-stream": {
+      "version": "1.0.8",
+      "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
+      "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
+      "dependencies": {
+        "delayed-stream": "~1.0.0"
       },
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/comma-separated-tokens": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz",
+      "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==",
       "funding": {
-        "url": "https://github.com/sponsors/sindresorhus"
+        "type": "github",
+        "url": "https://github.com/sponsors/wooorm"
       }
     },
-    "node_modules/camelcase-css": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz",
-      "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==",
+    "node_modules/commander": {
+      "version": "6.2.1",
+      "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz",
+      "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==",
+      "dev": true,
       "engines": {
         "node": ">= 6"
       }
     },
-    "node_modules/camelize": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.1.tgz",
-      "integrity": "sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==",
-      "peer": true,
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
+    "node_modules/compare-versions": {
+      "version": "4.1.4",
+      "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-4.1.4.tgz",
+      "integrity": "sha512-FemMreK9xNyL8gQevsdRMrvO4lFCkQP7qbuktn1q8ndcNk1+0mz7lgE7b/sNvbhVgY4w6tMN1FDp6aADjqw2rw==",
+      "dev": true
+    },
+    "node_modules/compute-scroll-into-view": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-2.0.4.tgz",
+      "integrity": "sha512-y/ZA3BGnxoM/QHHQ2Uy49CLtnWPbt4tTPpEEZiEmmiWBFKjej7nEyH8Ryz54jH0MLXflUYA3Er2zUxPSJu5R+g=="
+    },
+    "node_modules/concat-map": {
+      "version": "0.0.1",
+      "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+      "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="
+    },
+    "node_modules/concurrently": {
+      "version": "6.5.1",
+      "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-6.5.1.tgz",
+      "integrity": "sha512-FlSwNpGjWQfRwPLXvJ/OgysbBxPkWpiVjy1042b0U7on7S7qwwMIILRj7WTN1mTgqa582bG6NFuScOoh6Zgdag==",
+      "dev": true,
+      "dependencies": {
+        "chalk": "^4.1.0",
+        "date-fns": "^2.16.1",
+        "lodash": "^4.17.21",
+        "rxjs": "^6.6.3",
+        "spawn-command": "^0.0.2-1",
+        "supports-color": "^8.1.0",
+        "tree-kill": "^1.2.2",
+        "yargs": "^16.2.0"
+      },
+      "bin": {
+        "concurrently": "bin/concurrently.js"
+      },
+      "engines": {
+        "node": ">=10.0.0"
       }
     },
-    "node_modules/chainsaw": {
-      "version": "0.1.0",
-      "resolved": "https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz",
-      "integrity": "sha512-75kWfWt6MEKNC8xYXIdRpDehRYY/tNSgwKaJq+dbbDcxORuVrrQ+SEHoWsniVn9XPYfP4gmdWIeDk/4YNp1rNQ==",
+    "node_modules/concurrently/node_modules/rxjs": {
+      "version": "6.6.7",
+      "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz",
+      "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==",
       "dev": true,
       "dependencies": {
-        "traverse": ">=0.3.0 <0.4"
+        "tslib": "^1.9.0"
       },
       "engines": {
-        "node": "*"
+        "npm": ">=2.0.0"
       }
     },
-    "node_modules/chalk": {
-      "version": "4.1.2",
-      "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
-      "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+    "node_modules/concurrently/node_modules/supports-color": {
+      "version": "8.1.1",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
+      "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
+      "dev": true,
       "dependencies": {
-        "ansi-styles": "^4.1.0",
-        "supports-color": "^7.1.0"
+        "has-flag": "^4.0.0"
       },
       "engines": {
         "node": ">=10"
       },
       "funding": {
-        "url": "https://github.com/chalk/chalk?sponsor=1"
+        "url": "https://github.com/chalk/supports-color?sponsor=1"
       }
     },
-    "node_modules/character-entities": {
-      "version": "2.0.2",
-      "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz",
-      "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==",
-      "funding": {
-        "type": "github",
-        "url": "https://github.com/sponsors/wooorm"
+    "node_modules/consola": {
+      "version": "2.15.3",
+      "resolved": "https://registry.npmjs.org/consola/-/consola-2.15.3.tgz",
+      "integrity": "sha512-9vAdYbHj6x2fLKC4+oPH0kFzY/orMZyG2Aj+kNylHxKGJ/Ed4dpNyAQYwJOdqO4zdM7XpVHmyejQDcQHrnuXbw==",
+      "dev": true
+    },
+    "node_modules/console-control-strings": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
+      "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ=="
+    },
+    "node_modules/console.table": {
+      "version": "0.10.0",
+      "resolved": "https://registry.npmjs.org/console.table/-/console.table-0.10.0.tgz",
+      "integrity": "sha512-dPyZofqggxuvSf7WXvNjuRfnsOk1YazkVP8FdxH4tcH2c37wc79/Yl6Bhr7Lsu00KMgy2ql/qCMuNu8xctZM8g==",
+      "dev": true,
+      "dependencies": {
+        "easy-table": "1.1.0"
+      },
+      "engines": {
+        "node": "> 0.10"
       }
     },
-    "node_modules/chardet": {
-      "version": "0.7.0",
-      "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz",
-      "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==",
+    "node_modules/convert-source-map": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
+      "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==",
       "dev": true
     },
-    "node_modules/cheerio": {
-      "version": "1.0.0-rc.12",
-      "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz",
-      "integrity": "sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==",
-      "dev": true,
+    "node_modules/cookie": {
+      "version": "0.4.2",
+      "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz",
+      "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==",
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/core-util-is": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
+      "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==",
+      "dev": true
+    },
+    "node_modules/cross-spawn": {
+      "version": "7.0.3",
+      "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
+      "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
       "dependencies": {
-        "cheerio-select": "^2.1.0",
-        "dom-serializer": "^2.0.0",
-        "domhandler": "^5.0.3",
-        "domutils": "^3.0.1",
-        "htmlparser2": "^8.0.1",
-        "parse5": "^7.0.0",
-        "parse5-htmlparser2-tree-adapter": "^7.0.0"
+        "path-key": "^3.1.0",
+        "shebang-command": "^2.0.0",
+        "which": "^2.0.1"
       },
       "engines": {
-        "node": ">= 6"
-      },
-      "funding": {
-        "url": "https://github.com/cheeriojs/cheerio?sponsor=1"
+        "node": ">= 8"
+      }
+    },
+    "node_modules/css-color-keywords": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz",
+      "integrity": "sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg==",
+      "peer": true,
+      "engines": {
+        "node": ">=4"
       }
     },
-    "node_modules/cheerio-select": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz",
-      "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==",
+    "node_modules/css-select": {
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz",
+      "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==",
       "dev": true,
       "dependencies": {
         "boolbase": "^1.0.0",
-        "css-select": "^5.1.0",
         "css-what": "^6.1.0",
-        "domelementtype": "^2.3.0",
-        "domhandler": "^5.0.3",
-        "domutils": "^3.0.1"
+        "domhandler": "^5.0.2",
+        "domutils": "^3.0.1",
+        "nth-check": "^2.0.1"
       },
       "funding": {
         "url": "https://github.com/sponsors/fb55"
       }
     },
-    "node_modules/chokidar": {
-      "version": "3.5.3",
-      "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
-      "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
-      "funding": [
-        {
-          "type": "individual",
-          "url": "https://paulmillr.com/funding/"
-        }
-      ],
+    "node_modules/css-to-react-native": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/css-to-react-native/-/css-to-react-native-3.2.0.tgz",
+      "integrity": "sha512-e8RKaLXMOFii+02mOlqwjbD00KSEKqblnpO9e++1aXS1fPQOpS1YoqdVHBqPjHNoxeF2mimzVqawm2KCbEdtHQ==",
+      "peer": true,
       "dependencies": {
-        "anymatch": "~3.1.2",
-        "braces": "~3.0.2",
-        "glob-parent": "~5.1.2",
-        "is-binary-path": "~2.1.0",
-        "is-glob": "~4.0.1",
-        "normalize-path": "~3.0.0",
-        "readdirp": "~3.6.0"
-      },
-      "engines": {
-        "node": ">= 8.10.0"
-      },
-      "optionalDependencies": {
-        "fsevents": "~2.3.2"
+        "camelize": "^1.0.0",
+        "css-color-keywords": "^1.0.0",
+        "postcss-value-parser": "^4.0.2"
       }
     },
-    "node_modules/chokidar/node_modules/glob-parent": {
-      "version": "5.1.2",
-      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
-      "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
-      "dependencies": {
-        "is-glob": "^4.0.1"
-      },
+    "node_modules/css-what": {
+      "version": "6.1.0",
+      "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz",
+      "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==",
+      "dev": true,
       "engines": {
         "node": ">= 6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/fb55"
       }
     },
-    "node_modules/chownr": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz",
-      "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==",
+    "node_modules/cssesc": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
+      "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
+      "bin": {
+        "cssesc": "bin/cssesc"
+      },
       "engines": {
-        "node": ">=10"
+        "node": ">=4"
       }
     },
-    "node_modules/clean-stack": {
-      "version": "2.2.0",
-      "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz",
-      "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==",
-      "engines": {
-        "node": ">=6"
-      }
+    "node_modules/csstype": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz",
+      "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw=="
     },
-    "node_modules/cli-color": {
-      "version": "2.0.3",
-      "resolved": "https://registry.npmjs.org/cli-color/-/cli-color-2.0.3.tgz",
-      "integrity": "sha512-OkoZnxyC4ERN3zLzZaY9Emb7f/MhBOIpePv0Ycok0fJYT+Ouo00UBEIwsVsr0yoow++n5YWlSUgST9GKhNHiRQ==",
+    "node_modules/d": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz",
+      "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==",
       "dev": true,
       "dependencies": {
-        "d": "^1.0.1",
-        "es5-ext": "^0.10.61",
-        "es6-iterator": "^2.0.3",
-        "memoizee": "^0.4.15",
-        "timers-ext": "^0.1.7"
-      },
+        "es5-ext": "^0.10.50",
+        "type": "^1.0.1"
+      }
+    },
+    "node_modules/date-fns": {
+      "version": "2.29.3",
+      "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.29.3.tgz",
+      "integrity": "sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA==",
+      "dev": true,
       "engines": {
-        "node": ">=0.10"
+        "node": ">=0.11"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/date-fns"
       }
     },
-    "node_modules/cli-cursor": {
-      "version": "3.1.0",
-      "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz",
-      "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==",
+    "node_modules/debug": {
+      "version": "4.3.4",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
+      "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
       "dependencies": {
-        "restore-cursor": "^3.1.0"
+        "ms": "2.1.2"
       },
       "engines": {
-        "node": ">=8"
+        "node": ">=6.0"
+      },
+      "peerDependenciesMeta": {
+        "supports-color": {
+          "optional": true
+        }
       }
     },
-    "node_modules/cli-spinners": {
-      "version": "2.7.0",
-      "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.7.0.tgz",
-      "integrity": "sha512-qu3pN8Y3qHNgE2AFweciB1IfMnmZ/fsNTEE+NOFjmGB2F/7rLhnhzppvpCnN4FovtP26k8lHyy9ptEbNwWFLzw==",
+    "node_modules/decamelize": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz",
+      "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==",
+      "dev": true,
       "engines": {
-        "node": ">=6"
+        "node": ">=10"
       },
       "funding": {
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
-    "node_modules/cli-width": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz",
-      "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==",
-      "dev": true,
-      "engines": {
-        "node": ">= 10"
+    "node_modules/decode-named-character-reference": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.0.2.tgz",
+      "integrity": "sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg==",
+      "dependencies": {
+        "character-entities": "^2.0.0"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/wooorm"
       }
     },
-    "node_modules/cliui": {
-      "version": "7.0.4",
-      "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
-      "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
-      "dev": true,
+    "node_modules/decompress-response": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz",
+      "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==",
       "dependencies": {
-        "string-width": "^4.2.0",
-        "strip-ansi": "^6.0.0",
-        "wrap-ansi": "^7.0.0"
+        "mimic-response": "^3.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
       }
     },
-    "node_modules/cliui/node_modules/ansi-regex": {
-      "version": "5.0.1",
-      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
-      "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
-      "dev": true,
+    "node_modules/decompress-response/node_modules/mimic-response": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz",
+      "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==",
       "engines": {
-        "node": ">=8"
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
       }
     },
-    "node_modules/cliui/node_modules/strip-ansi": {
-      "version": "6.0.1",
-      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
-      "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+    "node_modules/dedent": {
+      "version": "0.7.0",
+      "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz",
+      "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==",
+      "dev": true
+    },
+    "node_modules/deep-extend": {
+      "version": "0.6.0",
+      "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
+      "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==",
       "dev": true,
-      "dependencies": {
-        "ansi-regex": "^5.0.1"
-      },
       "engines": {
-        "node": ">=8"
+        "node": ">=4.0.0"
       }
     },
-    "node_modules/clone": {
-      "version": "1.0.4",
-      "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz",
-      "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==",
+    "node_modules/deep-is": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
+      "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
+      "dev": true
+    },
+    "node_modules/deepmerge": {
+      "version": "4.3.1",
+      "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz",
+      "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==",
+      "dev": true,
       "engines": {
-        "node": ">=0.8"
+        "node": ">=0.10.0"
       }
     },
-    "node_modules/clone-response": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz",
-      "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==",
+    "node_modules/defaults": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz",
+      "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==",
       "dependencies": {
-        "mimic-response": "^1.0.0"
+        "clone": "^1.0.2"
       },
       "funding": {
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
-    "node_modules/color-convert": {
+    "node_modules/defer-to-connect": {
       "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
-      "dependencies": {
-        "color-name": "~1.1.4"
-      },
+      "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz",
+      "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==",
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/delayed-stream": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
+      "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
       "engines": {
-        "node": ">=7.0.0"
+        "node": ">=0.4.0"
       }
     },
-    "node_modules/color-name": {
-      "version": "1.1.4",
-      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
+    "node_modules/delegates": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
+      "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ=="
     },
-    "node_modules/color-support": {
-      "version": "1.1.3",
-      "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz",
-      "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==",
-      "bin": {
-        "color-support": "bin.js"
+    "node_modules/depd": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
+      "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==",
+      "engines": {
+        "node": ">= 0.6"
       }
     },
-    "node_modules/combined-stream": {
-      "version": "1.0.8",
-      "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
-      "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
-      "dependencies": {
-        "delayed-stream": "~1.0.0"
-      },
+    "node_modules/dequal": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz",
+      "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==",
       "engines": {
-        "node": ">= 0.8"
+        "node": ">=6"
       }
     },
-    "node_modules/comma-separated-tokens": {
-      "version": "2.0.3",
-      "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz",
-      "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==",
-      "funding": {
-        "type": "github",
-        "url": "https://github.com/sponsors/wooorm"
+    "node_modules/detect-libc": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz",
+      "integrity": "sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==",
+      "engines": {
+        "node": ">=8"
       }
     },
-    "node_modules/commander": {
-      "version": "6.2.1",
-      "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz",
-      "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==",
+    "node_modules/detect-newline": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz",
+      "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==",
       "dev": true,
       "engines": {
-        "node": ">= 6"
+        "node": ">=8"
       }
     },
-    "node_modules/compare-versions": {
-      "version": "4.1.4",
-      "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-4.1.4.tgz",
-      "integrity": "sha512-FemMreK9xNyL8gQevsdRMrvO4lFCkQP7qbuktn1q8ndcNk1+0mz7lgE7b/sNvbhVgY4w6tMN1FDp6aADjqw2rw==",
-      "dev": true
-    },
-    "node_modules/compute-scroll-into-view": {
-      "version": "2.0.4",
-      "resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-2.0.4.tgz",
-      "integrity": "sha512-y/ZA3BGnxoM/QHHQ2Uy49CLtnWPbt4tTPpEEZiEmmiWBFKjej7nEyH8Ryz54jH0MLXflUYA3Er2zUxPSJu5R+g=="
-    },
-    "node_modules/concat-map": {
-      "version": "0.0.1",
-      "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
-      "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="
+    "node_modules/didyoumean": {
+      "version": "1.2.2",
+      "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz",
+      "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw=="
     },
-    "node_modules/concurrently": {
-      "version": "6.5.1",
-      "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-6.5.1.tgz",
-      "integrity": "sha512-FlSwNpGjWQfRwPLXvJ/OgysbBxPkWpiVjy1042b0U7on7S7qwwMIILRj7WTN1mTgqa582bG6NFuScOoh6Zgdag==",
-      "dev": true,
-      "dependencies": {
-        "chalk": "^4.1.0",
-        "date-fns": "^2.16.1",
-        "lodash": "^4.17.21",
-        "rxjs": "^6.6.3",
-        "spawn-command": "^0.0.2-1",
-        "supports-color": "^8.1.0",
-        "tree-kill": "^1.2.2",
-        "yargs": "^16.2.0"
-      },
-      "bin": {
-        "concurrently": "bin/concurrently.js"
-      },
+    "node_modules/diff": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz",
+      "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==",
       "engines": {
-        "node": ">=10.0.0"
+        "node": ">=0.3.1"
       }
     },
-    "node_modules/concurrently/node_modules/rxjs": {
-      "version": "6.6.7",
-      "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz",
-      "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==",
+    "node_modules/diff-sequences": {
+      "version": "29.4.3",
+      "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.4.3.tgz",
+      "integrity": "sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA==",
       "dev": true,
-      "dependencies": {
-        "tslib": "^1.9.0"
-      },
       "engines": {
-        "npm": ">=2.0.0"
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
       }
     },
-    "node_modules/concurrently/node_modules/supports-color": {
-      "version": "8.1.1",
-      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
-      "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
+    "node_modules/dir-glob": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
+      "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
       "dev": true,
       "dependencies": {
-        "has-flag": "^4.0.0"
+        "path-type": "^4.0.0"
       },
       "engines": {
-        "node": ">=10"
-      },
-      "funding": {
-        "url": "https://github.com/chalk/supports-color?sponsor=1"
+        "node": ">=8"
       }
     },
-    "node_modules/consola": {
-      "version": "2.15.3",
-      "resolved": "https://registry.npmjs.org/consola/-/consola-2.15.3.tgz",
-      "integrity": "sha512-9vAdYbHj6x2fLKC4+oPH0kFzY/orMZyG2Aj+kNylHxKGJ/Ed4dpNyAQYwJOdqO4zdM7XpVHmyejQDcQHrnuXbw==",
-      "dev": true
-    },
-    "node_modules/console-control-strings": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
-      "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ=="
+    "node_modules/dlv": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz",
+      "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA=="
     },
-    "node_modules/console.table": {
-      "version": "0.10.0",
-      "resolved": "https://registry.npmjs.org/console.table/-/console.table-0.10.0.tgz",
-      "integrity": "sha512-dPyZofqggxuvSf7WXvNjuRfnsOk1YazkVP8FdxH4tcH2c37wc79/Yl6Bhr7Lsu00KMgy2ql/qCMuNu8xctZM8g==",
+    "node_modules/doctrine": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
+      "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
       "dev": true,
       "dependencies": {
-        "easy-table": "1.1.0"
+        "esutils": "^2.0.2"
       },
       "engines": {
-        "node": "> 0.10"
+        "node": ">=6.0.0"
       }
     },
-    "node_modules/cookie": {
-      "version": "0.4.2",
-      "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz",
-      "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==",
-      "engines": {
-        "node": ">= 0.6"
+    "node_modules/dom-serializer": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
+      "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==",
+      "dev": true,
+      "dependencies": {
+        "domelementtype": "^2.3.0",
+        "domhandler": "^5.0.2",
+        "entities": "^4.2.0"
+      },
+      "funding": {
+        "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
       }
     },
-    "node_modules/core-util-is": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
-      "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==",
-      "dev": true
+    "node_modules/domelementtype": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
+      "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/fb55"
+        }
+      ]
     },
-    "node_modules/cross-spawn": {
-      "version": "7.0.3",
-      "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
-      "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
+    "node_modules/domhandler": {
+      "version": "5.0.3",
+      "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz",
+      "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
+      "dev": true,
       "dependencies": {
-        "path-key": "^3.1.0",
-        "shebang-command": "^2.0.0",
-        "which": "^2.0.1"
+        "domelementtype": "^2.3.0"
       },
       "engines": {
-        "node": ">= 8"
-      }
-    },
-    "node_modules/css-color-keywords": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz",
-      "integrity": "sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg==",
-      "peer": true,
-      "engines": {
-        "node": ">=4"
+        "node": ">= 4"
+      },
+      "funding": {
+        "url": "https://github.com/fb55/domhandler?sponsor=1"
       }
     },
-    "node_modules/css-select": {
-      "version": "5.1.0",
-      "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz",
-      "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==",
+    "node_modules/domutils": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.0.1.tgz",
+      "integrity": "sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==",
       "dev": true,
       "dependencies": {
-        "boolbase": "^1.0.0",
-        "css-what": "^6.1.0",
-        "domhandler": "^5.0.2",
-        "domutils": "^3.0.1",
-        "nth-check": "^2.0.1"
+        "dom-serializer": "^2.0.0",
+        "domelementtype": "^2.3.0",
+        "domhandler": "^5.0.1"
       },
       "funding": {
-        "url": "https://github.com/sponsors/fb55"
+        "url": "https://github.com/fb55/domutils?sponsor=1"
       }
     },
-    "node_modules/css-to-react-native": {
-      "version": "3.2.0",
-      "resolved": "https://registry.npmjs.org/css-to-react-native/-/css-to-react-native-3.2.0.tgz",
-      "integrity": "sha512-e8RKaLXMOFii+02mOlqwjbD00KSEKqblnpO9e++1aXS1fPQOpS1YoqdVHBqPjHNoxeF2mimzVqawm2KCbEdtHQ==",
-      "peer": true,
+    "node_modules/downshift": {
+      "version": "7.6.0",
+      "resolved": "https://registry.npmjs.org/downshift/-/downshift-7.6.0.tgz",
+      "integrity": "sha512-VSoTVynTAsabou/hbZ6HJHUVhtBiVOjQoBsCPcQq5eAROIGP+9XKMp9asAKQ3cEcUP4oe0fFdD2pziUjhFY33Q==",
       "dependencies": {
-        "camelize": "^1.0.0",
-        "css-color-keywords": "^1.0.0",
-        "postcss-value-parser": "^4.0.2"
-      }
-    },
-    "node_modules/css-what": {
-      "version": "6.1.0",
-      "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz",
-      "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==",
-      "dev": true,
-      "engines": {
-        "node": ">= 6"
+        "@babel/runtime": "^7.14.8",
+        "compute-scroll-into-view": "^2.0.4",
+        "prop-types": "^15.7.2",
+        "react-is": "^17.0.2",
+        "tslib": "^2.3.0"
       },
-      "funding": {
-        "url": "https://github.com/sponsors/fb55"
+      "peerDependencies": {
+        "react": ">=16.12.0"
       }
     },
-    "node_modules/cssesc": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
-      "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
-      "bin": {
-        "cssesc": "bin/cssesc"
-      },
+    "node_modules/downshift/node_modules/react-is": {
+      "version": "17.0.2",
+      "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
+      "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w=="
+    },
+    "node_modules/downshift/node_modules/tslib": {
+      "version": "2.5.3",
+      "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.3.tgz",
+      "integrity": "sha512-mSxlJJwl3BMEQCUNnxXBU9jP4JBktcEGhURcPR6VQVlnP0FdDEsIaz0C35dXNGLyRfrATNofF0F5p2KPxQgB+w=="
+    },
+    "node_modules/dset": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/dset/-/dset-3.1.2.tgz",
+      "integrity": "sha512-g/M9sqy3oHe477Ar4voQxWtaPIFw1jTdKZuomOjhCcBx9nHUNn0pu6NopuFFrTh/TRZIKEj+76vLWFu9BNKk+Q==",
       "engines": {
         "node": ">=4"
       }
     },
-    "node_modules/csstype": {
-      "version": "3.1.1",
-      "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz",
-      "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw=="
-    },
-    "node_modules/d": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz",
-      "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==",
+    "node_modules/duplexer2": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz",
+      "integrity": "sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==",
       "dev": true,
       "dependencies": {
-        "es5-ext": "^0.10.50",
-        "type": "^1.0.1"
+        "readable-stream": "^2.0.2"
       }
     },
-    "node_modules/date-fns": {
-      "version": "2.29.3",
-      "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.29.3.tgz",
-      "integrity": "sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA==",
+    "node_modules/easy-table": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/easy-table/-/easy-table-1.1.0.tgz",
+      "integrity": "sha512-oq33hWOSSnl2Hoh00tZWaIPi1ievrD9aFG82/IgjlycAnW9hHx5PkJiXpxPsgEE+H7BsbVQXFVFST8TEXS6/pA==",
       "dev": true,
-      "engines": {
-        "node": ">=0.11"
-      },
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/date-fns"
+      "optionalDependencies": {
+        "wcwidth": ">=1.0.1"
       }
     },
-    "node_modules/debug": {
-      "version": "4.3.4",
-      "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
-      "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
-      "dependencies": {
-        "ms": "2.1.2"
-      },
-      "engines": {
-        "node": ">=6.0"
-      },
-      "peerDependenciesMeta": {
-        "supports-color": {
-          "optional": true
-        }
-      }
+    "node_modules/electron-to-chromium": {
+      "version": "1.4.449",
+      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.449.tgz",
+      "integrity": "sha512-TxLRpRUj/107ATefeP8VIUWNOv90xJxZZbCW/eIbSZQiuiFANCx2b7u+GbVc9X4gU+xnbvypNMYVM/WArE1DNQ==",
+      "dev": true
     },
-    "node_modules/decamelize": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz",
-      "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==",
+    "node_modules/emittery": {
+      "version": "0.13.1",
+      "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz",
+      "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==",
       "dev": true,
       "engines": {
-        "node": ">=10"
+        "node": ">=12"
       },
       "funding": {
-        "url": "https://github.com/sponsors/sindresorhus"
+        "url": "https://github.com/sindresorhus/emittery?sponsor=1"
       }
     },
-    "node_modules/decode-named-character-reference": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.0.2.tgz",
-      "integrity": "sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg==",
+    "node_modules/emoji-regex": {
+      "version": "8.0.0",
+      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+      "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
+    },
+    "node_modules/encoding": {
+      "version": "0.1.13",
+      "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz",
+      "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==",
+      "optional": true,
       "dependencies": {
-        "character-entities": "^2.0.0"
-      },
-      "funding": {
-        "type": "github",
-        "url": "https://github.com/sponsors/wooorm"
+        "iconv-lite": "^0.6.2"
       }
     },
-    "node_modules/decompress-response": {
-      "version": "6.0.0",
-      "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz",
-      "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==",
+    "node_modules/end-of-stream": {
+      "version": "1.4.4",
+      "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
+      "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
       "dependencies": {
-        "mimic-response": "^3.1.0"
-      },
-      "engines": {
-        "node": ">=10"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/sindresorhus"
+        "once": "^1.4.0"
       }
     },
-    "node_modules/decompress-response/node_modules/mimic-response": {
-      "version": "3.1.0",
-      "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz",
-      "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==",
+    "node_modules/entities": {
+      "version": "4.4.0",
+      "resolved": "https://registry.npmjs.org/entities/-/entities-4.4.0.tgz",
+      "integrity": "sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==",
+      "dev": true,
       "engines": {
-        "node": ">=10"
+        "node": ">=0.12"
       },
       "funding": {
-        "url": "https://github.com/sponsors/sindresorhus"
+        "url": "https://github.com/fb55/entities?sponsor=1"
       }
     },
-    "node_modules/deep-extend": {
-      "version": "0.6.0",
-      "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
-      "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==",
-      "dev": true,
+    "node_modules/env-paths": {
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz",
+      "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==",
       "engines": {
-        "node": ">=4.0.0"
+        "node": ">=6"
       }
     },
-    "node_modules/deep-is": {
-      "version": "0.1.4",
-      "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
-      "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
-      "dev": true
+    "node_modules/err-code": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz",
+      "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA=="
     },
-    "node_modules/defaults": {
-      "version": "1.0.4",
-      "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz",
-      "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==",
+    "node_modules/error-ex": {
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
+      "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
+      "dev": true,
       "dependencies": {
-        "clone": "^1.0.2"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/sindresorhus"
+        "is-arrayish": "^0.2.1"
       }
     },
-    "node_modules/defer-to-connect": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz",
-      "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==",
+    "node_modules/es5-ext": {
+      "version": "0.10.62",
+      "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.62.tgz",
+      "integrity": "sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==",
+      "dev": true,
+      "hasInstallScript": true,
+      "dependencies": {
+        "es6-iterator": "^2.0.3",
+        "es6-symbol": "^3.1.3",
+        "next-tick": "^1.1.0"
+      },
       "engines": {
-        "node": ">=10"
+        "node": ">=0.10"
       }
     },
-    "node_modules/delayed-stream": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
-      "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
-      "engines": {
-        "node": ">=0.4.0"
+    "node_modules/es6-iterator": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz",
+      "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==",
+      "dev": true,
+      "dependencies": {
+        "d": "1",
+        "es5-ext": "^0.10.35",
+        "es6-symbol": "^3.1.1"
       }
     },
-    "node_modules/delegates": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
-      "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ=="
-    },
-    "node_modules/depd": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
-      "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==",
-      "engines": {
-        "node": ">= 0.6"
+    "node_modules/es6-symbol": {
+      "version": "3.1.3",
+      "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz",
+      "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==",
+      "dev": true,
+      "dependencies": {
+        "d": "^1.0.1",
+        "ext": "^1.1.2"
       }
     },
-    "node_modules/dequal": {
+    "node_modules/es6-weak-map": {
       "version": "2.0.3",
-      "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz",
-      "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==",
-      "engines": {
-        "node": ">=6"
+      "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz",
+      "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==",
+      "dev": true,
+      "dependencies": {
+        "d": "1",
+        "es5-ext": "^0.10.46",
+        "es6-iterator": "^2.0.3",
+        "es6-symbol": "^3.1.1"
       }
     },
-    "node_modules/detect-libc": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz",
-      "integrity": "sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==",
+    "node_modules/esbuild": {
+      "version": "0.17.19",
+      "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.19.tgz",
+      "integrity": "sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==",
+      "hasInstallScript": true,
+      "bin": {
+        "esbuild": "bin/esbuild"
+      },
       "engines": {
-        "node": ">=8"
+        "node": ">=12"
+      },
+      "optionalDependencies": {
+        "@esbuild/android-arm": "0.17.19",
+        "@esbuild/android-arm64": "0.17.19",
+        "@esbuild/android-x64": "0.17.19",
+        "@esbuild/darwin-arm64": "0.17.19",
+        "@esbuild/darwin-x64": "0.17.19",
+        "@esbuild/freebsd-arm64": "0.17.19",
+        "@esbuild/freebsd-x64": "0.17.19",
+        "@esbuild/linux-arm": "0.17.19",
+        "@esbuild/linux-arm64": "0.17.19",
+        "@esbuild/linux-ia32": "0.17.19",
+        "@esbuild/linux-loong64": "0.17.19",
+        "@esbuild/linux-mips64el": "0.17.19",
+        "@esbuild/linux-ppc64": "0.17.19",
+        "@esbuild/linux-riscv64": "0.17.19",
+        "@esbuild/linux-s390x": "0.17.19",
+        "@esbuild/linux-x64": "0.17.19",
+        "@esbuild/netbsd-x64": "0.17.19",
+        "@esbuild/openbsd-x64": "0.17.19",
+        "@esbuild/sunos-x64": "0.17.19",
+        "@esbuild/win32-arm64": "0.17.19",
+        "@esbuild/win32-ia32": "0.17.19",
+        "@esbuild/win32-x64": "0.17.19"
       }
     },
-    "node_modules/didyoumean": {
-      "version": "1.2.2",
-      "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz",
-      "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw=="
-    },
-    "node_modules/diff": {
-      "version": "5.0.0",
-      "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz",
-      "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==",
+    "node_modules/escalade": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
+      "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
       "engines": {
-        "node": ">=0.3.1"
+        "node": ">=6"
       }
     },
-    "node_modules/dir-glob": {
-      "version": "3.0.1",
-      "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
-      "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
+    "node_modules/escape-string-regexp": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
+      "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
       "dev": true,
-      "dependencies": {
-        "path-type": "^4.0.0"
-      },
       "engines": {
-        "node": ">=8"
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
       }
     },
-    "node_modules/dlv": {
-      "version": "1.1.3",
-      "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz",
-      "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA=="
-    },
-    "node_modules/doctrine": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
-      "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
+    "node_modules/eslint": {
+      "version": "8.32.0",
+      "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.32.0.tgz",
+      "integrity": "sha512-nETVXpnthqKPFyuY2FNjz/bEd6nbosRgKbkgS/y1C7LJop96gYHWpiguLecMHQ2XCPxn77DS0P+68WzG6vkZSQ==",
       "dev": true,
       "dependencies": {
-        "esutils": "^2.0.2"
+        "@eslint/eslintrc": "^1.4.1",
+        "@humanwhocodes/config-array": "^0.11.8",
+        "@humanwhocodes/module-importer": "^1.0.1",
+        "@nodelib/fs.walk": "^1.2.8",
+        "ajv": "^6.10.0",
+        "chalk": "^4.0.0",
+        "cross-spawn": "^7.0.2",
+        "debug": "^4.3.2",
+        "doctrine": "^3.0.0",
+        "escape-string-regexp": "^4.0.0",
+        "eslint-scope": "^7.1.1",
+        "eslint-utils": "^3.0.0",
+        "eslint-visitor-keys": "^3.3.0",
+        "espree": "^9.4.0",
+        "esquery": "^1.4.0",
+        "esutils": "^2.0.2",
+        "fast-deep-equal": "^3.1.3",
+        "file-entry-cache": "^6.0.1",
+        "find-up": "^5.0.0",
+        "glob-parent": "^6.0.2",
+        "globals": "^13.19.0",
+        "grapheme-splitter": "^1.0.4",
+        "ignore": "^5.2.0",
+        "import-fresh": "^3.0.0",
+        "imurmurhash": "^0.1.4",
+        "is-glob": "^4.0.0",
+        "is-path-inside": "^3.0.3",
+        "js-sdsl": "^4.1.4",
+        "js-yaml": "^4.1.0",
+        "json-stable-stringify-without-jsonify": "^1.0.1",
+        "levn": "^0.4.1",
+        "lodash.merge": "^4.6.2",
+        "minimatch": "^3.1.2",
+        "natural-compare": "^1.4.0",
+        "optionator": "^0.9.1",
+        "regexpp": "^3.2.0",
+        "strip-ansi": "^6.0.1",
+        "strip-json-comments": "^3.1.0",
+        "text-table": "^0.2.0"
+      },
+      "bin": {
+        "eslint": "bin/eslint.js"
       },
       "engines": {
-        "node": ">=6.0.0"
-      }
-    },
-    "node_modules/dom-serializer": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
-      "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==",
-      "dev": true,
-      "dependencies": {
-        "domelementtype": "^2.3.0",
-        "domhandler": "^5.0.2",
-        "entities": "^4.2.0"
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
       },
       "funding": {
-        "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
+        "url": "https://opencollective.com/eslint"
       }
     },
-    "node_modules/domelementtype": {
-      "version": "2.3.0",
-      "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
-      "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==",
-      "dev": true,
-      "funding": [
-        {
-          "type": "github",
-          "url": "https://github.com/sponsors/fb55"
-        }
-      ]
-    },
-    "node_modules/domhandler": {
-      "version": "5.0.3",
-      "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz",
-      "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
+    "node_modules/eslint-scope": {
+      "version": "5.1.1",
+      "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
+      "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==",
       "dev": true,
       "dependencies": {
-        "domelementtype": "^2.3.0"
+        "esrecurse": "^4.3.0",
+        "estraverse": "^4.1.1"
       },
       "engines": {
-        "node": ">= 4"
-      },
-      "funding": {
-        "url": "https://github.com/fb55/domhandler?sponsor=1"
+        "node": ">=8.0.0"
       }
     },
-    "node_modules/domutils": {
-      "version": "3.0.1",
-      "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.0.1.tgz",
-      "integrity": "sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==",
+    "node_modules/eslint-utils": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz",
+      "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==",
       "dev": true,
       "dependencies": {
-        "dom-serializer": "^2.0.0",
-        "domelementtype": "^2.3.0",
-        "domhandler": "^5.0.1"
+        "eslint-visitor-keys": "^2.0.0"
+      },
+      "engines": {
+        "node": "^10.0.0 || ^12.0.0 || >= 14.0.0"
       },
       "funding": {
-        "url": "https://github.com/fb55/domutils?sponsor=1"
-      }
-    },
-    "node_modules/downshift": {
-      "version": "7.6.0",
-      "resolved": "https://registry.npmjs.org/downshift/-/downshift-7.6.0.tgz",
-      "integrity": "sha512-VSoTVynTAsabou/hbZ6HJHUVhtBiVOjQoBsCPcQq5eAROIGP+9XKMp9asAKQ3cEcUP4oe0fFdD2pziUjhFY33Q==",
-      "dependencies": {
-        "@babel/runtime": "^7.14.8",
-        "compute-scroll-into-view": "^2.0.4",
-        "prop-types": "^15.7.2",
-        "react-is": "^17.0.2",
-        "tslib": "^2.3.0"
+        "url": "https://github.com/sponsors/mysticatea"
       },
       "peerDependencies": {
-        "react": ">=16.12.0"
+        "eslint": ">=5"
       }
     },
-    "node_modules/downshift/node_modules/react-is": {
-      "version": "17.0.2",
-      "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
-      "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w=="
-    },
-    "node_modules/downshift/node_modules/tslib": {
-      "version": "2.5.3",
-      "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.3.tgz",
-      "integrity": "sha512-mSxlJJwl3BMEQCUNnxXBU9jP4JBktcEGhURcPR6VQVlnP0FdDEsIaz0C35dXNGLyRfrATNofF0F5p2KPxQgB+w=="
-    },
-    "node_modules/dset": {
-      "version": "3.1.2",
-      "resolved": "https://registry.npmjs.org/dset/-/dset-3.1.2.tgz",
-      "integrity": "sha512-g/M9sqy3oHe477Ar4voQxWtaPIFw1jTdKZuomOjhCcBx9nHUNn0pu6NopuFFrTh/TRZIKEj+76vLWFu9BNKk+Q==",
+    "node_modules/eslint-utils/node_modules/eslint-visitor-keys": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz",
+      "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==",
+      "dev": true,
       "engines": {
-        "node": ">=4"
+        "node": ">=10"
       }
     },
-    "node_modules/duplexer2": {
-      "version": "0.1.4",
-      "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz",
-      "integrity": "sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==",
+    "node_modules/eslint-visitor-keys": {
+      "version": "3.3.0",
+      "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz",
+      "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==",
       "dev": true,
-      "dependencies": {
-        "readable-stream": "^2.0.2"
+      "engines": {
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
       }
     },
-    "node_modules/easy-table": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/easy-table/-/easy-table-1.1.0.tgz",
-      "integrity": "sha512-oq33hWOSSnl2Hoh00tZWaIPi1ievrD9aFG82/IgjlycAnW9hHx5PkJiXpxPsgEE+H7BsbVQXFVFST8TEXS6/pA==",
+    "node_modules/eslint/node_modules/ansi-regex": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+      "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
       "dev": true,
-      "optionalDependencies": {
-        "wcwidth": ">=1.0.1"
+      "engines": {
+        "node": ">=8"
       }
     },
-    "node_modules/emoji-regex": {
-      "version": "8.0.0",
-      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
-      "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
-    },
-    "node_modules/encoding": {
-      "version": "0.1.13",
-      "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz",
-      "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==",
-      "optional": true,
+    "node_modules/eslint/node_modules/eslint-scope": {
+      "version": "7.1.1",
+      "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz",
+      "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==",
+      "dev": true,
       "dependencies": {
-        "iconv-lite": "^0.6.2"
+        "esrecurse": "^4.3.0",
+        "estraverse": "^5.2.0"
+      },
+      "engines": {
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
       }
     },
-    "node_modules/end-of-stream": {
-      "version": "1.4.4",
-      "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
-      "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
-      "dependencies": {
-        "once": "^1.4.0"
+    "node_modules/eslint/node_modules/estraverse": {
+      "version": "5.3.0",
+      "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
+      "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
+      "dev": true,
+      "engines": {
+        "node": ">=4.0"
       }
     },
-    "node_modules/entities": {
-      "version": "4.4.0",
-      "resolved": "https://registry.npmjs.org/entities/-/entities-4.4.0.tgz",
-      "integrity": "sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==",
+    "node_modules/eslint/node_modules/strip-ansi": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+      "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+      "dev": true,
+      "dependencies": {
+        "ansi-regex": "^5.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/espree": {
+      "version": "9.4.1",
+      "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz",
+      "integrity": "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==",
       "dev": true,
+      "dependencies": {
+        "acorn": "^8.8.0",
+        "acorn-jsx": "^5.3.2",
+        "eslint-visitor-keys": "^3.3.0"
+      },
       "engines": {
-        "node": ">=0.12"
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
       },
       "funding": {
-        "url": "https://github.com/fb55/entities?sponsor=1"
+        "url": "https://opencollective.com/eslint"
       }
     },
-    "node_modules/env-paths": {
-      "version": "2.2.1",
-      "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz",
-      "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==",
+    "node_modules/esprima": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
+      "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
+      "dev": true,
+      "bin": {
+        "esparse": "bin/esparse.js",
+        "esvalidate": "bin/esvalidate.js"
+      },
       "engines": {
-        "node": ">=6"
+        "node": ">=4"
       }
     },
-    "node_modules/err-code": {
-      "version": "2.0.3",
-      "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz",
-      "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA=="
-    },
-    "node_modules/es5-ext": {
-      "version": "0.10.62",
-      "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.62.tgz",
-      "integrity": "sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==",
+    "node_modules/esquery": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz",
+      "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==",
       "dev": true,
-      "hasInstallScript": true,
       "dependencies": {
-        "es6-iterator": "^2.0.3",
-        "es6-symbol": "^3.1.3",
-        "next-tick": "^1.1.0"
+        "estraverse": "^5.1.0"
       },
       "engines": {
         "node": ">=0.10"
       }
     },
-    "node_modules/es6-iterator": {
-      "version": "2.0.3",
-      "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz",
-      "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==",
+    "node_modules/esquery/node_modules/estraverse": {
+      "version": "5.3.0",
+      "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
+      "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
       "dev": true,
-      "dependencies": {
-        "d": "1",
-        "es5-ext": "^0.10.35",
-        "es6-symbol": "^3.1.1"
+      "engines": {
+        "node": ">=4.0"
       }
     },
-    "node_modules/es6-symbol": {
-      "version": "3.1.3",
-      "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz",
-      "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==",
+    "node_modules/esrecurse": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
+      "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
       "dev": true,
       "dependencies": {
-        "d": "^1.0.1",
-        "ext": "^1.1.2"
+        "estraverse": "^5.2.0"
+      },
+      "engines": {
+        "node": ">=4.0"
       }
     },
-    "node_modules/es6-weak-map": {
+    "node_modules/esrecurse/node_modules/estraverse": {
+      "version": "5.3.0",
+      "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
+      "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
+      "dev": true,
+      "engines": {
+        "node": ">=4.0"
+      }
+    },
+    "node_modules/estraverse": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
+      "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
+      "dev": true,
+      "engines": {
+        "node": ">=4.0"
+      }
+    },
+    "node_modules/esutils": {
       "version": "2.0.3",
-      "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz",
-      "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==",
+      "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
+      "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/event-emitter": {
+      "version": "0.3.5",
+      "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz",
+      "integrity": "sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==",
       "dev": true,
       "dependencies": {
         "d": "1",
-        "es5-ext": "^0.10.46",
-        "es6-iterator": "^2.0.3",
-        "es6-symbol": "^3.1.1"
+        "es5-ext": "~0.10.14"
       }
     },
-    "node_modules/esbuild": {
-      "version": "0.17.19",
-      "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.19.tgz",
-      "integrity": "sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==",
-      "hasInstallScript": true,
-      "bin": {
-        "esbuild": "bin/esbuild"
+    "node_modules/execa": {
+      "version": "5.1.1",
+      "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz",
+      "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==",
+      "dependencies": {
+        "cross-spawn": "^7.0.3",
+        "get-stream": "^6.0.0",
+        "human-signals": "^2.1.0",
+        "is-stream": "^2.0.0",
+        "merge-stream": "^2.0.0",
+        "npm-run-path": "^4.0.1",
+        "onetime": "^5.1.2",
+        "signal-exit": "^3.0.3",
+        "strip-final-newline": "^2.0.0"
       },
       "engines": {
-        "node": ">=12"
+        "node": ">=10"
       },
-      "optionalDependencies": {
-        "@esbuild/android-arm": "0.17.19",
-        "@esbuild/android-arm64": "0.17.19",
-        "@esbuild/android-x64": "0.17.19",
-        "@esbuild/darwin-arm64": "0.17.19",
-        "@esbuild/darwin-x64": "0.17.19",
-        "@esbuild/freebsd-arm64": "0.17.19",
-        "@esbuild/freebsd-x64": "0.17.19",
-        "@esbuild/linux-arm": "0.17.19",
-        "@esbuild/linux-arm64": "0.17.19",
-        "@esbuild/linux-ia32": "0.17.19",
-        "@esbuild/linux-loong64": "0.17.19",
-        "@esbuild/linux-mips64el": "0.17.19",
-        "@esbuild/linux-ppc64": "0.17.19",
-        "@esbuild/linux-riscv64": "0.17.19",
-        "@esbuild/linux-s390x": "0.17.19",
-        "@esbuild/linux-x64": "0.17.19",
-        "@esbuild/netbsd-x64": "0.17.19",
-        "@esbuild/openbsd-x64": "0.17.19",
-        "@esbuild/sunos-x64": "0.17.19",
-        "@esbuild/win32-arm64": "0.17.19",
-        "@esbuild/win32-ia32": "0.17.19",
-        "@esbuild/win32-x64": "0.17.19"
-      }
-    },
-    "node_modules/escalade": {
-      "version": "3.1.1",
-      "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
-      "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
-      "engines": {
-        "node": ">=6"
+      "funding": {
+        "url": "https://github.com/sindresorhus/execa?sponsor=1"
       }
     },
-    "node_modules/escape-string-regexp": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
-      "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
-      "dev": true,
+    "node_modules/execa/node_modules/get-stream": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz",
+      "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==",
       "engines": {
         "node": ">=10"
       },
@@ -3550,420 +5036,567 @@
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
-    "node_modules/eslint": {
-      "version": "8.32.0",
-      "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.32.0.tgz",
-      "integrity": "sha512-nETVXpnthqKPFyuY2FNjz/bEd6nbosRgKbkgS/y1C7LJop96gYHWpiguLecMHQ2XCPxn77DS0P+68WzG6vkZSQ==",
+    "node_modules/exit": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz",
+      "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.8.0"
+      }
+    },
+    "node_modules/expand-template": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz",
+      "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==",
+      "dev": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/expect": {
+      "version": "29.5.0",
+      "resolved": "https://registry.npmjs.org/expect/-/expect-29.5.0.tgz",
+      "integrity": "sha512-yM7xqUrCO2JdpFo4XpM82t+PJBFybdqoQuJLDGeDX2ij8NZzqRHyu3Hp188/JX7SWqud+7t4MUdvcgGBICMHZg==",
       "dev": true,
       "dependencies": {
-        "@eslint/eslintrc": "^1.4.1",
-        "@humanwhocodes/config-array": "^0.11.8",
-        "@humanwhocodes/module-importer": "^1.0.1",
-        "@nodelib/fs.walk": "^1.2.8",
-        "ajv": "^6.10.0",
-        "chalk": "^4.0.0",
-        "cross-spawn": "^7.0.2",
-        "debug": "^4.3.2",
-        "doctrine": "^3.0.0",
-        "escape-string-regexp": "^4.0.0",
-        "eslint-scope": "^7.1.1",
-        "eslint-utils": "^3.0.0",
-        "eslint-visitor-keys": "^3.3.0",
-        "espree": "^9.4.0",
-        "esquery": "^1.4.0",
-        "esutils": "^2.0.2",
-        "fast-deep-equal": "^3.1.3",
-        "file-entry-cache": "^6.0.1",
-        "find-up": "^5.0.0",
-        "glob-parent": "^6.0.2",
-        "globals": "^13.19.0",
-        "grapheme-splitter": "^1.0.4",
-        "ignore": "^5.2.0",
-        "import-fresh": "^3.0.0",
-        "imurmurhash": "^0.1.4",
-        "is-glob": "^4.0.0",
-        "is-path-inside": "^3.0.3",
-        "js-sdsl": "^4.1.4",
-        "js-yaml": "^4.1.0",
-        "json-stable-stringify-without-jsonify": "^1.0.1",
-        "levn": "^0.4.1",
-        "lodash.merge": "^4.6.2",
-        "minimatch": "^3.1.2",
-        "natural-compare": "^1.4.0",
-        "optionator": "^0.9.1",
-        "regexpp": "^3.2.0",
-        "strip-ansi": "^6.0.1",
-        "strip-json-comments": "^3.1.0",
-        "text-table": "^0.2.0"
+        "@jest/expect-utils": "^29.5.0",
+        "jest-get-type": "^29.4.3",
+        "jest-matcher-utils": "^29.5.0",
+        "jest-message-util": "^29.5.0",
+        "jest-util": "^29.5.0"
       },
-      "bin": {
-        "eslint": "bin/eslint.js"
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      }
+    },
+    "node_modules/ext": {
+      "version": "1.7.0",
+      "resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz",
+      "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==",
+      "dev": true,
+      "dependencies": {
+        "type": "^2.7.2"
+      }
+    },
+    "node_modules/ext/node_modules/type": {
+      "version": "2.7.2",
+      "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz",
+      "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==",
+      "dev": true
+    },
+    "node_modules/extend": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
+      "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="
+    },
+    "node_modules/external-editor": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz",
+      "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==",
+      "dev": true,
+      "dependencies": {
+        "chardet": "^0.7.0",
+        "iconv-lite": "^0.4.24",
+        "tmp": "^0.0.33"
       },
       "engines": {
-        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
-      },
-      "funding": {
-        "url": "https://opencollective.com/eslint"
+        "node": ">=4"
       }
     },
-    "node_modules/eslint-scope": {
-      "version": "5.1.1",
-      "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
-      "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==",
+    "node_modules/external-editor/node_modules/iconv-lite": {
+      "version": "0.4.24",
+      "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
+      "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
       "dev": true,
       "dependencies": {
-        "esrecurse": "^4.3.0",
-        "estraverse": "^4.1.1"
+        "safer-buffer": ">= 2.1.2 < 3"
       },
       "engines": {
-        "node": ">=8.0.0"
+        "node": ">=0.10.0"
       }
     },
-    "node_modules/eslint-utils": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz",
-      "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==",
+    "node_modules/external-editor/node_modules/tmp": {
+      "version": "0.0.33",
+      "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
+      "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==",
       "dev": true,
       "dependencies": {
-        "eslint-visitor-keys": "^2.0.0"
+        "os-tmpdir": "~1.0.2"
       },
       "engines": {
-        "node": "^10.0.0 || ^12.0.0 || >= 14.0.0"
+        "node": ">=0.6.0"
+      }
+    },
+    "node_modules/fast-deep-equal": {
+      "version": "3.1.3",
+      "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
+      "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
+      "dev": true
+    },
+    "node_modules/fast-glob": {
+      "version": "3.2.12",
+      "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz",
+      "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==",
+      "dependencies": {
+        "@nodelib/fs.stat": "^2.0.2",
+        "@nodelib/fs.walk": "^1.2.3",
+        "glob-parent": "^5.1.2",
+        "merge2": "^1.3.0",
+        "micromatch": "^4.0.4"
       },
-      "funding": {
-        "url": "https://github.com/sponsors/mysticatea"
+      "engines": {
+        "node": ">=8.6.0"
+      }
+    },
+    "node_modules/fast-glob/node_modules/glob-parent": {
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+      "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+      "dependencies": {
+        "is-glob": "^4.0.1"
       },
-      "peerDependencies": {
-        "eslint": ">=5"
+      "engines": {
+        "node": ">= 6"
       }
     },
-    "node_modules/eslint-utils/node_modules/eslint-visitor-keys": {
+    "node_modules/fast-json-stable-stringify": {
       "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz",
-      "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==",
-      "dev": true,
-      "engines": {
-        "node": ">=10"
+      "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
+      "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
+      "dev": true
+    },
+    "node_modules/fast-levenshtein": {
+      "version": "2.0.6",
+      "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
+      "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
+      "dev": true
+    },
+    "node_modules/fast-safe-stringify": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz",
+      "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==",
+      "dev": true
+    },
+    "node_modules/fastq": {
+      "version": "1.15.0",
+      "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz",
+      "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==",
+      "dependencies": {
+        "reusify": "^1.0.4"
       }
     },
-    "node_modules/eslint-visitor-keys": {
-      "version": "3.3.0",
-      "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz",
-      "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==",
+    "node_modules/fb-watchman": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz",
+      "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==",
       "dev": true,
-      "engines": {
-        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      "dependencies": {
+        "bser": "2.1.1"
       }
     },
-    "node_modules/eslint/node_modules/ansi-regex": {
-      "version": "5.0.1",
-      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
-      "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+    "node_modules/fd-slicer": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz",
+      "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==",
       "dev": true,
-      "engines": {
-        "node": ">=8"
+      "dependencies": {
+        "pend": "~1.2.0"
       }
     },
-    "node_modules/eslint/node_modules/eslint-scope": {
-      "version": "7.1.1",
-      "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz",
-      "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==",
+    "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/figures": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz",
+      "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==",
       "dev": true,
       "dependencies": {
-        "esrecurse": "^4.3.0",
-        "estraverse": "^5.2.0"
+        "escape-string-regexp": "^1.0.5"
       },
       "engines": {
-        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
       }
     },
-    "node_modules/eslint/node_modules/estraverse": {
-      "version": "5.3.0",
-      "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
-      "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
+    "node_modules/figures/node_modules/escape-string-regexp": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+      "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
       "dev": true,
       "engines": {
-        "node": ">=4.0"
+        "node": ">=0.8.0"
       }
     },
-    "node_modules/eslint/node_modules/strip-ansi": {
+    "node_modules/file-entry-cache": {
       "version": "6.0.1",
-      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
-      "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+      "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
+      "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==",
       "dev": true,
       "dependencies": {
-        "ansi-regex": "^5.0.1"
+        "flat-cache": "^3.0.4"
+      },
+      "engines": {
+        "node": "^10.12.0 || >=12.0.0"
+      }
+    },
+    "node_modules/fill-range": {
+      "version": "7.0.1",
+      "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
+      "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
+      "dependencies": {
+        "to-regex-range": "^5.0.1"
       },
       "engines": {
         "node": ">=8"
       }
     },
-    "node_modules/espree": {
-      "version": "9.4.1",
-      "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz",
-      "integrity": "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==",
+    "node_modules/find-up": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
+      "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
       "dev": true,
       "dependencies": {
-        "acorn": "^8.8.0",
-        "acorn-jsx": "^5.3.2",
-        "eslint-visitor-keys": "^3.3.0"
+        "locate-path": "^6.0.0",
+        "path-exists": "^4.0.0"
       },
       "engines": {
-        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+        "node": ">=10"
       },
       "funding": {
-        "url": "https://opencollective.com/eslint"
+        "url": "https://github.com/sponsors/sindresorhus"
       }
     },
-    "node_modules/esquery": {
-      "version": "1.4.0",
-      "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz",
-      "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==",
-      "dev": true,
+    "node_modules/fkill": {
+      "version": "8.1.0",
+      "resolved": "https://registry.npmjs.org/fkill/-/fkill-8.1.0.tgz",
+      "integrity": "sha512-XrPKdURVYoXerpYx+zhhaXrO9vHVflnGD4JhwjOwg03vKwyOH6eZ+EY69aKDD+q1EbCzviVmD+9OG9rwQy+z/A==",
       "dependencies": {
-        "estraverse": "^5.1.0"
+        "aggregate-error": "^4.0.0",
+        "execa": "^5.1.1",
+        "pid-port": "^0.2.0",
+        "process-exists": "^4.1.0",
+        "ps-list": "^7.2.0",
+        "taskkill": "^4.0.0"
+      },
+      "engines": {
+        "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/fkill/node_modules/aggregate-error": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-4.0.1.tgz",
+      "integrity": "sha512-0poP0T7el6Vq3rstR8Mn4V/IQrpBLO6POkUSrN7RhyY+GF/InCFShQzsQ39T25gkHhLgSLByyAz+Kjb+c2L98w==",
+      "dependencies": {
+        "clean-stack": "^4.0.0",
+        "indent-string": "^5.0.0"
+      },
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/fkill/node_modules/clean-stack": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-4.2.0.tgz",
+      "integrity": "sha512-LYv6XPxoyODi36Dp976riBtSY27VmFo+MKqEU9QCCWyTrdEPDog+RWA7xQWHi6Vbp61j5c4cdzzX1NidnwtUWg==",
+      "dependencies": {
+        "escape-string-regexp": "5.0.0"
+      },
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/fkill/node_modules/escape-string-regexp": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz",
+      "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==",
+      "engines": {
+        "node": ">=12"
       },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/fkill/node_modules/indent-string": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-5.0.0.tgz",
+      "integrity": "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==",
       "engines": {
-        "node": ">=0.10"
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
       }
     },
-    "node_modules/esquery/node_modules/estraverse": {
-      "version": "5.3.0",
-      "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
-      "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
+    "node_modules/flat": {
+      "version": "5.0.2",
+      "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz",
+      "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==",
       "dev": true,
-      "engines": {
-        "node": ">=4.0"
+      "bin": {
+        "flat": "cli.js"
       }
     },
-    "node_modules/esrecurse": {
-      "version": "4.3.0",
-      "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
-      "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
+    "node_modules/flat-cache": {
+      "version": "3.0.4",
+      "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz",
+      "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==",
       "dev": true,
       "dependencies": {
-        "estraverse": "^5.2.0"
+        "flatted": "^3.1.0",
+        "rimraf": "^3.0.2"
       },
       "engines": {
-        "node": ">=4.0"
+        "node": "^10.12.0 || >=12.0.0"
       }
     },
-    "node_modules/esrecurse/node_modules/estraverse": {
-      "version": "5.3.0",
-      "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
-      "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
-      "dev": true,
-      "engines": {
-        "node": ">=4.0"
-      }
+    "node_modules/flatted": {
+      "version": "3.2.7",
+      "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz",
+      "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==",
+      "dev": true
     },
-    "node_modules/estraverse": {
-      "version": "4.3.0",
-      "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
-      "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
-      "dev": true,
+    "node_modules/follow-redirects": {
+      "version": "1.15.2",
+      "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz",
+      "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==",
+      "funding": [
+        {
+          "type": "individual",
+          "url": "https://github.com/sponsors/RubenVerborgh"
+        }
+      ],
       "engines": {
         "node": ">=4.0"
+      },
+      "peerDependenciesMeta": {
+        "debug": {
+          "optional": true
+        }
       }
     },
-    "node_modules/esutils": {
-      "version": "2.0.3",
-      "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
-      "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
-      "dev": true,
+    "node_modules/form-data": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
+      "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
+      "dependencies": {
+        "asynckit": "^0.4.0",
+        "combined-stream": "^1.0.8",
+        "mime-types": "^2.1.12"
+      },
       "engines": {
-        "node": ">=0.10.0"
+        "node": ">= 6"
       }
     },
-    "node_modules/event-emitter": {
-      "version": "0.3.5",
-      "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz",
-      "integrity": "sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==",
-      "dev": true,
-      "dependencies": {
-        "d": "1",
-        "es5-ext": "~0.10.14"
-      }
+    "node_modules/fs-constants": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
+      "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==",
+      "dev": true
     },
-    "node_modules/execa": {
-      "version": "5.1.1",
-      "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz",
-      "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==",
+    "node_modules/fs-extra": {
+      "version": "10.1.0",
+      "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz",
+      "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==",
       "dependencies": {
-        "cross-spawn": "^7.0.3",
-        "get-stream": "^6.0.0",
-        "human-signals": "^2.1.0",
-        "is-stream": "^2.0.0",
-        "merge-stream": "^2.0.0",
-        "npm-run-path": "^4.0.1",
-        "onetime": "^5.1.2",
-        "signal-exit": "^3.0.3",
-        "strip-final-newline": "^2.0.0"
+        "graceful-fs": "^4.2.0",
+        "jsonfile": "^6.0.1",
+        "universalify": "^2.0.0"
       },
       "engines": {
-        "node": ">=10"
-      },
-      "funding": {
-        "url": "https://github.com/sindresorhus/execa?sponsor=1"
+        "node": ">=12"
       }
     },
-    "node_modules/execa/node_modules/get-stream": {
-      "version": "6.0.1",
-      "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz",
-      "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==",
-      "engines": {
-        "node": ">=10"
+    "node_modules/fs-minipass": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz",
+      "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==",
+      "dependencies": {
+        "minipass": "^3.0.0"
       },
-      "funding": {
-        "url": "https://github.com/sponsors/sindresorhus"
-      }
-    },
-    "node_modules/expand-template": {
-      "version": "2.0.3",
-      "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz",
-      "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==",
-      "dev": true,
       "engines": {
-        "node": ">=6"
-      }
-    },
-    "node_modules/ext": {
-      "version": "1.7.0",
-      "resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz",
-      "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==",
-      "dev": true,
-      "dependencies": {
-        "type": "^2.7.2"
+        "node": ">= 8"
       }
     },
-    "node_modules/ext/node_modules/type": {
-      "version": "2.7.2",
-      "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz",
-      "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==",
-      "dev": true
+    "node_modules/fs.realpath": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+      "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="
     },
-    "node_modules/extend": {
-      "version": "3.0.2",
-      "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
-      "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="
+    "node_modules/fsevents": {
+      "version": "2.3.2",
+      "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
+      "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
+      "hasInstallScript": true,
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+      }
     },
-    "node_modules/external-editor": {
-      "version": "3.1.0",
-      "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz",
-      "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==",
+    "node_modules/fstream": {
+      "version": "1.0.12",
+      "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz",
+      "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==",
       "dev": true,
       "dependencies": {
-        "chardet": "^0.7.0",
-        "iconv-lite": "^0.4.24",
-        "tmp": "^0.0.33"
+        "graceful-fs": "^4.1.2",
+        "inherits": "~2.0.0",
+        "mkdirp": ">=0.5 0",
+        "rimraf": "2"
       },
       "engines": {
-        "node": ">=4"
+        "node": ">=0.6"
       }
     },
-    "node_modules/external-editor/node_modules/iconv-lite": {
-      "version": "0.4.24",
-      "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
-      "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
+    "node_modules/fstream/node_modules/glob": {
+      "version": "7.2.3",
+      "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+      "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
       "dev": true,
       "dependencies": {
-        "safer-buffer": ">= 2.1.2 < 3"
+        "fs.realpath": "^1.0.0",
+        "inflight": "^1.0.4",
+        "inherits": "2",
+        "minimatch": "^3.1.1",
+        "once": "^1.3.0",
+        "path-is-absolute": "^1.0.0"
       },
       "engines": {
-        "node": ">=0.10.0"
+        "node": "*"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
       }
     },
-    "node_modules/external-editor/node_modules/tmp": {
-      "version": "0.0.33",
-      "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
-      "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==",
+    "node_modules/fstream/node_modules/rimraf": {
+      "version": "2.7.1",
+      "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
+      "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
       "dev": true,
       "dependencies": {
-        "os-tmpdir": "~1.0.2"
+        "glob": "^7.1.3"
       },
-      "engines": {
-        "node": ">=0.6.0"
+      "bin": {
+        "rimraf": "bin.js"
       }
     },
-    "node_modules/fast-deep-equal": {
-      "version": "3.1.3",
-      "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
-      "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
-      "dev": true
+    "node_modules/function-bind": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
+      "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
     },
-    "node_modules/fast-glob": {
-      "version": "3.2.12",
-      "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz",
-      "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==",
+    "node_modules/gauge": {
+      "version": "4.0.4",
+      "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz",
+      "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==",
       "dependencies": {
-        "@nodelib/fs.stat": "^2.0.2",
-        "@nodelib/fs.walk": "^1.2.3",
-        "glob-parent": "^5.1.2",
-        "merge2": "^1.3.0",
-        "micromatch": "^4.0.4"
+        "aproba": "^1.0.3 || ^2.0.0",
+        "color-support": "^1.1.3",
+        "console-control-strings": "^1.1.0",
+        "has-unicode": "^2.0.1",
+        "signal-exit": "^3.0.7",
+        "string-width": "^4.2.3",
+        "strip-ansi": "^6.0.1",
+        "wide-align": "^1.1.5"
       },
       "engines": {
-        "node": ">=8.6.0"
+        "node": "^12.13.0 || ^14.15.0 || >=16.0.0"
       }
     },
-    "node_modules/fast-glob/node_modules/glob-parent": {
-      "version": "5.1.2",
-      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
-      "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+    "node_modules/gauge/node_modules/ansi-regex": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+      "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/gauge/node_modules/strip-ansi": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+      "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
       "dependencies": {
-        "is-glob": "^4.0.1"
+        "ansi-regex": "^5.0.1"
       },
       "engines": {
-        "node": ">= 6"
+        "node": ">=8"
       }
     },
-    "node_modules/fast-json-stable-stringify": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
-      "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
-      "dev": true
-    },
-    "node_modules/fast-levenshtein": {
-      "version": "2.0.6",
-      "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
-      "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
-      "dev": true
-    },
-    "node_modules/fast-safe-stringify": {
-      "version": "2.1.1",
-      "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz",
-      "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==",
-      "dev": true
+    "node_modules/gensync": {
+      "version": "1.0.0-beta.2",
+      "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
+      "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==",
+      "dev": true,
+      "engines": {
+        "node": ">=6.9.0"
+      }
     },
-    "node_modules/fastq": {
-      "version": "1.15.0",
-      "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz",
-      "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==",
-      "dependencies": {
-        "reusify": "^1.0.4"
+    "node_modules/get-caller-file": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
+      "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
+      "engines": {
+        "node": "6.* || 8.* || >= 10.*"
       }
     },
-    "node_modules/fd-slicer": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz",
-      "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==",
+    "node_modules/get-intrinsic": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz",
+      "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==",
       "dev": true,
       "dependencies": {
-        "pend": "~1.2.0"
+        "function-bind": "^1.1.1",
+        "has": "^1.0.3",
+        "has-symbols": "^1.0.3"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
       }
     },
-    "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/get-package-type": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz",
+      "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==",
+      "dev": true,
+      "engines": {
+        "node": ">=8.0.0"
+      }
     },
-    "node_modules/figures": {
-      "version": "3.2.0",
-      "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz",
-      "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==",
+    "node_modules/get-stdin": {
+      "version": "8.0.0",
+      "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-8.0.0.tgz",
+      "integrity": "sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg==",
       "dev": true,
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/get-stream": {
+      "version": "5.2.0",
+      "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz",
+      "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==",
       "dependencies": {
-        "escape-string-regexp": "^1.0.5"
+        "pump": "^3.0.0"
       },
       "engines": {
         "node": ">=8"
@@ -3972,314 +5605,471 @@
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
-    "node_modules/figures/node_modules/escape-string-regexp": {
-      "version": "1.0.5",
-      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
-      "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
-      "dev": true,
+    "node_modules/github-from-package": {
+      "version": "0.0.0",
+      "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz",
+      "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==",
+      "dev": true
+    },
+    "node_modules/glob": {
+      "version": "8.1.0",
+      "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz",
+      "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==",
+      "dependencies": {
+        "fs.realpath": "^1.0.0",
+        "inflight": "^1.0.4",
+        "inherits": "2",
+        "minimatch": "^5.0.1",
+        "once": "^1.3.0"
+      },
       "engines": {
-        "node": ">=0.8.0"
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
       }
     },
-    "node_modules/file-entry-cache": {
-      "version": "6.0.1",
-      "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
-      "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==",
-      "dev": true,
+    "node_modules/glob-parent": {
+      "version": "6.0.2",
+      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
+      "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
       "dependencies": {
-        "flat-cache": "^3.0.4"
+        "is-glob": "^4.0.3"
       },
       "engines": {
-        "node": "^10.12.0 || >=12.0.0"
+        "node": ">=10.13.0"
       }
     },
-    "node_modules/fill-range": {
-      "version": "7.0.1",
-      "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
-      "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
+    "node_modules/glob/node_modules/brace-expansion": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+      "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
       "dependencies": {
-        "to-regex-range": "^5.0.1"
+        "balanced-match": "^1.0.0"
+      }
+    },
+    "node_modules/glob/node_modules/minimatch": {
+      "version": "5.1.6",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz",
+      "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==",
+      "dependencies": {
+        "brace-expansion": "^2.0.1"
       },
       "engines": {
-        "node": ">=8"
+        "node": ">=10"
       }
     },
-    "node_modules/find-up": {
-      "version": "5.0.0",
-      "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
-      "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
+    "node_modules/globals": {
+      "version": "13.19.0",
+      "resolved": "https://registry.npmjs.org/globals/-/globals-13.19.0.tgz",
+      "integrity": "sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ==",
       "dev": true,
       "dependencies": {
-        "locate-path": "^6.0.0",
-        "path-exists": "^4.0.0"
+        "type-fest": "^0.20.2"
       },
       "engines": {
-        "node": ">=10"
+        "node": ">=8"
       },
       "funding": {
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
-    "node_modules/fkill": {
-      "version": "8.1.0",
-      "resolved": "https://registry.npmjs.org/fkill/-/fkill-8.1.0.tgz",
-      "integrity": "sha512-XrPKdURVYoXerpYx+zhhaXrO9vHVflnGD4JhwjOwg03vKwyOH6eZ+EY69aKDD+q1EbCzviVmD+9OG9rwQy+z/A==",
+    "node_modules/globby": {
+      "version": "11.1.0",
+      "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
+      "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==",
+      "dev": true,
       "dependencies": {
-        "aggregate-error": "^4.0.0",
-        "execa": "^5.1.1",
-        "pid-port": "^0.2.0",
-        "process-exists": "^4.1.0",
-        "ps-list": "^7.2.0",
-        "taskkill": "^4.0.0"
+        "array-union": "^2.1.0",
+        "dir-glob": "^3.0.1",
+        "fast-glob": "^3.2.9",
+        "ignore": "^5.2.0",
+        "merge2": "^1.4.1",
+        "slash": "^3.0.0"
       },
       "engines": {
-        "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+        "node": ">=10"
       },
       "funding": {
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
-    "node_modules/fkill/node_modules/aggregate-error": {
-      "version": "4.0.1",
-      "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-4.0.1.tgz",
-      "integrity": "sha512-0poP0T7el6Vq3rstR8Mn4V/IQrpBLO6POkUSrN7RhyY+GF/InCFShQzsQ39T25gkHhLgSLByyAz+Kjb+c2L98w==",
+    "node_modules/got": {
+      "version": "11.8.6",
+      "resolved": "https://registry.npmjs.org/got/-/got-11.8.6.tgz",
+      "integrity": "sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==",
       "dependencies": {
-        "clean-stack": "^4.0.0",
-        "indent-string": "^5.0.0"
+        "@sindresorhus/is": "^4.0.0",
+        "@szmarczak/http-timer": "^4.0.5",
+        "@types/cacheable-request": "^6.0.1",
+        "@types/responselike": "^1.0.0",
+        "cacheable-lookup": "^5.0.3",
+        "cacheable-request": "^7.0.2",
+        "decompress-response": "^6.0.0",
+        "http2-wrapper": "^1.0.0-beta.5.2",
+        "lowercase-keys": "^2.0.0",
+        "p-cancelable": "^2.0.0",
+        "responselike": "^2.0.0"
       },
       "engines": {
-        "node": ">=12"
+        "node": ">=10.19.0"
       },
       "funding": {
-        "url": "https://github.com/sponsors/sindresorhus"
+        "url": "https://github.com/sindresorhus/got?sponsor=1"
       }
     },
-    "node_modules/fkill/node_modules/clean-stack": {
-      "version": "4.2.0",
-      "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-4.2.0.tgz",
-      "integrity": "sha512-LYv6XPxoyODi36Dp976riBtSY27VmFo+MKqEU9QCCWyTrdEPDog+RWA7xQWHi6Vbp61j5c4cdzzX1NidnwtUWg==",
+    "node_modules/graceful-fs": {
+      "version": "4.2.10",
+      "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz",
+      "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA=="
+    },
+    "node_modules/grapheme-splitter": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz",
+      "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==",
+      "dev": true
+    },
+    "node_modules/has": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
+      "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
       "dependencies": {
-        "escape-string-regexp": "5.0.0"
+        "function-bind": "^1.1.1"
       },
       "engines": {
-        "node": ">=12"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/sindresorhus"
+        "node": ">= 0.4.0"
       }
     },
-    "node_modules/fkill/node_modules/escape-string-regexp": {
-      "version": "5.0.0",
-      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz",
-      "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==",
+    "node_modules/has-flag": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+      "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/has-symbols": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
+      "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
+      "dev": true,
       "engines": {
-        "node": ">=12"
+        "node": ">= 0.4"
       },
       "funding": {
-        "url": "https://github.com/sponsors/sindresorhus"
+        "url": "https://github.com/sponsors/ljharb"
       }
     },
-    "node_modules/fkill/node_modules/indent-string": {
-      "version": "5.0.0",
-      "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-5.0.0.tgz",
-      "integrity": "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==",
-      "engines": {
-        "node": ">=12"
-      },
+    "node_modules/has-unicode": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
+      "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ=="
+    },
+    "node_modules/hast-util-whitespace": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-2.0.1.tgz",
+      "integrity": "sha512-nAxA0v8+vXSBDt3AnRUNjyRIQ0rD+ntpbAp4LnPkumc5M9yUbSMa4XDU9Q6etY4f1Wp4bNgvc1yjiZtsTTrSng==",
       "funding": {
-        "url": "https://github.com/sponsors/sindresorhus"
+        "type": "opencollective",
+        "url": "https://opencollective.com/unified"
       }
     },
-    "node_modules/flat": {
-      "version": "5.0.2",
-      "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz",
-      "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==",
+    "node_modules/he": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
+      "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
       "dev": true,
       "bin": {
-        "flat": "cli.js"
+        "he": "bin/he"
       }
     },
-    "node_modules/flat-cache": {
-      "version": "3.0.4",
-      "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz",
-      "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==",
+    "node_modules/highlight.js": {
+      "version": "11.7.0",
+      "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.7.0.tgz",
+      "integrity": "sha512-1rRqesRFhMO/PRF+G86evnyJkCgaZFOI+Z6kdj15TA18funfoqJXvgPCLSf0SWq3SRfg1j3HlDs8o4s3EGq1oQ==",
+      "engines": {
+        "node": ">=12.0.0"
+      }
+    },
+    "node_modules/hoist-non-react-statics": {
+      "version": "3.3.2",
+      "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
+      "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==",
+      "dependencies": {
+        "react-is": "^16.7.0"
+      }
+    },
+    "node_modules/hoist-non-react-statics/node_modules/react-is": {
+      "version": "16.13.1",
+      "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
+      "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
+    },
+    "node_modules/hosted-git-info": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz",
+      "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==",
       "dev": true,
       "dependencies": {
-        "flatted": "^3.1.0",
-        "rimraf": "^3.0.2"
+        "lru-cache": "^6.0.0"
       },
       "engines": {
-        "node": "^10.12.0 || >=12.0.0"
+        "node": ">=10"
       }
     },
-    "node_modules/flatted": {
-      "version": "3.2.7",
-      "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz",
-      "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==",
+    "node_modules/html-escaper": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz",
+      "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==",
       "dev": true
     },
-    "node_modules/follow-redirects": {
-      "version": "1.15.2",
-      "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz",
-      "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==",
+    "node_modules/htmlparser2": {
+      "version": "8.0.1",
+      "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.1.tgz",
+      "integrity": "sha512-4lVbmc1diZC7GUJQtRQ5yBAeUCL1exyMwmForWkRLnwyzWBFxN633SALPMGYaWZvKe9j1pRZJpauvmxENSp/EA==",
+      "dev": true,
       "funding": [
+        "https://github.com/fb55/htmlparser2?sponsor=1",
         {
-          "type": "individual",
-          "url": "https://github.com/sponsors/RubenVerborgh"
+          "type": "github",
+          "url": "https://github.com/sponsors/fb55"
         }
       ],
-      "engines": {
-        "node": ">=4.0"
-      },
-      "peerDependenciesMeta": {
-        "debug": {
-          "optional": true
-        }
+      "dependencies": {
+        "domelementtype": "^2.3.0",
+        "domhandler": "^5.0.2",
+        "domutils": "^3.0.1",
+        "entities": "^4.3.0"
       }
     },
-    "node_modules/form-data": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
-      "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
+    "node_modules/http-cache-semantics": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz",
+      "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ=="
+    },
+    "node_modules/http-proxy-agent": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz",
+      "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==",
+      "dev": true,
       "dependencies": {
-        "asynckit": "^0.4.0",
-        "combined-stream": "^1.0.8",
-        "mime-types": "^2.1.12"
+        "@tootallnate/once": "1",
+        "agent-base": "6",
+        "debug": "4"
       },
       "engines": {
         "node": ">= 6"
       }
     },
-    "node_modules/fs-constants": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
-      "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==",
-      "dev": true
-    },
-    "node_modules/fs-extra": {
-      "version": "10.1.0",
-      "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz",
-      "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==",
+    "node_modules/http2-wrapper": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz",
+      "integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==",
       "dependencies": {
-        "graceful-fs": "^4.2.0",
-        "jsonfile": "^6.0.1",
-        "universalify": "^2.0.0"
+        "quick-lru": "^5.1.1",
+        "resolve-alpn": "^1.0.0"
       },
       "engines": {
-        "node": ">=12"
+        "node": ">=10.19.0"
       }
     },
-    "node_modules/fs-minipass": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz",
-      "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==",
+    "node_modules/https-proxy-agent": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
+      "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==",
       "dependencies": {
-        "minipass": "^3.0.0"
+        "agent-base": "6",
+        "debug": "4"
       },
       "engines": {
-        "node": ">= 8"
+        "node": ">= 6"
       }
     },
-    "node_modules/fs.realpath": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
-      "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="
+    "node_modules/human-signals": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz",
+      "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==",
+      "engines": {
+        "node": ">=10.17.0"
+      }
     },
-    "node_modules/fsevents": {
-      "version": "2.3.2",
-      "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
-      "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
-      "hasInstallScript": true,
+    "node_modules/humanize-ms": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz",
+      "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==",
+      "dependencies": {
+        "ms": "^2.0.0"
+      }
+    },
+    "node_modules/iconv-lite": {
+      "version": "0.6.3",
+      "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
+      "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
       "optional": true,
-      "os": [
-        "darwin"
-      ],
+      "dependencies": {
+        "safer-buffer": ">= 2.1.2 < 3.0.0"
+      },
       "engines": {
-        "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+        "node": ">=0.10.0"
       }
     },
-    "node_modules/fstream": {
-      "version": "1.0.12",
-      "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz",
-      "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==",
+    "node_modules/ieee754": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
+      "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ]
+    },
+    "node_modules/ignore": {
+      "version": "5.2.4",
+      "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz",
+      "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==",
       "dev": true,
-      "dependencies": {
-        "graceful-fs": "^4.1.2",
-        "inherits": "~2.0.0",
-        "mkdirp": ">=0.5 0",
-        "rimraf": "2"
-      },
       "engines": {
-        "node": ">=0.6"
+        "node": ">= 4"
       }
     },
-    "node_modules/fstream/node_modules/glob": {
-      "version": "7.2.3",
-      "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
-      "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
+    "node_modules/immer": {
+      "version": "9.0.19",
+      "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.19.tgz",
+      "integrity": "sha512-eY+Y0qcsB4TZKwgQzLaE/lqYMlKhv5J9dyd2RhhtGhNo2njPXDqU9XPfcNfa3MIDsdtZt5KlkIsirlo4dHsWdQ==",
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/immer"
+      }
+    },
+    "node_modules/import-fresh": {
+      "version": "3.3.0",
+      "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
+      "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
       "dev": true,
       "dependencies": {
-        "fs.realpath": "^1.0.0",
-        "inflight": "^1.0.4",
-        "inherits": "2",
-        "minimatch": "^3.1.1",
-        "once": "^1.3.0",
-        "path-is-absolute": "^1.0.0"
+        "parent-module": "^1.0.0",
+        "resolve-from": "^4.0.0"
       },
       "engines": {
-        "node": "*"
+        "node": ">=6"
       },
       "funding": {
-        "url": "https://github.com/sponsors/isaacs"
+        "url": "https://github.com/sponsors/sindresorhus"
       }
     },
-    "node_modules/fstream/node_modules/rimraf": {
-      "version": "2.7.1",
-      "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
-      "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
+    "node_modules/import-local": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz",
+      "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==",
       "dev": true,
       "dependencies": {
-        "glob": "^7.1.3"
+        "pkg-dir": "^4.2.0",
+        "resolve-cwd": "^3.0.0"
       },
       "bin": {
-        "rimraf": "bin.js"
+        "import-local-fixture": "fixtures/cli.js"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
       }
     },
-    "node_modules/function-bind": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
-      "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
+    "node_modules/imurmurhash": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
+      "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
+      "engines": {
+        "node": ">=0.8.19"
+      }
     },
-    "node_modules/gauge": {
-      "version": "4.0.4",
-      "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz",
-      "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==",
+    "node_modules/indent-string": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz",
+      "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/infer-owner": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz",
+      "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A=="
+    },
+    "node_modules/inflight": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+      "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
       "dependencies": {
-        "aproba": "^1.0.3 || ^2.0.0",
-        "color-support": "^1.1.3",
-        "console-control-strings": "^1.1.0",
-        "has-unicode": "^2.0.1",
-        "signal-exit": "^3.0.7",
-        "string-width": "^4.2.3",
-        "strip-ansi": "^6.0.1",
-        "wide-align": "^1.1.5"
+        "once": "^1.3.0",
+        "wrappy": "1"
+      }
+    },
+    "node_modules/inherits": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+      "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
+    },
+    "node_modules/ini": {
+      "version": "1.3.8",
+      "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
+      "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==",
+      "dev": true
+    },
+    "node_modules/inline-style-parser": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.1.1.tgz",
+      "integrity": "sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q=="
+    },
+    "node_modules/inquirer": {
+      "version": "8.2.5",
+      "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.5.tgz",
+      "integrity": "sha512-QAgPDQMEgrDssk1XiwwHoOGYF9BAbUcc1+j+FhEvaOt8/cKRqyLn0U5qA6F74fGhTMGxf92pOvPBeh29jQJDTQ==",
+      "dev": true,
+      "dependencies": {
+        "ansi-escapes": "^4.2.1",
+        "chalk": "^4.1.1",
+        "cli-cursor": "^3.1.0",
+        "cli-width": "^3.0.0",
+        "external-editor": "^3.0.3",
+        "figures": "^3.0.0",
+        "lodash": "^4.17.21",
+        "mute-stream": "0.0.8",
+        "ora": "^5.4.1",
+        "run-async": "^2.4.0",
+        "rxjs": "^7.5.5",
+        "string-width": "^4.1.0",
+        "strip-ansi": "^6.0.0",
+        "through": "^2.3.6",
+        "wrap-ansi": "^7.0.0"
       },
       "engines": {
-        "node": "^12.13.0 || ^14.15.0 || >=16.0.0"
+        "node": ">=12.0.0"
       }
     },
-    "node_modules/gauge/node_modules/ansi-regex": {
+    "node_modules/inquirer/node_modules/ansi-regex": {
       "version": "5.0.1",
       "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
       "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+      "dev": true,
       "engines": {
         "node": ">=8"
       }
     },
-    "node_modules/gauge/node_modules/strip-ansi": {
+    "node_modules/inquirer/node_modules/strip-ansi": {
       "version": "6.0.1",
       "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
       "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+      "dev": true,
       "dependencies": {
         "ansi-regex": "^5.0.1"
       },
@@ -4287,116 +6077,146 @@
         "node": ">=8"
       }
     },
-    "node_modules/get-caller-file": {
+    "node_modules/ip": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz",
+      "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ=="
+    },
+    "node_modules/is-arrayish": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
+      "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==",
+      "dev": true
+    },
+    "node_modules/is-binary-path": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
+      "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
+      "dependencies": {
+        "binary-extensions": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/is-buffer": {
       "version": "2.0.5",
-      "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
-      "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
+      "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz",
+      "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==",
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ],
       "engines": {
-        "node": "6.* || 8.* || >= 10.*"
+        "node": ">=4"
       }
     },
-    "node_modules/get-intrinsic": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz",
-      "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==",
-      "dev": true,
+    "node_modules/is-core-module": {
+      "version": "2.12.1",
+      "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.1.tgz",
+      "integrity": "sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==",
       "dependencies": {
-        "function-bind": "^1.1.1",
-        "has": "^1.0.3",
-        "has-symbols": "^1.0.3"
+        "has": "^1.0.3"
       },
       "funding": {
         "url": "https://github.com/sponsors/ljharb"
       }
     },
-    "node_modules/get-stdin": {
-      "version": "8.0.0",
-      "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-8.0.0.tgz",
-      "integrity": "sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg==",
-      "dev": true,
+    "node_modules/is-extglob": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+      "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
       "engines": {
-        "node": ">=10"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/sindresorhus"
+        "node": ">=0.10.0"
       }
     },
-    "node_modules/get-stream": {
-      "version": "5.2.0",
-      "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz",
-      "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==",
-      "dependencies": {
-        "pump": "^3.0.0"
-      },
+    "node_modules/is-fullwidth-code-point": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+      "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
       "engines": {
         "node": ">=8"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/sindresorhus"
       }
     },
-    "node_modules/github-from-package": {
-      "version": "0.0.0",
-      "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz",
-      "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==",
-      "dev": true
+    "node_modules/is-generator-fn": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz",
+      "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=6"
+      }
     },
-    "node_modules/glob": {
-      "version": "8.1.0",
-      "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz",
-      "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==",
+    "node_modules/is-glob": {
+      "version": "4.0.3",
+      "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+      "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
       "dependencies": {
-        "fs.realpath": "^1.0.0",
-        "inflight": "^1.0.4",
-        "inherits": "2",
-        "minimatch": "^5.0.1",
-        "once": "^1.3.0"
+        "is-extglob": "^2.1.1"
       },
       "engines": {
-        "node": ">=12"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/isaacs"
+        "node": ">=0.10.0"
       }
     },
-    "node_modules/glob-parent": {
-      "version": "6.0.2",
-      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
-      "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
-      "dependencies": {
-        "is-glob": "^4.0.3"
-      },
+    "node_modules/is-interactive": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz",
+      "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==",
       "engines": {
-        "node": ">=10.13.0"
+        "node": ">=8"
       }
     },
-    "node_modules/glob/node_modules/brace-expansion": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
-      "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
-      "dependencies": {
-        "balanced-match": "^1.0.0"
+    "node_modules/is-lambda": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz",
+      "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ=="
+    },
+    "node_modules/is-number": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+      "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+      "engines": {
+        "node": ">=0.12.0"
+      }
+    },
+    "node_modules/is-path-inside": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz",
+      "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
       }
     },
-    "node_modules/glob/node_modules/minimatch": {
-      "version": "5.1.6",
-      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz",
-      "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==",
-      "dependencies": {
-        "brace-expansion": "^2.0.1"
-      },
+    "node_modules/is-plain-obj": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz",
+      "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==",
+      "dev": true,
       "engines": {
-        "node": ">=10"
+        "node": ">=8"
       }
     },
-    "node_modules/globals": {
-      "version": "13.19.0",
-      "resolved": "https://registry.npmjs.org/globals/-/globals-13.19.0.tgz",
-      "integrity": "sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ==",
-      "dev": true,
-      "dependencies": {
-        "type-fest": "^0.20.2"
-      },
+    "node_modules/is-promise": {
+      "version": "2.2.2",
+      "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz",
+      "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==",
+      "dev": true
+    },
+    "node_modules/is-stream": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
+      "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
       "engines": {
         "node": ">=8"
       },
@@ -4404,19 +6224,10 @@
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
-    "node_modules/globby": {
-      "version": "11.1.0",
-      "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
-      "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==",
-      "dev": true,
-      "dependencies": {
-        "array-union": "^2.1.0",
-        "dir-glob": "^3.0.1",
-        "fast-glob": "^3.2.9",
-        "ignore": "^5.2.0",
-        "merge2": "^1.4.1",
-        "slash": "^3.0.0"
-      },
+    "node_modules/is-unicode-supported": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz",
+      "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==",
       "engines": {
         "node": ">=10"
       },
@@ -4424,524 +6235,746 @@
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
-    "node_modules/got": {
-      "version": "11.8.6",
-      "resolved": "https://registry.npmjs.org/got/-/got-11.8.6.tgz",
-      "integrity": "sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==",
+    "node_modules/isarray": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+      "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==",
+      "dev": true
+    },
+    "node_modules/isexe": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+      "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="
+    },
+    "node_modules/istanbul-lib-coverage": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz",
+      "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/istanbul-lib-instrument": {
+      "version": "5.2.1",
+      "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz",
+      "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==",
+      "dev": true,
       "dependencies": {
-        "@sindresorhus/is": "^4.0.0",
-        "@szmarczak/http-timer": "^4.0.5",
-        "@types/cacheable-request": "^6.0.1",
-        "@types/responselike": "^1.0.0",
-        "cacheable-lookup": "^5.0.3",
-        "cacheable-request": "^7.0.2",
-        "decompress-response": "^6.0.0",
-        "http2-wrapper": "^1.0.0-beta.5.2",
-        "lowercase-keys": "^2.0.0",
-        "p-cancelable": "^2.0.0",
-        "responselike": "^2.0.0"
+        "@babel/core": "^7.12.3",
+        "@babel/parser": "^7.14.7",
+        "@istanbuljs/schema": "^0.1.2",
+        "istanbul-lib-coverage": "^3.2.0",
+        "semver": "^6.3.0"
       },
       "engines": {
-        "node": ">=10.19.0"
-      },
-      "funding": {
-        "url": "https://github.com/sindresorhus/got?sponsor=1"
+        "node": ">=8"
       }
     },
-    "node_modules/graceful-fs": {
-      "version": "4.2.10",
-      "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz",
-      "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA=="
-    },
-    "node_modules/grapheme-splitter": {
-      "version": "1.0.4",
-      "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz",
-      "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==",
-      "dev": true
+    "node_modules/istanbul-lib-instrument/node_modules/semver": {
+      "version": "6.3.0",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+      "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+      "dev": true,
+      "bin": {
+        "semver": "bin/semver.js"
+      }
     },
-    "node_modules/has": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
-      "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
+    "node_modules/istanbul-lib-report": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz",
+      "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==",
+      "dev": true,
       "dependencies": {
-        "function-bind": "^1.1.1"
+        "istanbul-lib-coverage": "^3.0.0",
+        "make-dir": "^3.0.0",
+        "supports-color": "^7.1.0"
       },
       "engines": {
-        "node": ">= 0.4.0"
+        "node": ">=8"
       }
     },
-    "node_modules/has-flag": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-      "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+    "node_modules/istanbul-lib-source-maps": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz",
+      "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==",
+      "dev": true,
+      "dependencies": {
+        "debug": "^4.1.1",
+        "istanbul-lib-coverage": "^3.0.0",
+        "source-map": "^0.6.1"
+      },
       "engines": {
-        "node": ">=8"
+        "node": ">=10"
       }
     },
-    "node_modules/has-symbols": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
-      "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
+    "node_modules/istanbul-reports": {
+      "version": "3.1.5",
+      "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz",
+      "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==",
       "dev": true,
-      "engines": {
-        "node": ">= 0.4"
+      "dependencies": {
+        "html-escaper": "^2.0.0",
+        "istanbul-lib-report": "^3.0.0"
       },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
+      "engines": {
+        "node": ">=8"
       }
     },
-    "node_modules/has-unicode": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
-      "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ=="
-    },
-    "node_modules/hast-util-whitespace": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-2.0.1.tgz",
-      "integrity": "sha512-nAxA0v8+vXSBDt3AnRUNjyRIQ0rD+ntpbAp4LnPkumc5M9yUbSMa4XDU9Q6etY4f1Wp4bNgvc1yjiZtsTTrSng==",
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/unified"
+    "node_modules/iterare": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/iterare/-/iterare-1.2.1.tgz",
+      "integrity": "sha512-RKYVTCjAnRthyJes037NX/IiqeidgN1xc3j1RjFfECFp28A1GVwK9nA+i0rJPaHqSZwygLzRnFlzUuHFoWWy+Q==",
+      "engines": {
+        "node": ">=6"
       }
     },
-    "node_modules/he": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
-      "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
+    "node_modules/jest": {
+      "version": "29.5.0",
+      "resolved": "https://registry.npmjs.org/jest/-/jest-29.5.0.tgz",
+      "integrity": "sha512-juMg3he2uru1QoXX078zTa7pO85QyB9xajZc6bU+d9yEGwrKX6+vGmJQ3UdVZsvTEUARIdObzH68QItim6OSSQ==",
       "dev": true,
+      "dependencies": {
+        "@jest/core": "^29.5.0",
+        "@jest/types": "^29.5.0",
+        "import-local": "^3.0.2",
+        "jest-cli": "^29.5.0"
+      },
       "bin": {
-        "he": "bin/he"
-      }
-    },
-    "node_modules/highlight.js": {
-      "version": "11.7.0",
-      "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.7.0.tgz",
-      "integrity": "sha512-1rRqesRFhMO/PRF+G86evnyJkCgaZFOI+Z6kdj15TA18funfoqJXvgPCLSf0SWq3SRfg1j3HlDs8o4s3EGq1oQ==",
+        "jest": "bin/jest.js"
+      },
       "engines": {
-        "node": ">=12.0.0"
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      },
+      "peerDependencies": {
+        "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0"
+      },
+      "peerDependenciesMeta": {
+        "node-notifier": {
+          "optional": true
+        }
       }
     },
-    "node_modules/hoist-non-react-statics": {
-      "version": "3.3.2",
-      "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
-      "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==",
+    "node_modules/jest-changed-files": {
+      "version": "29.5.0",
+      "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.5.0.tgz",
+      "integrity": "sha512-IFG34IUMUaNBIxjQXF/iu7g6EcdMrGRRxaUSw92I/2g2YC6vCdTltl4nHvt7Ci5nSJwXIkCu8Ka1DKF+X7Z1Ag==",
+      "dev": true,
       "dependencies": {
-        "react-is": "^16.7.0"
+        "execa": "^5.0.0",
+        "p-limit": "^3.1.0"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
       }
     },
-    "node_modules/hoist-non-react-statics/node_modules/react-is": {
-      "version": "16.13.1",
-      "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
-      "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
-    },
-    "node_modules/hosted-git-info": {
-      "version": "4.1.0",
-      "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz",
-      "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==",
+    "node_modules/jest-circus": {
+      "version": "29.5.0",
+      "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.5.0.tgz",
+      "integrity": "sha512-gq/ongqeQKAplVxqJmbeUOJJKkW3dDNPY8PjhJ5G0lBRvu0e3EWGxGy5cI4LAGA7gV2UHCtWBI4EMXK8c9nQKA==",
       "dev": true,
       "dependencies": {
-        "lru-cache": "^6.0.0"
+        "@jest/environment": "^29.5.0",
+        "@jest/expect": "^29.5.0",
+        "@jest/test-result": "^29.5.0",
+        "@jest/types": "^29.5.0",
+        "@types/node": "*",
+        "chalk": "^4.0.0",
+        "co": "^4.6.0",
+        "dedent": "^0.7.0",
+        "is-generator-fn": "^2.0.0",
+        "jest-each": "^29.5.0",
+        "jest-matcher-utils": "^29.5.0",
+        "jest-message-util": "^29.5.0",
+        "jest-runtime": "^29.5.0",
+        "jest-snapshot": "^29.5.0",
+        "jest-util": "^29.5.0",
+        "p-limit": "^3.1.0",
+        "pretty-format": "^29.5.0",
+        "pure-rand": "^6.0.0",
+        "slash": "^3.0.0",
+        "stack-utils": "^2.0.3"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      }
+    },
+    "node_modules/jest-cli": {
+      "version": "29.5.0",
+      "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.5.0.tgz",
+      "integrity": "sha512-L1KcP1l4HtfwdxXNFCL5bmUbLQiKrakMUriBEcc1Vfz6gx31ORKdreuWvmQVBit+1ss9NNR3yxjwfwzZNdQXJw==",
+      "dev": true,
+      "dependencies": {
+        "@jest/core": "^29.5.0",
+        "@jest/test-result": "^29.5.0",
+        "@jest/types": "^29.5.0",
+        "chalk": "^4.0.0",
+        "exit": "^0.1.2",
+        "graceful-fs": "^4.2.9",
+        "import-local": "^3.0.2",
+        "jest-config": "^29.5.0",
+        "jest-util": "^29.5.0",
+        "jest-validate": "^29.5.0",
+        "prompts": "^2.0.1",
+        "yargs": "^17.3.1"
+      },
+      "bin": {
+        "jest": "bin/jest.js"
       },
       "engines": {
-        "node": ">=10"
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      },
+      "peerDependencies": {
+        "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0"
+      },
+      "peerDependenciesMeta": {
+        "node-notifier": {
+          "optional": true
+        }
       }
     },
-    "node_modules/htmlparser2": {
-      "version": "8.0.1",
-      "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.1.tgz",
-      "integrity": "sha512-4lVbmc1diZC7GUJQtRQ5yBAeUCL1exyMwmForWkRLnwyzWBFxN633SALPMGYaWZvKe9j1pRZJpauvmxENSp/EA==",
+    "node_modules/jest-cli/node_modules/ansi-regex": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+      "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
       "dev": true,
-      "funding": [
-        "https://github.com/fb55/htmlparser2?sponsor=1",
-        {
-          "type": "github",
-          "url": "https://github.com/sponsors/fb55"
-        }
-      ],
-      "dependencies": {
-        "domelementtype": "^2.3.0",
-        "domhandler": "^5.0.2",
-        "domutils": "^3.0.1",
-        "entities": "^4.3.0"
+      "engines": {
+        "node": ">=8"
       }
     },
-    "node_modules/http-cache-semantics": {
-      "version": "4.1.1",
-      "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz",
-      "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ=="
-    },
-    "node_modules/http-proxy-agent": {
-      "version": "4.0.1",
-      "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz",
-      "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==",
+    "node_modules/jest-cli/node_modules/cliui": {
+      "version": "8.0.1",
+      "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
+      "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
       "dev": true,
       "dependencies": {
-        "@tootallnate/once": "1",
-        "agent-base": "6",
-        "debug": "4"
+        "string-width": "^4.2.0",
+        "strip-ansi": "^6.0.1",
+        "wrap-ansi": "^7.0.0"
       },
       "engines": {
-        "node": ">= 6"
+        "node": ">=12"
       }
     },
-    "node_modules/http2-wrapper": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz",
-      "integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==",
-      "dependencies": {
-        "quick-lru": "^5.1.1",
-        "resolve-alpn": "^1.0.0"
+    "node_modules/jest-cli/node_modules/strip-ansi": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+      "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+      "dev": true,
+      "dependencies": {
+        "ansi-regex": "^5.0.1"
       },
       "engines": {
-        "node": ">=10.19.0"
+        "node": ">=8"
       }
     },
-    "node_modules/https-proxy-agent": {
-      "version": "5.0.1",
-      "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
-      "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==",
+    "node_modules/jest-cli/node_modules/yargs": {
+      "version": "17.7.2",
+      "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
+      "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
+      "dev": true,
       "dependencies": {
-        "agent-base": "6",
-        "debug": "4"
+        "cliui": "^8.0.1",
+        "escalade": "^3.1.1",
+        "get-caller-file": "^2.0.5",
+        "require-directory": "^2.1.1",
+        "string-width": "^4.2.3",
+        "y18n": "^5.0.5",
+        "yargs-parser": "^21.1.1"
       },
       "engines": {
-        "node": ">= 6"
+        "node": ">=12"
       }
     },
-    "node_modules/human-signals": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz",
-      "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==",
+    "node_modules/jest-cli/node_modules/yargs-parser": {
+      "version": "21.1.1",
+      "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
+      "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
+      "dev": true,
       "engines": {
-        "node": ">=10.17.0"
+        "node": ">=12"
       }
     },
-    "node_modules/humanize-ms": {
-      "version": "1.2.1",
-      "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz",
-      "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==",
+    "node_modules/jest-config": {
+      "version": "29.5.0",
+      "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.5.0.tgz",
+      "integrity": "sha512-kvDUKBnNJPNBmFFOhDbm59iu1Fii1Q6SxyhXfvylq3UTHbg6o7j/g8k2dZyXWLvfdKB1vAPxNZnMgtKJcmu3kA==",
+      "dev": true,
       "dependencies": {
-        "ms": "^2.0.0"
+        "@babel/core": "^7.11.6",
+        "@jest/test-sequencer": "^29.5.0",
+        "@jest/types": "^29.5.0",
+        "babel-jest": "^29.5.0",
+        "chalk": "^4.0.0",
+        "ci-info": "^3.2.0",
+        "deepmerge": "^4.2.2",
+        "glob": "^7.1.3",
+        "graceful-fs": "^4.2.9",
+        "jest-circus": "^29.5.0",
+        "jest-environment-node": "^29.5.0",
+        "jest-get-type": "^29.4.3",
+        "jest-regex-util": "^29.4.3",
+        "jest-resolve": "^29.5.0",
+        "jest-runner": "^29.5.0",
+        "jest-util": "^29.5.0",
+        "jest-validate": "^29.5.0",
+        "micromatch": "^4.0.4",
+        "parse-json": "^5.2.0",
+        "pretty-format": "^29.5.0",
+        "slash": "^3.0.0",
+        "strip-json-comments": "^3.1.1"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      },
+      "peerDependencies": {
+        "@types/node": "*",
+        "ts-node": ">=9.0.0"
+      },
+      "peerDependenciesMeta": {
+        "@types/node": {
+          "optional": true
+        },
+        "ts-node": {
+          "optional": true
+        }
       }
     },
-    "node_modules/iconv-lite": {
-      "version": "0.6.3",
-      "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
-      "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
-      "optional": true,
+    "node_modules/jest-config/node_modules/glob": {
+      "version": "7.2.3",
+      "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+      "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
+      "dev": true,
       "dependencies": {
-        "safer-buffer": ">= 2.1.2 < 3.0.0"
+        "fs.realpath": "^1.0.0",
+        "inflight": "^1.0.4",
+        "inherits": "2",
+        "minimatch": "^3.1.1",
+        "once": "^1.3.0",
+        "path-is-absolute": "^1.0.0"
       },
       "engines": {
-        "node": ">=0.10.0"
+        "node": "*"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
       }
     },
-    "node_modules/ieee754": {
-      "version": "1.2.1",
-      "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
-      "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
-      "funding": [
-        {
-          "type": "github",
-          "url": "https://github.com/sponsors/feross"
-        },
-        {
-          "type": "patreon",
-          "url": "https://www.patreon.com/feross"
-        },
-        {
-          "type": "consulting",
-          "url": "https://feross.org/support"
-        }
-      ]
-    },
-    "node_modules/ignore": {
-      "version": "5.2.4",
-      "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz",
-      "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==",
+    "node_modules/jest-diff": {
+      "version": "29.5.0",
+      "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.5.0.tgz",
+      "integrity": "sha512-LtxijLLZBduXnHSniy0WMdaHjmQnt3g5sa16W4p0HqukYTTsyTW3GD1q41TyGl5YFXj/5B2U6dlh5FM1LIMgxw==",
       "dev": true,
+      "dependencies": {
+        "chalk": "^4.0.0",
+        "diff-sequences": "^29.4.3",
+        "jest-get-type": "^29.4.3",
+        "pretty-format": "^29.5.0"
+      },
       "engines": {
-        "node": ">= 4"
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
       }
     },
-    "node_modules/immer": {
-      "version": "9.0.19",
-      "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.19.tgz",
-      "integrity": "sha512-eY+Y0qcsB4TZKwgQzLaE/lqYMlKhv5J9dyd2RhhtGhNo2njPXDqU9XPfcNfa3MIDsdtZt5KlkIsirlo4dHsWdQ==",
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/immer"
+    "node_modules/jest-docblock": {
+      "version": "29.4.3",
+      "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.4.3.tgz",
+      "integrity": "sha512-fzdTftThczeSD9nZ3fzA/4KkHtnmllawWrXO69vtI+L9WjEIuXWs4AmyME7lN5hU7dB0sHhuPfcKofRsUb/2Fg==",
+      "dev": true,
+      "dependencies": {
+        "detect-newline": "^3.0.0"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
       }
     },
-    "node_modules/import-fresh": {
-      "version": "3.3.0",
-      "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
-      "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
+    "node_modules/jest-each": {
+      "version": "29.5.0",
+      "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.5.0.tgz",
+      "integrity": "sha512-HM5kIJ1BTnVt+DQZ2ALp3rzXEl+g726csObrW/jpEGl+CDSSQpOJJX2KE/vEg8cxcMXdyEPu6U4QX5eruQv5hA==",
       "dev": true,
       "dependencies": {
-        "parent-module": "^1.0.0",
-        "resolve-from": "^4.0.0"
+        "@jest/types": "^29.5.0",
+        "chalk": "^4.0.0",
+        "jest-get-type": "^29.4.3",
+        "jest-util": "^29.5.0",
+        "pretty-format": "^29.5.0"
       },
       "engines": {
-        "node": ">=6"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/sindresorhus"
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
       }
     },
-    "node_modules/imurmurhash": {
-      "version": "0.1.4",
-      "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
-      "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
+    "node_modules/jest-environment-node": {
+      "version": "29.5.0",
+      "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.5.0.tgz",
+      "integrity": "sha512-ExxuIK/+yQ+6PRGaHkKewYtg6hto2uGCgvKdb2nfJfKXgZ17DfXjvbZ+jA1Qt9A8EQSfPnt5FKIfnOO3u1h9qw==",
+      "dev": true,
+      "dependencies": {
+        "@jest/environment": "^29.5.0",
+        "@jest/fake-timers": "^29.5.0",
+        "@jest/types": "^29.5.0",
+        "@types/node": "*",
+        "jest-mock": "^29.5.0",
+        "jest-util": "^29.5.0"
+      },
       "engines": {
-        "node": ">=0.8.19"
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
       }
     },
-    "node_modules/indent-string": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz",
-      "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==",
+    "node_modules/jest-get-type": {
+      "version": "29.4.3",
+      "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.4.3.tgz",
+      "integrity": "sha512-J5Xez4nRRMjk8emnTpWrlkyb9pfRQQanDrvWHhsR1+VUfbwxi30eVcZFlcdGInRibU4G5LwHXpI7IRHU0CY+gg==",
+      "dev": true,
       "engines": {
-        "node": ">=8"
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
       }
     },
-    "node_modules/infer-owner": {
-      "version": "1.0.4",
-      "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz",
-      "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A=="
-    },
-    "node_modules/inflight": {
-      "version": "1.0.6",
-      "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
-      "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
+    "node_modules/jest-haste-map": {
+      "version": "29.5.0",
+      "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.5.0.tgz",
+      "integrity": "sha512-IspOPnnBro8YfVYSw6yDRKh/TiCdRngjxeacCps1cQ9cgVN6+10JUcuJ1EabrgYLOATsIAigxA0rLR9x/YlrSA==",
+      "dev": true,
       "dependencies": {
-        "once": "^1.3.0",
-        "wrappy": "1"
+        "@jest/types": "^29.5.0",
+        "@types/graceful-fs": "^4.1.3",
+        "@types/node": "*",
+        "anymatch": "^3.0.3",
+        "fb-watchman": "^2.0.0",
+        "graceful-fs": "^4.2.9",
+        "jest-regex-util": "^29.4.3",
+        "jest-util": "^29.5.0",
+        "jest-worker": "^29.5.0",
+        "micromatch": "^4.0.4",
+        "walker": "^1.0.8"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      },
+      "optionalDependencies": {
+        "fsevents": "^2.3.2"
       }
     },
-    "node_modules/inherits": {
-      "version": "2.0.4",
-      "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
-      "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
-    },
-    "node_modules/ini": {
-      "version": "1.3.8",
-      "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
-      "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==",
-      "dev": true
-    },
-    "node_modules/inline-style-parser": {
-      "version": "0.1.1",
-      "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.1.1.tgz",
-      "integrity": "sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q=="
-    },
-    "node_modules/inquirer": {
-      "version": "8.2.5",
-      "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.5.tgz",
-      "integrity": "sha512-QAgPDQMEgrDssk1XiwwHoOGYF9BAbUcc1+j+FhEvaOt8/cKRqyLn0U5qA6F74fGhTMGxf92pOvPBeh29jQJDTQ==",
+    "node_modules/jest-leak-detector": {
+      "version": "29.5.0",
+      "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.5.0.tgz",
+      "integrity": "sha512-u9YdeeVnghBUtpN5mVxjID7KbkKE1QU4f6uUwuxiY0vYRi9BUCLKlPEZfDGR67ofdFmDz9oPAy2G92Ujrntmow==",
       "dev": true,
       "dependencies": {
-        "ansi-escapes": "^4.2.1",
-        "chalk": "^4.1.1",
-        "cli-cursor": "^3.1.0",
-        "cli-width": "^3.0.0",
-        "external-editor": "^3.0.3",
-        "figures": "^3.0.0",
-        "lodash": "^4.17.21",
-        "mute-stream": "0.0.8",
-        "ora": "^5.4.1",
-        "run-async": "^2.4.0",
-        "rxjs": "^7.5.5",
-        "string-width": "^4.1.0",
-        "strip-ansi": "^6.0.0",
-        "through": "^2.3.6",
-        "wrap-ansi": "^7.0.0"
+        "jest-get-type": "^29.4.3",
+        "pretty-format": "^29.5.0"
       },
       "engines": {
-        "node": ">=12.0.0"
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
       }
     },
-    "node_modules/inquirer/node_modules/ansi-regex": {
-      "version": "5.0.1",
-      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
-      "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+    "node_modules/jest-matcher-utils": {
+      "version": "29.5.0",
+      "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.5.0.tgz",
+      "integrity": "sha512-lecRtgm/rjIK0CQ7LPQwzCs2VwW6WAahA55YBuI+xqmhm7LAaxokSB8C97yJeYyT+HvQkH741StzpU41wohhWw==",
       "dev": true,
+      "dependencies": {
+        "chalk": "^4.0.0",
+        "jest-diff": "^29.5.0",
+        "jest-get-type": "^29.4.3",
+        "pretty-format": "^29.5.0"
+      },
       "engines": {
-        "node": ">=8"
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
       }
     },
-    "node_modules/inquirer/node_modules/strip-ansi": {
-      "version": "6.0.1",
-      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
-      "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+    "node_modules/jest-message-util": {
+      "version": "29.5.0",
+      "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.5.0.tgz",
+      "integrity": "sha512-Kijeg9Dag6CKtIDA7O21zNTACqD5MD/8HfIV8pdD94vFyFuer52SigdC3IQMhab3vACxXMiFk+yMHNdbqtyTGA==",
       "dev": true,
       "dependencies": {
-        "ansi-regex": "^5.0.1"
+        "@babel/code-frame": "^7.12.13",
+        "@jest/types": "^29.5.0",
+        "@types/stack-utils": "^2.0.0",
+        "chalk": "^4.0.0",
+        "graceful-fs": "^4.2.9",
+        "micromatch": "^4.0.4",
+        "pretty-format": "^29.5.0",
+        "slash": "^3.0.0",
+        "stack-utils": "^2.0.3"
       },
       "engines": {
-        "node": ">=8"
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
       }
     },
-    "node_modules/ip": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz",
-      "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ=="
-    },
-    "node_modules/is-binary-path": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
-      "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
+    "node_modules/jest-mock": {
+      "version": "29.5.0",
+      "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.5.0.tgz",
+      "integrity": "sha512-GqOzvdWDE4fAV2bWQLQCkujxYWL7RxjCnj71b5VhDAGOevB3qj3Ovg26A5NI84ZpODxyzaozXLOh2NCgkbvyaw==",
+      "dev": true,
       "dependencies": {
-        "binary-extensions": "^2.0.0"
+        "@jest/types": "^29.5.0",
+        "@types/node": "*",
+        "jest-util": "^29.5.0"
       },
       "engines": {
-        "node": ">=8"
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
       }
     },
-    "node_modules/is-buffer": {
-      "version": "2.0.5",
-      "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz",
-      "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==",
-      "funding": [
-        {
-          "type": "github",
-          "url": "https://github.com/sponsors/feross"
-        },
-        {
-          "type": "patreon",
-          "url": "https://www.patreon.com/feross"
-        },
-        {
-          "type": "consulting",
-          "url": "https://feross.org/support"
+    "node_modules/jest-pnp-resolver": {
+      "version": "1.2.3",
+      "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz",
+      "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==",
+      "dev": true,
+      "engines": {
+        "node": ">=6"
+      },
+      "peerDependencies": {
+        "jest-resolve": "*"
+      },
+      "peerDependenciesMeta": {
+        "jest-resolve": {
+          "optional": true
         }
-      ],
+      }
+    },
+    "node_modules/jest-regex-util": {
+      "version": "29.4.3",
+      "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.4.3.tgz",
+      "integrity": "sha512-O4FglZaMmWXbGHSQInfXewIsd1LMn9p3ZXB/6r4FOkyhX2/iP/soMG98jGvk/A3HAN78+5VWcBGO0BJAPRh4kg==",
+      "dev": true,
       "engines": {
-        "node": ">=4"
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
       }
     },
-    "node_modules/is-core-module": {
-      "version": "2.12.1",
-      "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.1.tgz",
-      "integrity": "sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==",
+    "node_modules/jest-resolve": {
+      "version": "29.5.0",
+      "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.5.0.tgz",
+      "integrity": "sha512-1TzxJ37FQq7J10jPtQjcc+MkCkE3GBpBecsSUWJ0qZNJpmg6m0D9/7II03yJulm3H/fvVjgqLh/k2eYg+ui52w==",
+      "dev": true,
       "dependencies": {
-        "has": "^1.0.3"
+        "chalk": "^4.0.0",
+        "graceful-fs": "^4.2.9",
+        "jest-haste-map": "^29.5.0",
+        "jest-pnp-resolver": "^1.2.2",
+        "jest-util": "^29.5.0",
+        "jest-validate": "^29.5.0",
+        "resolve": "^1.20.0",
+        "resolve.exports": "^2.0.0",
+        "slash": "^3.0.0"
       },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
       }
     },
-    "node_modules/is-extglob": {
-      "version": "2.1.1",
-      "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
-      "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+    "node_modules/jest-resolve-dependencies": {
+      "version": "29.5.0",
+      "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.5.0.tgz",
+      "integrity": "sha512-sjV3GFr0hDJMBpYeUuGduP+YeCRbd7S/ck6IvL3kQ9cpySYKqcqhdLLC2rFwrcL7tz5vYibomBrsFYWkIGGjOg==",
+      "dev": true,
+      "dependencies": {
+        "jest-regex-util": "^29.4.3",
+        "jest-snapshot": "^29.5.0"
+      },
       "engines": {
-        "node": ">=0.10.0"
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
       }
     },
-    "node_modules/is-fullwidth-code-point": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
-      "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+    "node_modules/jest-runner": {
+      "version": "29.5.0",
+      "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.5.0.tgz",
+      "integrity": "sha512-m7b6ypERhFghJsslMLhydaXBiLf7+jXy8FwGRHO3BGV1mcQpPbwiqiKUR2zU2NJuNeMenJmlFZCsIqzJCTeGLQ==",
+      "dev": true,
+      "dependencies": {
+        "@jest/console": "^29.5.0",
+        "@jest/environment": "^29.5.0",
+        "@jest/test-result": "^29.5.0",
+        "@jest/transform": "^29.5.0",
+        "@jest/types": "^29.5.0",
+        "@types/node": "*",
+        "chalk": "^4.0.0",
+        "emittery": "^0.13.1",
+        "graceful-fs": "^4.2.9",
+        "jest-docblock": "^29.4.3",
+        "jest-environment-node": "^29.5.0",
+        "jest-haste-map": "^29.5.0",
+        "jest-leak-detector": "^29.5.0",
+        "jest-message-util": "^29.5.0",
+        "jest-resolve": "^29.5.0",
+        "jest-runtime": "^29.5.0",
+        "jest-util": "^29.5.0",
+        "jest-watcher": "^29.5.0",
+        "jest-worker": "^29.5.0",
+        "p-limit": "^3.1.0",
+        "source-map-support": "0.5.13"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      }
+    },
+    "node_modules/jest-runtime": {
+      "version": "29.5.0",
+      "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.5.0.tgz",
+      "integrity": "sha512-1Hr6Hh7bAgXQP+pln3homOiEZtCDZFqwmle7Ew2j8OlbkIu6uE3Y/etJQG8MLQs3Zy90xrp2C0BRrtPHG4zryw==",
+      "dev": true,
+      "dependencies": {
+        "@jest/environment": "^29.5.0",
+        "@jest/fake-timers": "^29.5.0",
+        "@jest/globals": "^29.5.0",
+        "@jest/source-map": "^29.4.3",
+        "@jest/test-result": "^29.5.0",
+        "@jest/transform": "^29.5.0",
+        "@jest/types": "^29.5.0",
+        "@types/node": "*",
+        "chalk": "^4.0.0",
+        "cjs-module-lexer": "^1.0.0",
+        "collect-v8-coverage": "^1.0.0",
+        "glob": "^7.1.3",
+        "graceful-fs": "^4.2.9",
+        "jest-haste-map": "^29.5.0",
+        "jest-message-util": "^29.5.0",
+        "jest-mock": "^29.5.0",
+        "jest-regex-util": "^29.4.3",
+        "jest-resolve": "^29.5.0",
+        "jest-snapshot": "^29.5.0",
+        "jest-util": "^29.5.0",
+        "slash": "^3.0.0",
+        "strip-bom": "^4.0.0"
+      },
       "engines": {
-        "node": ">=8"
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
       }
     },
-    "node_modules/is-glob": {
-      "version": "4.0.3",
-      "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
-      "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+    "node_modules/jest-runtime/node_modules/glob": {
+      "version": "7.2.3",
+      "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+      "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
+      "dev": true,
       "dependencies": {
-        "is-extglob": "^2.1.1"
+        "fs.realpath": "^1.0.0",
+        "inflight": "^1.0.4",
+        "inherits": "2",
+        "minimatch": "^3.1.1",
+        "once": "^1.3.0",
+        "path-is-absolute": "^1.0.0"
       },
       "engines": {
-        "node": ">=0.10.0"
+        "node": "*"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
       }
     },
-    "node_modules/is-interactive": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz",
-      "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==",
+    "node_modules/jest-snapshot": {
+      "version": "29.5.0",
+      "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.5.0.tgz",
+      "integrity": "sha512-x7Wolra5V0tt3wRs3/ts3S6ciSQVypgGQlJpz2rsdQYoUKxMxPNaoHMGJN6qAuPJqS+2iQ1ZUn5kl7HCyls84g==",
+      "dev": true,
+      "dependencies": {
+        "@babel/core": "^7.11.6",
+        "@babel/generator": "^7.7.2",
+        "@babel/plugin-syntax-jsx": "^7.7.2",
+        "@babel/plugin-syntax-typescript": "^7.7.2",
+        "@babel/traverse": "^7.7.2",
+        "@babel/types": "^7.3.3",
+        "@jest/expect-utils": "^29.5.0",
+        "@jest/transform": "^29.5.0",
+        "@jest/types": "^29.5.0",
+        "@types/babel__traverse": "^7.0.6",
+        "@types/prettier": "^2.1.5",
+        "babel-preset-current-node-syntax": "^1.0.0",
+        "chalk": "^4.0.0",
+        "expect": "^29.5.0",
+        "graceful-fs": "^4.2.9",
+        "jest-diff": "^29.5.0",
+        "jest-get-type": "^29.4.3",
+        "jest-matcher-utils": "^29.5.0",
+        "jest-message-util": "^29.5.0",
+        "jest-util": "^29.5.0",
+        "natural-compare": "^1.4.0",
+        "pretty-format": "^29.5.0",
+        "semver": "^7.3.5"
+      },
       "engines": {
-        "node": ">=8"
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
       }
     },
-    "node_modules/is-lambda": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz",
-      "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ=="
-    },
-    "node_modules/is-number": {
-      "version": "7.0.0",
-      "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
-      "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+    "node_modules/jest-util": {
+      "version": "29.5.0",
+      "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz",
+      "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==",
+      "dev": true,
+      "dependencies": {
+        "@jest/types": "^29.5.0",
+        "@types/node": "*",
+        "chalk": "^4.0.0",
+        "ci-info": "^3.2.0",
+        "graceful-fs": "^4.2.9",
+        "picomatch": "^2.2.3"
+      },
       "engines": {
-        "node": ">=0.12.0"
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
       }
     },
-    "node_modules/is-path-inside": {
-      "version": "3.0.3",
-      "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz",
-      "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==",
+    "node_modules/jest-validate": {
+      "version": "29.5.0",
+      "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.5.0.tgz",
+      "integrity": "sha512-pC26etNIi+y3HV8A+tUGr/lph9B18GnzSRAkPaaZJIE1eFdiYm6/CewuiJQ8/RlfHd1u/8Ioi8/sJ+CmbA+zAQ==",
       "dev": true,
+      "dependencies": {
+        "@jest/types": "^29.5.0",
+        "camelcase": "^6.2.0",
+        "chalk": "^4.0.0",
+        "jest-get-type": "^29.4.3",
+        "leven": "^3.1.0",
+        "pretty-format": "^29.5.0"
+      },
       "engines": {
-        "node": ">=8"
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
       }
     },
-    "node_modules/is-plain-obj": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz",
-      "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==",
+    "node_modules/jest-watcher": {
+      "version": "29.5.0",
+      "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.5.0.tgz",
+      "integrity": "sha512-KmTojKcapuqYrKDpRwfqcQ3zjMlwu27SYext9pt4GlF5FUgB+7XE1mcCnSm6a4uUpFyQIkb6ZhzZvHl+jiBCiA==",
       "dev": true,
+      "dependencies": {
+        "@jest/test-result": "^29.5.0",
+        "@jest/types": "^29.5.0",
+        "@types/node": "*",
+        "ansi-escapes": "^4.2.1",
+        "chalk": "^4.0.0",
+        "emittery": "^0.13.1",
+        "jest-util": "^29.5.0",
+        "string-length": "^4.0.1"
+      },
       "engines": {
-        "node": ">=8"
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
       }
     },
-    "node_modules/is-promise": {
-      "version": "2.2.2",
-      "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz",
-      "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==",
-      "dev": true
-    },
-    "node_modules/is-stream": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
-      "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
-      "engines": {
-        "node": ">=8"
+    "node_modules/jest-worker": {
+      "version": "29.5.0",
+      "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.5.0.tgz",
+      "integrity": "sha512-NcrQnevGoSp4b5kg+akIpthoAFHxPBcb5P6mYPY0fUNT+sSvmtu6jlkEle3anczUKIKEbMxFimk9oTP/tpIPgA==",
+      "dev": true,
+      "dependencies": {
+        "@types/node": "*",
+        "jest-util": "^29.5.0",
+        "merge-stream": "^2.0.0",
+        "supports-color": "^8.0.0"
       },
-      "funding": {
-        "url": "https://github.com/sponsors/sindresorhus"
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
       }
     },
-    "node_modules/is-unicode-supported": {
-      "version": "0.1.0",
-      "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz",
-      "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==",
+    "node_modules/jest-worker/node_modules/supports-color": {
+      "version": "8.1.1",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
+      "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
+      "dev": true,
+      "dependencies": {
+        "has-flag": "^4.0.0"
+      },
       "engines": {
         "node": ">=10"
       },
       "funding": {
-        "url": "https://github.com/sponsors/sindresorhus"
-      }
-    },
-    "node_modules/isarray": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
-      "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==",
-      "dev": true
-    },
-    "node_modules/isexe": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
-      "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="
-    },
-    "node_modules/iterare": {
-      "version": "1.2.1",
-      "resolved": "https://registry.npmjs.org/iterare/-/iterare-1.2.1.tgz",
-      "integrity": "sha512-RKYVTCjAnRthyJes037NX/IiqeidgN1xc3j1RjFfECFp28A1GVwK9nA+i0rJPaHqSZwygLzRnFlzUuHFoWWy+Q==",
-      "engines": {
-        "node": ">=6"
+        "url": "https://github.com/chalk/supports-color?sponsor=1"
       }
     },
     "node_modules/jiti": {
@@ -4983,7 +7016,6 @@
       "version": "2.5.2",
       "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz",
       "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==",
-      "peer": true,
       "bin": {
         "jsesc": "bin/jsesc"
       },
@@ -4996,6 +7028,12 @@
       "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
       "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ=="
     },
+    "node_modules/json-parse-even-better-errors": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
+      "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==",
+      "dev": true
+    },
     "node_modules/json-schema-to-typescript": {
       "version": "12.0.0",
       "resolved": "https://registry.npmjs.org/json-schema-to-typescript/-/json-schema-to-typescript-12.0.0.tgz",
@@ -5097,6 +7135,18 @@
       "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
       "dev": true
     },
+    "node_modules/json5": {
+      "version": "2.2.3",
+      "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
+      "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
+      "dev": true,
+      "bin": {
+        "json5": "lib/cli.js"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
     "node_modules/jsonfile": {
       "version": "6.1.0",
       "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
@@ -5211,6 +7261,12 @@
       "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
       "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
     },
+    "node_modules/lodash.memoize": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",
+      "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==",
+      "dev": true
+    },
     "node_modules/lodash.merge": {
       "version": "4.6.2",
       "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
@@ -5306,6 +7362,36 @@
         "node": ">= 6"
       }
     },
+    "node_modules/make-dir": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
+      "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
+      "dev": true,
+      "dependencies": {
+        "semver": "^6.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/make-dir/node_modules/semver": {
+      "version": "6.3.0",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+      "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+      "dev": true,
+      "bin": {
+        "semver": "bin/semver.js"
+      }
+    },
+    "node_modules/make-error": {
+      "version": "1.3.6",
+      "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
+      "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
+      "dev": true
+    },
     "node_modules/make-fetch-happen": {
       "version": "10.2.1",
       "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-10.2.1.tgz",
@@ -5361,6 +7447,15 @@
         "node": ">=12"
       }
     },
+    "node_modules/makeerror": {
+      "version": "1.0.12",
+      "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz",
+      "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==",
+      "dev": true,
+      "dependencies": {
+        "tmpl": "1.0.5"
+      }
+    },
     "node_modules/markdown-it": {
       "version": "12.3.2",
       "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz",
@@ -6372,6 +8467,18 @@
         "url": "https://github.com/sponsors/isaacs"
       }
     },
+    "node_modules/node-int64": {
+      "version": "0.4.0",
+      "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz",
+      "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==",
+      "dev": true
+    },
+    "node_modules/node-releases": {
+      "version": "2.0.12",
+      "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.12.tgz",
+      "integrity": "sha512-QzsYKWhXTWx8h1kIvqfnC++o0pEmpRQA/aenALsL2F4pqNVr7YzcdMlDij5WBnwftRbJCNJL/O7zdKaxKPHqgQ==",
+      "dev": true
+    },
     "node_modules/nopt": {
       "version": "6.0.0",
       "resolved": "https://registry.npmjs.org/nopt/-/nopt-6.0.0.tgz",
@@ -6608,6 +8715,15 @@
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
+    "node_modules/p-try": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
+      "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
     "node_modules/parent-module": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
@@ -6620,6 +8736,24 @@
         "node": ">=6"
       }
     },
+    "node_modules/parse-json": {
+      "version": "5.2.0",
+      "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
+      "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==",
+      "dev": true,
+      "dependencies": {
+        "@babel/code-frame": "^7.0.0",
+        "error-ex": "^1.3.1",
+        "json-parse-even-better-errors": "^2.3.0",
+        "lines-and-columns": "^1.1.6"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
     "node_modules/parse-semver": {
       "version": "1.1.1",
       "resolved": "https://registry.npmjs.org/parse-semver/-/parse-semver-1.1.1.tgz",
@@ -6760,6 +8894,70 @@
         "node": ">= 6"
       }
     },
+    "node_modules/pkg-dir": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz",
+      "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==",
+      "dev": true,
+      "dependencies": {
+        "find-up": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/pkg-dir/node_modules/find-up": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
+      "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+      "dev": true,
+      "dependencies": {
+        "locate-path": "^5.0.0",
+        "path-exists": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/pkg-dir/node_modules/locate-path": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
+      "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+      "dev": true,
+      "dependencies": {
+        "p-locate": "^4.1.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/pkg-dir/node_modules/p-limit": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+      "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+      "dev": true,
+      "dependencies": {
+        "p-try": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/pkg-dir/node_modules/p-locate": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
+      "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
+      "dev": true,
+      "dependencies": {
+        "p-limit": "^2.2.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
     "node_modules/postcss": {
       "version": "8.4.24",
       "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.24.tgz",
@@ -6902,9 +9100,9 @@
       }
     },
     "node_modules/posthog-js": {
-      "version": "1.63.3",
-      "resolved": "https://registry.npmjs.org/posthog-js/-/posthog-js-1.63.3.tgz",
-      "integrity": "sha512-Ob2x1ENxx/mWAdhLhc6ouKAph9LwmitBy7M+hiaFoS0T9g7OVL4lYdrJbODbYV+HX/HeO3bsnQwYO1QLPWm/YA==",
+      "version": "1.68.5",
+      "resolved": "https://registry.npmjs.org/posthog-js/-/posthog-js-1.68.5.tgz",
+      "integrity": "sha512-EqQuIX0k564T2fhmzQK2Gcb8s/XRhHTpk6JOeGtJV7lpMI8Hffe+gGjGHcqIc4RoOg3LjAGYNHj6XgN+QPggLg==",
       "dependencies": {
         "fflate": "^0.4.1"
       }
@@ -6953,10 +9151,36 @@
         "prettier": "bin-prettier.js"
       },
       "engines": {
-        "node": ">=10.13.0"
+        "node": ">=10.13.0"
+      },
+      "funding": {
+        "url": "https://github.com/prettier/prettier?sponsor=1"
+      }
+    },
+    "node_modules/pretty-format": {
+      "version": "29.5.0",
+      "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz",
+      "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==",
+      "dev": true,
+      "dependencies": {
+        "@jest/schemas": "^29.4.3",
+        "ansi-styles": "^5.0.0",
+        "react-is": "^18.0.0"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      }
+    },
+    "node_modules/pretty-format/node_modules/ansi-styles": {
+      "version": "5.2.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
+      "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
+      "dev": true,
+      "engines": {
+        "node": ">=10"
       },
       "funding": {
-        "url": "https://github.com/prettier/prettier?sponsor=1"
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
       }
     },
     "node_modules/process-exists": {
@@ -7004,6 +9228,28 @@
         "node": ">=10"
       }
     },
+    "node_modules/prompts": {
+      "version": "2.4.2",
+      "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz",
+      "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==",
+      "dev": true,
+      "dependencies": {
+        "kleur": "^3.0.3",
+        "sisteransi": "^1.0.5"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/prompts/node_modules/kleur": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz",
+      "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==",
+      "dev": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
     "node_modules/prop-types": {
       "version": "15.8.1",
       "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
@@ -7062,6 +9308,22 @@
         "node": ">=6"
       }
     },
+    "node_modules/pure-rand": {
+      "version": "6.0.2",
+      "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.0.2.tgz",
+      "integrity": "sha512-6Yg0ekpKICSjPswYOuC5sku/TSWaRYlA0qsXqJgM/d/4pLPHPuTxK7Nbf7jFKzAeedUhR8C7K9Uv63FBsSo8xQ==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "individual",
+          "url": "https://github.com/sponsors/dubzzz"
+        },
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/fast-check"
+        }
+      ]
+    },
     "node_modules/qs": {
       "version": "6.11.0",
       "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
@@ -7391,6 +9653,27 @@
       "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz",
       "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g=="
     },
+    "node_modules/resolve-cwd": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz",
+      "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==",
+      "dev": true,
+      "dependencies": {
+        "resolve-from": "^5.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/resolve-cwd/node_modules/resolve-from": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
+      "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
     "node_modules/resolve-from": {
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
@@ -7400,6 +9683,15 @@
         "node": ">=4"
       }
     },
+    "node_modules/resolve.exports": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz",
+      "integrity": "sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==",
+      "dev": true,
+      "engines": {
+        "node": ">=10"
+      }
+    },
     "node_modules/responselike": {
       "version": "2.0.1",
       "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz",
@@ -7585,9 +9877,9 @@
       }
     },
     "node_modules/semver": {
-      "version": "7.3.8",
-      "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
-      "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
+      "version": "7.5.3",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz",
+      "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==",
       "dependencies": {
         "lru-cache": "^6.0.0"
       },
@@ -7707,6 +9999,12 @@
         "simple-concat": "^1.0.0"
       }
     },
+    "node_modules/sisteransi": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz",
+      "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==",
+      "dev": true
+    },
     "node_modules/slash": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
@@ -7751,6 +10049,15 @@
         "node": ">= 10"
       }
     },
+    "node_modules/source-map": {
+      "version": "0.6.1",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+      "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
     "node_modules/source-map-js": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
@@ -7759,6 +10066,16 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/source-map-support": {
+      "version": "0.5.13",
+      "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz",
+      "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==",
+      "dev": true,
+      "dependencies": {
+        "buffer-from": "^1.0.0",
+        "source-map": "^0.6.0"
+      }
+    },
     "node_modules/space-separated-tokens": {
       "version": "2.0.2",
       "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz",
@@ -7774,6 +10091,12 @@
       "integrity": "sha512-n98l9E2RMSJ9ON1AKisHzz7V42VDiBQGY6PB1BwRglz99wpVsSuGzQ+jOi6lFXBGVTCrRpltvjm+/XA+tpeJrg==",
       "dev": true
     },
+    "node_modules/sprintf-js": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
+      "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==",
+      "dev": true
+    },
     "node_modules/ssri": {
       "version": "9.0.1",
       "resolved": "https://registry.npmjs.org/ssri/-/ssri-9.0.1.tgz",
@@ -7785,6 +10108,27 @@
         "node": "^12.13.0 || ^14.15.0 || >=16.0.0"
       }
     },
+    "node_modules/stack-utils": {
+      "version": "2.0.6",
+      "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz",
+      "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==",
+      "dev": true,
+      "dependencies": {
+        "escape-string-regexp": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/stack-utils/node_modules/escape-string-regexp": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz",
+      "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
     "node_modules/string_decoder": {
       "version": "1.1.1",
       "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
@@ -7798,6 +10142,40 @@
       "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
       "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
     },
+    "node_modules/string-length": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz",
+      "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==",
+      "dev": true,
+      "dependencies": {
+        "char-regex": "^1.0.2",
+        "strip-ansi": "^6.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/string-length/node_modules/ansi-regex": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+      "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/string-length/node_modules/strip-ansi": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+      "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+      "dev": true,
+      "dependencies": {
+        "ansi-regex": "^5.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
     "node_modules/string-width": {
       "version": "4.2.3",
       "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
@@ -7844,6 +10222,15 @@
         "url": "https://github.com/chalk/strip-ansi?sponsor=1"
       }
     },
+    "node_modules/strip-bom": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz",
+      "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
     "node_modules/strip-final-newline": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz",
@@ -8131,6 +10518,40 @@
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
+    "node_modules/test-exclude": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz",
+      "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==",
+      "dev": true,
+      "dependencies": {
+        "@istanbuljs/schema": "^0.1.2",
+        "glob": "^7.1.4",
+        "minimatch": "^3.0.4"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/test-exclude/node_modules/glob": {
+      "version": "7.2.3",
+      "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+      "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
+      "dev": true,
+      "dependencies": {
+        "fs.realpath": "^1.0.0",
+        "inflight": "^1.0.4",
+        "inherits": "2",
+        "minimatch": "^3.1.1",
+        "once": "^1.3.0",
+        "path-is-absolute": "^1.0.0"
+      },
+      "engines": {
+        "node": "*"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
     "node_modules/text-table": {
       "version": "0.2.0",
       "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
@@ -8184,11 +10605,16 @@
         "node": ">=8.17.0"
       }
     },
+    "node_modules/tmpl": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz",
+      "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==",
+      "dev": true
+    },
     "node_modules/to-fast-properties": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
       "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==",
-      "peer": true,
       "engines": {
         "node": ">=4"
       }
@@ -8250,6 +10676,58 @@
       "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz",
       "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA=="
     },
+    "node_modules/ts-jest": {
+      "version": "29.1.1",
+      "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.1.1.tgz",
+      "integrity": "sha512-D6xjnnbP17cC85nliwGiL+tpoKN0StpgE0TeOjXQTU6MVCfsB4v7aW05CgQ/1OywGb0x/oy9hHFnN+sczTiRaA==",
+      "dev": true,
+      "dependencies": {
+        "bs-logger": "0.x",
+        "fast-json-stable-stringify": "2.x",
+        "jest-util": "^29.0.0",
+        "json5": "^2.2.3",
+        "lodash.memoize": "4.x",
+        "make-error": "1.x",
+        "semver": "^7.5.3",
+        "yargs-parser": "^21.0.1"
+      },
+      "bin": {
+        "ts-jest": "cli.js"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      },
+      "peerDependencies": {
+        "@babel/core": ">=7.0.0-beta.0 <8",
+        "@jest/types": "^29.0.0",
+        "babel-jest": "^29.0.0",
+        "jest": "^29.0.0",
+        "typescript": ">=4.3 <6"
+      },
+      "peerDependenciesMeta": {
+        "@babel/core": {
+          "optional": true
+        },
+        "@jest/types": {
+          "optional": true
+        },
+        "babel-jest": {
+          "optional": true
+        },
+        "esbuild": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/ts-jest/node_modules/yargs-parser": {
+      "version": "21.1.1",
+      "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
+      "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
+      "dev": true,
+      "engines": {
+        "node": ">=12"
+      }
+    },
     "node_modules/tslib": {
       "version": "1.14.1",
       "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
@@ -8309,6 +10787,15 @@
         "node": ">= 0.8.0"
       }
     },
+    "node_modules/type-detect": {
+      "version": "4.0.8",
+      "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz",
+      "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==",
+      "dev": true,
+      "engines": {
+        "node": ">=4"
+      }
+    },
     "node_modules/type-fest": {
       "version": "0.20.2",
       "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
@@ -8518,6 +11005,36 @@
         "setimmediate": "~1.0.4"
       }
     },
+    "node_modules/update-browserslist-db": {
+      "version": "1.0.11",
+      "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz",
+      "integrity": "sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/browserslist"
+        },
+        {
+          "type": "tidelift",
+          "url": "https://tidelift.com/funding/github/npm/browserslist"
+        },
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
+      "dependencies": {
+        "escalade": "^3.1.1",
+        "picocolors": "^1.0.0"
+      },
+      "bin": {
+        "update-browserslist-db": "cli.js"
+      },
+      "peerDependencies": {
+        "browserslist": ">= 4.21.0"
+      }
+    },
     "node_modules/uri-js": {
       "version": "4.4.1",
       "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
@@ -8571,6 +11088,26 @@
         "node": ">=8"
       }
     },
+    "node_modules/v8-to-istanbul": {
+      "version": "9.1.0",
+      "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.1.0.tgz",
+      "integrity": "sha512-6z3GW9x8G1gd+JIIgQQQxXuiJtCXeAjp6RaPEPLv62mH3iPHPxV6W3robxtCzNErRo6ZwTmzWhsbNvjyEBKzKA==",
+      "dev": true,
+      "dependencies": {
+        "@jridgewell/trace-mapping": "^0.3.12",
+        "@types/istanbul-lib-coverage": "^2.0.1",
+        "convert-source-map": "^1.6.0"
+      },
+      "engines": {
+        "node": ">=10.12.0"
+      }
+    },
+    "node_modules/v8-to-istanbul/node_modules/convert-source-map": {
+      "version": "1.9.0",
+      "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz",
+      "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==",
+      "dev": true
+    },
     "node_modules/vfile": {
       "version": "5.3.7",
       "resolved": "https://registry.npmjs.org/vfile/-/vfile-5.3.7.tgz",
@@ -8816,6 +11353,15 @@
       "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.2.tgz",
       "integrity": "sha512-zHhCWatviizPIq9B7Vh9uvrH6x3sK8itC84HkamnBWoDFJtzBf7SWlpLCZUit72b3os45h6RWQNC9xHRDF8dRA=="
     },
+    "node_modules/walker": {
+      "version": "1.0.8",
+      "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz",
+      "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==",
+      "dev": true,
+      "dependencies": {
+        "makeerror": "1.0.12"
+      }
+    },
     "node_modules/wcwidth": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz",
@@ -8915,6 +11461,19 @@
       "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
       "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
     },
+    "node_modules/write-file-atomic": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz",
+      "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==",
+      "dev": true,
+      "dependencies": {
+        "imurmurhash": "^0.1.4",
+        "signal-exit": "^3.0.7"
+      },
+      "engines": {
+        "node": "^12.13.0 || ^14.15.0 || >=16.0.0"
+      }
+    },
     "node_modules/ws": {
       "version": "8.13.0",
       "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz",
@@ -9058,22 +11617,73 @@
       "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz",
       "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw=="
     },
+    "@ampproject/remapping": {
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz",
+      "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==",
+      "dev": true,
+      "requires": {
+        "@jridgewell/gen-mapping": "^0.3.0",
+        "@jridgewell/trace-mapping": "^0.3.9"
+      }
+    },
     "@babel/code-frame": {
-      "version": "7.21.4",
-      "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.21.4.tgz",
-      "integrity": "sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g==",
-      "peer": true,
+      "version": "7.22.5",
+      "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.5.tgz",
+      "integrity": "sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ==",
       "requires": {
-        "@babel/highlight": "^7.18.6"
+        "@babel/highlight": "^7.22.5"
+      }
+    },
+    "@babel/compat-data": {
+      "version": "7.22.5",
+      "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.5.tgz",
+      "integrity": "sha512-4Jc/YuIaYqKnDDz892kPIledykKg12Aw1PYX5i/TY28anJtacvM1Rrr8wbieB9GfEJwlzqT0hUEao0CxEebiDA==",
+      "dev": true
+    },
+    "@babel/core": {
+      "version": "7.22.5",
+      "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.22.5.tgz",
+      "integrity": "sha512-SBuTAjg91A3eKOvD+bPEz3LlhHZRNu1nFOVts9lzDJTXshHTjII0BAtDS3Y2DAkdZdDKWVZGVwkDfc4Clxn1dg==",
+      "dev": true,
+      "requires": {
+        "@ampproject/remapping": "^2.2.0",
+        "@babel/code-frame": "^7.22.5",
+        "@babel/generator": "^7.22.5",
+        "@babel/helper-compilation-targets": "^7.22.5",
+        "@babel/helper-module-transforms": "^7.22.5",
+        "@babel/helpers": "^7.22.5",
+        "@babel/parser": "^7.22.5",
+        "@babel/template": "^7.22.5",
+        "@babel/traverse": "^7.22.5",
+        "@babel/types": "^7.22.5",
+        "convert-source-map": "^1.7.0",
+        "debug": "^4.1.0",
+        "gensync": "^1.0.0-beta.2",
+        "json5": "^2.2.2",
+        "semver": "^6.3.0"
+      },
+      "dependencies": {
+        "convert-source-map": {
+          "version": "1.9.0",
+          "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz",
+          "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==",
+          "dev": true
+        },
+        "semver": {
+          "version": "6.3.0",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+          "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+          "dev": true
+        }
       }
     },
     "@babel/generator": {
-      "version": "7.21.4",
-      "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.21.4.tgz",
-      "integrity": "sha512-NieM3pVIYW2SwGzKoqfPrQsf4xGs9M9AIG3ThppsSRmO+m7eQhmI6amajKMUeIO37wFfsvnvcxQFx6x6iqxDnA==",
-      "peer": true,
+      "version": "7.22.5",
+      "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.5.tgz",
+      "integrity": "sha512-+lcUbnTRhd0jOewtFSedLyiPsD5tswKkbgcezOqqWFUVNEwoUTlpPOBmvhG7OXWLR4jMdv0czPGH5XbflnD1EA==",
       "requires": {
-        "@babel/types": "^7.21.4",
+        "@babel/types": "^7.22.5",
         "@jridgewell/gen-mapping": "^0.3.2",
         "@jridgewell/trace-mapping": "^0.3.17",
         "jsesc": "^2.5.1"
@@ -9088,68 +11698,144 @@
         "@babel/types": "^7.18.6"
       }
     },
+    "@babel/helper-compilation-targets": {
+      "version": "7.22.5",
+      "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.5.tgz",
+      "integrity": "sha512-Ji+ywpHeuqxB8WDxraCiqR0xfhYjiDE/e6k7FuIaANnoOFxAHskHChz4vA1mJC9Lbm01s1PVAGhQY4FUKSkGZw==",
+      "dev": true,
+      "requires": {
+        "@babel/compat-data": "^7.22.5",
+        "@babel/helper-validator-option": "^7.22.5",
+        "browserslist": "^4.21.3",
+        "lru-cache": "^5.1.1",
+        "semver": "^6.3.0"
+      },
+      "dependencies": {
+        "lru-cache": {
+          "version": "5.1.1",
+          "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
+          "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
+          "dev": true,
+          "requires": {
+            "yallist": "^3.0.2"
+          }
+        },
+        "semver": {
+          "version": "6.3.0",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+          "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+          "dev": true
+        },
+        "yallist": {
+          "version": "3.1.1",
+          "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
+          "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
+          "dev": true
+        }
+      }
+    },
     "@babel/helper-environment-visitor": {
-      "version": "7.18.9",
-      "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz",
-      "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==",
-      "peer": true
+      "version": "7.22.5",
+      "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz",
+      "integrity": "sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q=="
     },
     "@babel/helper-function-name": {
-      "version": "7.21.0",
-      "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.21.0.tgz",
-      "integrity": "sha512-HfK1aMRanKHpxemaY2gqBmL04iAPOPRj7DxtNbiDOrJK+gdwkiNRVpCpUJYbUT+aZyemKN8brqTOxzCaG6ExRg==",
-      "peer": true,
+      "version": "7.22.5",
+      "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz",
+      "integrity": "sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==",
       "requires": {
-        "@babel/template": "^7.20.7",
-        "@babel/types": "^7.21.0"
+        "@babel/template": "^7.22.5",
+        "@babel/types": "^7.22.5"
       }
     },
     "@babel/helper-hoist-variables": {
-      "version": "7.18.6",
-      "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz",
-      "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==",
-      "peer": true,
+      "version": "7.22.5",
+      "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz",
+      "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==",
       "requires": {
-        "@babel/types": "^7.18.6"
+        "@babel/types": "^7.22.5"
       }
     },
     "@babel/helper-module-imports": {
-      "version": "7.21.4",
-      "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.21.4.tgz",
-      "integrity": "sha512-orajc5T2PsRYUN3ZryCEFeMDYwyw09c/pZeaQEZPH0MpKzSvn3e0uXsDBu3k03VI+9DBiRo+l22BfKTpKwa/Wg==",
-      "peer": true,
+      "version": "7.22.5",
+      "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.5.tgz",
+      "integrity": "sha512-8Dl6+HD/cKifutF5qGd/8ZJi84QeAKh+CEe1sBzz8UayBBGg1dAIJrdHOcOM5b2MpzWL2yuotJTtGjETq0qjXg==",
+      "requires": {
+        "@babel/types": "^7.22.5"
+      }
+    },
+    "@babel/helper-module-transforms": {
+      "version": "7.22.5",
+      "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.22.5.tgz",
+      "integrity": "sha512-+hGKDt/Ze8GFExiVHno/2dvG5IdstpzCq0y4Qc9OJ25D4q3pKfiIP/4Vp3/JvhDkLKsDK2api3q3fpIgiIF5bw==",
+      "dev": true,
+      "requires": {
+        "@babel/helper-environment-visitor": "^7.22.5",
+        "@babel/helper-module-imports": "^7.22.5",
+        "@babel/helper-simple-access": "^7.22.5",
+        "@babel/helper-split-export-declaration": "^7.22.5",
+        "@babel/helper-validator-identifier": "^7.22.5",
+        "@babel/template": "^7.22.5",
+        "@babel/traverse": "^7.22.5",
+        "@babel/types": "^7.22.5"
+      }
+    },
+    "@babel/helper-plugin-utils": {
+      "version": "7.22.5",
+      "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz",
+      "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==",
+      "dev": true
+    },
+    "@babel/helper-simple-access": {
+      "version": "7.22.5",
+      "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz",
+      "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==",
+      "dev": true,
       "requires": {
-        "@babel/types": "^7.21.4"
+        "@babel/types": "^7.22.5"
       }
     },
     "@babel/helper-split-export-declaration": {
-      "version": "7.18.6",
-      "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz",
-      "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==",
-      "peer": true,
+      "version": "7.22.5",
+      "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.5.tgz",
+      "integrity": "sha512-thqK5QFghPKWLhAV321lxF95yCg2K3Ob5yw+M3VHWfdia0IkPXUtoLH8x/6Fh486QUvzhb8YOWHChTVen2/PoQ==",
       "requires": {
-        "@babel/types": "^7.18.6"
+        "@babel/types": "^7.22.5"
       }
     },
     "@babel/helper-string-parser": {
-      "version": "7.19.4",
-      "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz",
-      "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==",
-      "peer": true
+      "version": "7.22.5",
+      "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz",
+      "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw=="
     },
     "@babel/helper-validator-identifier": {
-      "version": "7.19.1",
-      "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz",
-      "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==",
-      "peer": true
+      "version": "7.22.5",
+      "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz",
+      "integrity": "sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ=="
+    },
+    "@babel/helper-validator-option": {
+      "version": "7.22.5",
+      "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.5.tgz",
+      "integrity": "sha512-R3oB6xlIVKUnxNUxbmgq7pKjxpru24zlimpE8WK47fACIlM0II/Hm1RS8IaOI7NgCr6LNS+jl5l75m20npAziw==",
+      "dev": true
+    },
+    "@babel/helpers": {
+      "version": "7.22.5",
+      "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.22.5.tgz",
+      "integrity": "sha512-pSXRmfE1vzcUIDFQcSGA5Mr+GxBV9oiRKDuDxXvWQQBCh8HoIjs/2DlDB7H8smac1IVrB9/xdXj2N3Wol9Cr+Q==",
+      "dev": true,
+      "requires": {
+        "@babel/template": "^7.22.5",
+        "@babel/traverse": "^7.22.5",
+        "@babel/types": "^7.22.5"
+      }
     },
     "@babel/highlight": {
-      "version": "7.18.6",
-      "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz",
-      "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==",
-      "peer": true,
+      "version": "7.22.5",
+      "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.5.tgz",
+      "integrity": "sha512-BSKlD1hgnedS5XRnGOljZawtag7H1yPfQp0tdNJCHoH6AZ+Pcm9VvkrK59/Yy593Ypg0zMxH2BxD1VPYUQ7UIw==",
       "requires": {
-        "@babel/helper-validator-identifier": "^7.18.6",
+        "@babel/helper-validator-identifier": "^7.22.5",
         "chalk": "^2.0.0",
         "js-tokens": "^4.0.0"
       },
@@ -9158,7 +11844,6 @@
           "version": "3.2.1",
           "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
           "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
-          "peer": true,
           "requires": {
             "color-convert": "^1.9.0"
           }
@@ -9167,7 +11852,6 @@
           "version": "2.4.2",
           "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
           "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
-          "peer": true,
           "requires": {
             "ansi-styles": "^3.2.1",
             "escape-string-regexp": "^1.0.5",
@@ -9178,7 +11862,6 @@
           "version": "1.9.3",
           "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
           "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
-          "peer": true,
           "requires": {
             "color-name": "1.1.3"
           }
@@ -9186,26 +11869,22 @@
         "color-name": {
           "version": "1.1.3",
           "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
-          "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
-          "peer": true
+          "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="
         },
         "escape-string-regexp": {
           "version": "1.0.5",
           "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
-          "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
-          "peer": true
+          "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg=="
         },
         "has-flag": {
           "version": "3.0.0",
           "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
-          "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
-          "peer": true
+          "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw=="
         },
         "supports-color": {
           "version": "5.5.0",
           "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
           "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
-          "peer": true,
           "requires": {
             "has-flag": "^3.0.0"
           }
@@ -9213,10 +11892,135 @@
       }
     },
     "@babel/parser": {
-      "version": "7.21.4",
-      "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.21.4.tgz",
-      "integrity": "sha512-alVJj7k7zIxqBZ7BTRhz0IqJFxW1VJbm6N8JbcYhQ186df9ZBPbZBmWSqAMXwHGsCJdYks7z/voa3ibiS5bCIw==",
-      "peer": true
+      "version": "7.22.5",
+      "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.5.tgz",
+      "integrity": "sha512-DFZMC9LJUG9PLOclRC32G63UXwzqS2koQC8dkx+PLdmt1xSePYpbT/NbsrJy8Q/muXz7o/h/d4A7Fuyixm559Q=="
+    },
+    "@babel/plugin-syntax-async-generators": {
+      "version": "7.8.4",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz",
+      "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==",
+      "dev": true,
+      "requires": {
+        "@babel/helper-plugin-utils": "^7.8.0"
+      }
+    },
+    "@babel/plugin-syntax-bigint": {
+      "version": "7.8.3",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz",
+      "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==",
+      "dev": true,
+      "requires": {
+        "@babel/helper-plugin-utils": "^7.8.0"
+      }
+    },
+    "@babel/plugin-syntax-class-properties": {
+      "version": "7.12.13",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz",
+      "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==",
+      "dev": true,
+      "requires": {
+        "@babel/helper-plugin-utils": "^7.12.13"
+      }
+    },
+    "@babel/plugin-syntax-import-meta": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz",
+      "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==",
+      "dev": true,
+      "requires": {
+        "@babel/helper-plugin-utils": "^7.10.4"
+      }
+    },
+    "@babel/plugin-syntax-json-strings": {
+      "version": "7.8.3",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz",
+      "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==",
+      "dev": true,
+      "requires": {
+        "@babel/helper-plugin-utils": "^7.8.0"
+      }
+    },
+    "@babel/plugin-syntax-jsx": {
+      "version": "7.22.5",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.22.5.tgz",
+      "integrity": "sha512-gvyP4hZrgrs/wWMaocvxZ44Hw0b3W8Pe+cMxc8V1ULQ07oh8VNbIRaoD1LRZVTvD+0nieDKjfgKg89sD7rrKrg==",
+      "dev": true,
+      "requires": {
+        "@babel/helper-plugin-utils": "^7.22.5"
+      }
+    },
+    "@babel/plugin-syntax-logical-assignment-operators": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz",
+      "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==",
+      "dev": true,
+      "requires": {
+        "@babel/helper-plugin-utils": "^7.10.4"
+      }
+    },
+    "@babel/plugin-syntax-nullish-coalescing-operator": {
+      "version": "7.8.3",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz",
+      "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==",
+      "dev": true,
+      "requires": {
+        "@babel/helper-plugin-utils": "^7.8.0"
+      }
+    },
+    "@babel/plugin-syntax-numeric-separator": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz",
+      "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==",
+      "dev": true,
+      "requires": {
+        "@babel/helper-plugin-utils": "^7.10.4"
+      }
+    },
+    "@babel/plugin-syntax-object-rest-spread": {
+      "version": "7.8.3",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz",
+      "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==",
+      "dev": true,
+      "requires": {
+        "@babel/helper-plugin-utils": "^7.8.0"
+      }
+    },
+    "@babel/plugin-syntax-optional-catch-binding": {
+      "version": "7.8.3",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz",
+      "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==",
+      "dev": true,
+      "requires": {
+        "@babel/helper-plugin-utils": "^7.8.0"
+      }
+    },
+    "@babel/plugin-syntax-optional-chaining": {
+      "version": "7.8.3",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz",
+      "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==",
+      "dev": true,
+      "requires": {
+        "@babel/helper-plugin-utils": "^7.8.0"
+      }
+    },
+    "@babel/plugin-syntax-top-level-await": {
+      "version": "7.14.5",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz",
+      "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==",
+      "dev": true,
+      "requires": {
+        "@babel/helper-plugin-utils": "^7.14.5"
+      }
+    },
+    "@babel/plugin-syntax-typescript": {
+      "version": "7.22.5",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.22.5.tgz",
+      "integrity": "sha512-1mS2o03i7t1c6VzH6fdQ3OA8tcEIxwG18zIPRp+UY1Ihv6W+XZzBCVxExF9upussPXJ0xE9XRHwMoNs1ep/nRQ==",
+      "dev": true,
+      "requires": {
+        "@babel/helper-plugin-utils": "^7.22.5"
+      }
     },
     "@babel/runtime": {
       "version": "7.21.0",
@@ -9227,30 +12031,28 @@
       }
     },
     "@babel/template": {
-      "version": "7.20.7",
-      "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz",
-      "integrity": "sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==",
-      "peer": true,
+      "version": "7.22.5",
+      "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.5.tgz",
+      "integrity": "sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw==",
       "requires": {
-        "@babel/code-frame": "^7.18.6",
-        "@babel/parser": "^7.20.7",
-        "@babel/types": "^7.20.7"
+        "@babel/code-frame": "^7.22.5",
+        "@babel/parser": "^7.22.5",
+        "@babel/types": "^7.22.5"
       }
     },
     "@babel/traverse": {
-      "version": "7.21.4",
-      "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.21.4.tgz",
-      "integrity": "sha512-eyKrRHKdyZxqDm+fV1iqL9UAHMoIg0nDaGqfIOd8rKH17m5snv7Gn4qgjBoFfLz9APvjFU/ICT00NVCv1Epp8Q==",
-      "peer": true,
-      "requires": {
-        "@babel/code-frame": "^7.21.4",
-        "@babel/generator": "^7.21.4",
-        "@babel/helper-environment-visitor": "^7.18.9",
-        "@babel/helper-function-name": "^7.21.0",
-        "@babel/helper-hoist-variables": "^7.18.6",
-        "@babel/helper-split-export-declaration": "^7.18.6",
-        "@babel/parser": "^7.21.4",
-        "@babel/types": "^7.21.4",
+      "version": "7.22.5",
+      "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.5.tgz",
+      "integrity": "sha512-7DuIjPgERaNo6r+PZwItpjCZEa5vyw4eJGufeLxrPdBXBoLcCJCIasvK6pK/9DVNrLZTLFhUGqaC6X/PA007TQ==",
+      "requires": {
+        "@babel/code-frame": "^7.22.5",
+        "@babel/generator": "^7.22.5",
+        "@babel/helper-environment-visitor": "^7.22.5",
+        "@babel/helper-function-name": "^7.22.5",
+        "@babel/helper-hoist-variables": "^7.22.5",
+        "@babel/helper-split-export-declaration": "^7.22.5",
+        "@babel/parser": "^7.22.5",
+        "@babel/types": "^7.22.5",
         "debug": "^4.1.0",
         "globals": "^11.1.0"
       },
@@ -9258,19 +12060,17 @@
         "globals": {
           "version": "11.12.0",
           "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
-          "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==",
-          "peer": true
+          "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA=="
         }
       }
     },
     "@babel/types": {
-      "version": "7.21.4",
-      "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.21.4.tgz",
-      "integrity": "sha512-rU2oY501qDxE8Pyo7i/Orqma4ziCOrby0/9mvbDUGEfvZjb279Nk9k19e2fiCxHbRRpY2ZyrgW1eq22mvmOIzA==",
-      "peer": true,
+      "version": "7.22.5",
+      "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.5.tgz",
+      "integrity": "sha512-zo3MIHGOkPOfoRXitsgHLjEXmlDaD/5KU1Uzuc9GNiZPhSqVxVRtxuPaSBZDsYZ9qV88AjtMtWW7ww98loJ9KA==",
       "requires": {
-        "@babel/helper-string-parser": "^7.19.4",
-        "@babel/helper-validator-identifier": "^7.19.1",
+        "@babel/helper-string-parser": "^7.22.5",
+        "@babel/helper-validator-identifier": "^7.22.5",
         "to-fast-properties": "^2.0.0"
       }
     },
@@ -9286,6 +12086,12 @@
         "js-yaml": "^4.1.0"
       }
     },
+    "@bcoe/v8-coverage": {
+      "version": "0.2.3",
+      "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz",
+      "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==",
+      "dev": true
+    },
     "@electron/rebuild": {
       "version": "3.2.10",
       "resolved": "https://registry.npmjs.org/@electron/rebuild/-/rebuild-3.2.10.tgz",
@@ -9480,80 +12286,437 @@
       "integrity": "sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==",
       "optional": true
     },
-    "@esbuild/openbsd-x64": {
-      "version": "0.17.19",
-      "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.19.tgz",
-      "integrity": "sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==",
-      "optional": true
+    "@esbuild/openbsd-x64": {
+      "version": "0.17.19",
+      "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.19.tgz",
+      "integrity": "sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==",
+      "optional": true
+    },
+    "@esbuild/sunos-x64": {
+      "version": "0.17.19",
+      "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.19.tgz",
+      "integrity": "sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==",
+      "optional": true
+    },
+    "@esbuild/win32-arm64": {
+      "version": "0.17.19",
+      "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.19.tgz",
+      "integrity": "sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==",
+      "optional": true
+    },
+    "@esbuild/win32-ia32": {
+      "version": "0.17.19",
+      "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.19.tgz",
+      "integrity": "sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==",
+      "optional": true
+    },
+    "@esbuild/win32-x64": {
+      "version": "0.17.19",
+      "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.19.tgz",
+      "integrity": "sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==",
+      "optional": true
+    },
+    "@eslint/eslintrc": {
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz",
+      "integrity": "sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==",
+      "dev": true,
+      "requires": {
+        "ajv": "^6.12.4",
+        "debug": "^4.3.2",
+        "espree": "^9.4.0",
+        "globals": "^13.19.0",
+        "ignore": "^5.2.0",
+        "import-fresh": "^3.2.1",
+        "js-yaml": "^4.1.0",
+        "minimatch": "^3.1.2",
+        "strip-json-comments": "^3.1.1"
+      }
+    },
+    "@gar/promisify": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz",
+      "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw=="
+    },
+    "@humanwhocodes/config-array": {
+      "version": "0.11.8",
+      "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz",
+      "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==",
+      "dev": true,
+      "requires": {
+        "@humanwhocodes/object-schema": "^1.2.1",
+        "debug": "^4.1.1",
+        "minimatch": "^3.0.5"
+      }
+    },
+    "@humanwhocodes/module-importer": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
+      "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==",
+      "dev": true
+    },
+    "@humanwhocodes/object-schema": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz",
+      "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==",
+      "dev": true
+    },
+    "@istanbuljs/load-nyc-config": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz",
+      "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==",
+      "dev": true,
+      "requires": {
+        "camelcase": "^5.3.1",
+        "find-up": "^4.1.0",
+        "get-package-type": "^0.1.0",
+        "js-yaml": "^3.13.1",
+        "resolve-from": "^5.0.0"
+      },
+      "dependencies": {
+        "argparse": {
+          "version": "1.0.10",
+          "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
+          "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
+          "dev": true,
+          "requires": {
+            "sprintf-js": "~1.0.2"
+          }
+        },
+        "camelcase": {
+          "version": "5.3.1",
+          "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
+          "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
+          "dev": true
+        },
+        "find-up": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
+          "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+          "dev": true,
+          "requires": {
+            "locate-path": "^5.0.0",
+            "path-exists": "^4.0.0"
+          }
+        },
+        "js-yaml": {
+          "version": "3.14.1",
+          "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
+          "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
+          "dev": true,
+          "requires": {
+            "argparse": "^1.0.7",
+            "esprima": "^4.0.0"
+          }
+        },
+        "locate-path": {
+          "version": "5.0.0",
+          "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
+          "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+          "dev": true,
+          "requires": {
+            "p-locate": "^4.1.0"
+          }
+        },
+        "p-limit": {
+          "version": "2.3.0",
+          "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+          "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+          "dev": true,
+          "requires": {
+            "p-try": "^2.0.0"
+          }
+        },
+        "p-locate": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
+          "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
+          "dev": true,
+          "requires": {
+            "p-limit": "^2.2.0"
+          }
+        },
+        "resolve-from": {
+          "version": "5.0.0",
+          "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
+          "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==",
+          "dev": true
+        }
+      }
+    },
+    "@istanbuljs/schema": {
+      "version": "0.1.3",
+      "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz",
+      "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==",
+      "dev": true
+    },
+    "@jest/console": {
+      "version": "29.5.0",
+      "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.5.0.tgz",
+      "integrity": "sha512-NEpkObxPwyw/XxZVLPmAGKE89IQRp4puc6IQRPru6JKd1M3fW9v1xM1AnzIJE65hbCkzQAdnL8P47e9hzhiYLQ==",
+      "dev": true,
+      "requires": {
+        "@jest/types": "^29.5.0",
+        "@types/node": "*",
+        "chalk": "^4.0.0",
+        "jest-message-util": "^29.5.0",
+        "jest-util": "^29.5.0",
+        "slash": "^3.0.0"
+      }
+    },
+    "@jest/core": {
+      "version": "29.5.0",
+      "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.5.0.tgz",
+      "integrity": "sha512-28UzQc7ulUrOQw1IsN/kv1QES3q2kkbl/wGslyhAclqZ/8cMdB5M68BffkIdSJgKBUt50d3hbwJ92XESlE7LiQ==",
+      "dev": true,
+      "requires": {
+        "@jest/console": "^29.5.0",
+        "@jest/reporters": "^29.5.0",
+        "@jest/test-result": "^29.5.0",
+        "@jest/transform": "^29.5.0",
+        "@jest/types": "^29.5.0",
+        "@types/node": "*",
+        "ansi-escapes": "^4.2.1",
+        "chalk": "^4.0.0",
+        "ci-info": "^3.2.0",
+        "exit": "^0.1.2",
+        "graceful-fs": "^4.2.9",
+        "jest-changed-files": "^29.5.0",
+        "jest-config": "^29.5.0",
+        "jest-haste-map": "^29.5.0",
+        "jest-message-util": "^29.5.0",
+        "jest-regex-util": "^29.4.3",
+        "jest-resolve": "^29.5.0",
+        "jest-resolve-dependencies": "^29.5.0",
+        "jest-runner": "^29.5.0",
+        "jest-runtime": "^29.5.0",
+        "jest-snapshot": "^29.5.0",
+        "jest-util": "^29.5.0",
+        "jest-validate": "^29.5.0",
+        "jest-watcher": "^29.5.0",
+        "micromatch": "^4.0.4",
+        "pretty-format": "^29.5.0",
+        "slash": "^3.0.0",
+        "strip-ansi": "^6.0.0"
+      },
+      "dependencies": {
+        "ansi-regex": {
+          "version": "5.0.1",
+          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+          "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+          "dev": true
+        },
+        "strip-ansi": {
+          "version": "6.0.1",
+          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+          "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+          "dev": true,
+          "requires": {
+            "ansi-regex": "^5.0.1"
+          }
+        }
+      }
+    },
+    "@jest/environment": {
+      "version": "29.5.0",
+      "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.5.0.tgz",
+      "integrity": "sha512-5FXw2+wD29YU1d4I2htpRX7jYnAyTRjP2CsXQdo9SAM8g3ifxWPSV0HnClSn71xwctr0U3oZIIH+dtbfmnbXVQ==",
+      "dev": true,
+      "requires": {
+        "@jest/fake-timers": "^29.5.0",
+        "@jest/types": "^29.5.0",
+        "@types/node": "*",
+        "jest-mock": "^29.5.0"
+      }
+    },
+    "@jest/expect": {
+      "version": "29.5.0",
+      "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.5.0.tgz",
+      "integrity": "sha512-PueDR2HGihN3ciUNGr4uelropW7rqUfTiOn+8u0leg/42UhblPxHkfoh0Ruu3I9Y1962P3u2DY4+h7GVTSVU6g==",
+      "dev": true,
+      "requires": {
+        "expect": "^29.5.0",
+        "jest-snapshot": "^29.5.0"
+      }
     },
-    "@esbuild/sunos-x64": {
-      "version": "0.17.19",
-      "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.19.tgz",
-      "integrity": "sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==",
-      "optional": true
+    "@jest/expect-utils": {
+      "version": "29.5.0",
+      "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.5.0.tgz",
+      "integrity": "sha512-fmKzsidoXQT2KwnrwE0SQq3uj8Z763vzR8LnLBwC2qYWEFpjX8daRsk6rHUM1QvNlEW/UJXNXm59ztmJJWs2Mg==",
+      "dev": true,
+      "requires": {
+        "jest-get-type": "^29.4.3"
+      }
     },
-    "@esbuild/win32-arm64": {
-      "version": "0.17.19",
-      "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.19.tgz",
-      "integrity": "sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==",
-      "optional": true
+    "@jest/fake-timers": {
+      "version": "29.5.0",
+      "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.5.0.tgz",
+      "integrity": "sha512-9ARvuAAQcBwDAqOnglWq2zwNIRUDtk/SCkp/ToGEhFv5r86K21l+VEs0qNTaXtyiY0lEePl3kylijSYJQqdbDg==",
+      "dev": true,
+      "requires": {
+        "@jest/types": "^29.5.0",
+        "@sinonjs/fake-timers": "^10.0.2",
+        "@types/node": "*",
+        "jest-message-util": "^29.5.0",
+        "jest-mock": "^29.5.0",
+        "jest-util": "^29.5.0"
+      }
     },
-    "@esbuild/win32-ia32": {
-      "version": "0.17.19",
-      "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.19.tgz",
-      "integrity": "sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==",
-      "optional": true
+    "@jest/globals": {
+      "version": "29.5.0",
+      "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.5.0.tgz",
+      "integrity": "sha512-S02y0qMWGihdzNbUiqSAiKSpSozSuHX5UYc7QbnHP+D9Lyw8DgGGCinrN9uSuHPeKgSSzvPom2q1nAtBvUsvPQ==",
+      "dev": true,
+      "requires": {
+        "@jest/environment": "^29.5.0",
+        "@jest/expect": "^29.5.0",
+        "@jest/types": "^29.5.0",
+        "jest-mock": "^29.5.0"
+      }
     },
-    "@esbuild/win32-x64": {
-      "version": "0.17.19",
-      "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.19.tgz",
-      "integrity": "sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==",
-      "optional": true
+    "@jest/reporters": {
+      "version": "29.5.0",
+      "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.5.0.tgz",
+      "integrity": "sha512-D05STXqj/M8bP9hQNSICtPqz97u7ffGzZu+9XLucXhkOFBqKcXe04JLZOgIekOxdb73MAoBUFnqvf7MCpKk5OA==",
+      "dev": true,
+      "requires": {
+        "@bcoe/v8-coverage": "^0.2.3",
+        "@jest/console": "^29.5.0",
+        "@jest/test-result": "^29.5.0",
+        "@jest/transform": "^29.5.0",
+        "@jest/types": "^29.5.0",
+        "@jridgewell/trace-mapping": "^0.3.15",
+        "@types/node": "*",
+        "chalk": "^4.0.0",
+        "collect-v8-coverage": "^1.0.0",
+        "exit": "^0.1.2",
+        "glob": "^7.1.3",
+        "graceful-fs": "^4.2.9",
+        "istanbul-lib-coverage": "^3.0.0",
+        "istanbul-lib-instrument": "^5.1.0",
+        "istanbul-lib-report": "^3.0.0",
+        "istanbul-lib-source-maps": "^4.0.0",
+        "istanbul-reports": "^3.1.3",
+        "jest-message-util": "^29.5.0",
+        "jest-util": "^29.5.0",
+        "jest-worker": "^29.5.0",
+        "slash": "^3.0.0",
+        "string-length": "^4.0.1",
+        "strip-ansi": "^6.0.0",
+        "v8-to-istanbul": "^9.0.1"
+      },
+      "dependencies": {
+        "ansi-regex": {
+          "version": "5.0.1",
+          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+          "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+          "dev": true
+        },
+        "glob": {
+          "version": "7.2.3",
+          "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+          "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
+          "dev": true,
+          "requires": {
+            "fs.realpath": "^1.0.0",
+            "inflight": "^1.0.4",
+            "inherits": "2",
+            "minimatch": "^3.1.1",
+            "once": "^1.3.0",
+            "path-is-absolute": "^1.0.0"
+          }
+        },
+        "strip-ansi": {
+          "version": "6.0.1",
+          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+          "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+          "dev": true,
+          "requires": {
+            "ansi-regex": "^5.0.1"
+          }
+        }
+      }
     },
-    "@eslint/eslintrc": {
-      "version": "1.4.1",
-      "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz",
-      "integrity": "sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==",
+    "@jest/schemas": {
+      "version": "29.4.3",
+      "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.4.3.tgz",
+      "integrity": "sha512-VLYKXQmtmuEz6IxJsrZwzG9NvtkQsWNnWMsKxqWNu3+CnfzJQhp0WDDKWLVV9hLKr0l3SLLFRqcYHjhtyuDVxg==",
       "dev": true,
       "requires": {
-        "ajv": "^6.12.4",
-        "debug": "^4.3.2",
-        "espree": "^9.4.0",
-        "globals": "^13.19.0",
-        "ignore": "^5.2.0",
-        "import-fresh": "^3.2.1",
-        "js-yaml": "^4.1.0",
-        "minimatch": "^3.1.2",
-        "strip-json-comments": "^3.1.1"
+        "@sinclair/typebox": "^0.25.16"
       }
     },
-    "@gar/promisify": {
-      "version": "1.1.3",
-      "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz",
-      "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw=="
+    "@jest/source-map": {
+      "version": "29.4.3",
+      "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.4.3.tgz",
+      "integrity": "sha512-qyt/mb6rLyd9j1jUts4EQncvS6Yy3PM9HghnNv86QBlV+zdL2inCdK1tuVlL+J+lpiw2BI67qXOrX3UurBqQ1w==",
+      "dev": true,
+      "requires": {
+        "@jridgewell/trace-mapping": "^0.3.15",
+        "callsites": "^3.0.0",
+        "graceful-fs": "^4.2.9"
+      }
     },
-    "@humanwhocodes/config-array": {
-      "version": "0.11.8",
-      "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz",
-      "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==",
+    "@jest/test-result": {
+      "version": "29.5.0",
+      "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.5.0.tgz",
+      "integrity": "sha512-fGl4rfitnbfLsrfx1uUpDEESS7zM8JdgZgOCQuxQvL1Sn/I6ijeAVQWGfXI9zb1i9Mzo495cIpVZhA0yr60PkQ==",
       "dev": true,
       "requires": {
-        "@humanwhocodes/object-schema": "^1.2.1",
-        "debug": "^4.1.1",
-        "minimatch": "^3.0.5"
+        "@jest/console": "^29.5.0",
+        "@jest/types": "^29.5.0",
+        "@types/istanbul-lib-coverage": "^2.0.0",
+        "collect-v8-coverage": "^1.0.0"
       }
     },
-    "@humanwhocodes/module-importer": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
-      "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==",
-      "dev": true
+    "@jest/test-sequencer": {
+      "version": "29.5.0",
+      "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.5.0.tgz",
+      "integrity": "sha512-yPafQEcKjkSfDXyvtgiV4pevSeyuA6MQr6ZIdVkWJly9vkqjnFfcfhRQqpD5whjoU8EORki752xQmjaqoFjzMQ==",
+      "dev": true,
+      "requires": {
+        "@jest/test-result": "^29.5.0",
+        "graceful-fs": "^4.2.9",
+        "jest-haste-map": "^29.5.0",
+        "slash": "^3.0.0"
+      }
     },
-    "@humanwhocodes/object-schema": {
-      "version": "1.2.1",
-      "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz",
-      "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==",
-      "dev": true
+    "@jest/transform": {
+      "version": "29.5.0",
+      "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.5.0.tgz",
+      "integrity": "sha512-8vbeZWqLJOvHaDfeMuoHITGKSz5qWc9u04lnWrQE3VyuSw604PzQM824ZeX9XSjUCeDiE3GuxZe5UKa8J61NQw==",
+      "dev": true,
+      "requires": {
+        "@babel/core": "^7.11.6",
+        "@jest/types": "^29.5.0",
+        "@jridgewell/trace-mapping": "^0.3.15",
+        "babel-plugin-istanbul": "^6.1.1",
+        "chalk": "^4.0.0",
+        "convert-source-map": "^2.0.0",
+        "fast-json-stable-stringify": "^2.1.0",
+        "graceful-fs": "^4.2.9",
+        "jest-haste-map": "^29.5.0",
+        "jest-regex-util": "^29.4.3",
+        "jest-util": "^29.5.0",
+        "micromatch": "^4.0.4",
+        "pirates": "^4.0.4",
+        "slash": "^3.0.0",
+        "write-file-atomic": "^4.0.2"
+      }
+    },
+    "@jest/types": {
+      "version": "29.5.0",
+      "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz",
+      "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==",
+      "dev": true,
+      "requires": {
+        "@jest/schemas": "^29.4.3",
+        "@types/istanbul-lib-coverage": "^2.0.0",
+        "@types/istanbul-reports": "^3.0.0",
+        "@types/node": "*",
+        "@types/yargs": "^17.0.8",
+        "chalk": "^4.0.0"
+      }
     },
     "@jridgewell/gen-mapping": {
       "version": "0.3.3",
@@ -9919,11 +13082,35 @@
         "tslib": "^2.4.1 || ^1.9.3"
       }
     },
+    "@sinclair/typebox": {
+      "version": "0.25.24",
+      "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.25.24.tgz",
+      "integrity": "sha512-XJfwUVUKDHF5ugKwIcxEgc9k8b7HbznCp6eUfWgu710hMPNIO4aw4/zB5RogDQz8nd6gyCDpU9O/m6qYEWY6yQ==",
+      "dev": true
+    },
     "@sindresorhus/is": {
       "version": "4.6.0",
       "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz",
       "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw=="
     },
+    "@sinonjs/commons": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.0.tgz",
+      "integrity": "sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA==",
+      "dev": true,
+      "requires": {
+        "type-detect": "4.0.8"
+      }
+    },
+    "@sinonjs/fake-timers": {
+      "version": "10.3.0",
+      "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz",
+      "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==",
+      "dev": true,
+      "requires": {
+        "@sinonjs/commons": "^3.0.0"
+      }
+    },
     "@styled-icons/heroicons-outline": {
       "version": "10.47.0",
       "resolved": "https://registry.npmjs.org/@styled-icons/heroicons-outline/-/heroicons-outline-10.47.0.tgz",
@@ -10032,6 +13219,47 @@
       "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==",
       "dev": true
     },
+    "@types/babel__core": {
+      "version": "7.20.1",
+      "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.1.tgz",
+      "integrity": "sha512-aACu/U/omhdk15O4Nfb+fHgH/z3QsfQzpnvRZhYhThms83ZnAOZz7zZAWO7mn2yyNQaA4xTO8GLK3uqFU4bYYw==",
+      "dev": true,
+      "requires": {
+        "@babel/parser": "^7.20.7",
+        "@babel/types": "^7.20.7",
+        "@types/babel__generator": "*",
+        "@types/babel__template": "*",
+        "@types/babel__traverse": "*"
+      }
+    },
+    "@types/babel__generator": {
+      "version": "7.6.4",
+      "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz",
+      "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==",
+      "dev": true,
+      "requires": {
+        "@babel/types": "^7.0.0"
+      }
+    },
+    "@types/babel__template": {
+      "version": "7.4.1",
+      "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz",
+      "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==",
+      "dev": true,
+      "requires": {
+        "@babel/parser": "^7.1.0",
+        "@babel/types": "^7.0.0"
+      }
+    },
+    "@types/babel__traverse": {
+      "version": "7.20.1",
+      "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.1.tgz",
+      "integrity": "sha512-MitHFXnhtgwsGZWtT68URpOvLN4EREih1u3QtQiN4VdAxWKRVvGCSvw/Qth0M0Qq3pJpnGOu5JaM/ydK7OGbqg==",
+      "dev": true,
+      "requires": {
+        "@babel/types": "^7.20.7"
+      }
+    },
     "@types/cacheable-request": {
       "version": "6.0.3",
       "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz",
@@ -10061,6 +13289,15 @@
         "@types/node": "*"
       }
     },
+    "@types/graceful-fs": {
+      "version": "4.1.6",
+      "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.6.tgz",
+      "integrity": "sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw==",
+      "dev": true,
+      "requires": {
+        "@types/node": "*"
+      }
+    },
     "@types/hast": {
       "version": "2.3.4",
       "resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.4.tgz",
@@ -10083,6 +13320,40 @@
       "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.1.tgz",
       "integrity": "sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ=="
     },
+    "@types/istanbul-lib-coverage": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz",
+      "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==",
+      "dev": true
+    },
+    "@types/istanbul-lib-report": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz",
+      "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==",
+      "dev": true,
+      "requires": {
+        "@types/istanbul-lib-coverage": "*"
+      }
+    },
+    "@types/istanbul-reports": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz",
+      "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==",
+      "dev": true,
+      "requires": {
+        "@types/istanbul-lib-report": "*"
+      }
+    },
+    "@types/jest": {
+      "version": "29.5.2",
+      "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.2.tgz",
+      "integrity": "sha512-mSoZVJF5YzGVCk+FsDxzDuH7s+SCkzrgKZzf0Z0T2WudhBUPoF6ktoTPC4R0ZoCPCV5xUvuU6ias5NvxcBcMMg==",
+      "dev": true,
+      "requires": {
+        "expect": "^29.0.0",
+        "pretty-format": "^29.0.0"
+      }
+    },
     "@types/json-schema": {
       "version": "7.0.11",
       "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz",
@@ -10205,6 +13476,12 @@
       "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==",
       "dev": true
     },
+    "@types/stack-utils": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz",
+      "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==",
+      "dev": true
+    },
     "@types/styled-components": {
       "version": "5.1.26",
       "resolved": "https://registry.npmjs.org/@types/styled-components/-/styled-components-5.1.26.tgz",
@@ -10227,9 +13504,9 @@
       "integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA=="
     },
     "@types/vscode": {
-      "version": "1.60.0",
-      "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.60.0.tgz",
-      "integrity": "sha512-wZt3VTmzYrgZ0l/3QmEbCq4KAJ71K3/hmMQ/nfpv84oH8e81KKwPEoQ5v8dNCxfHFVJ1JabHKmCvqdYOoVm1Ow==",
+      "version": "1.67.0",
+      "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.67.0.tgz",
+      "integrity": "sha512-GH8BDf8cw9AC9080uneJfulhSa7KHSMI2s/CyKePXoGNos9J486w2V4YKoeNUqIEkW4hKoEAWp6/cXTwyGj47g==",
       "dev": true
     },
     "@types/ws": {
@@ -10241,6 +13518,21 @@
         "@types/node": "*"
       }
     },
+    "@types/yargs": {
+      "version": "17.0.24",
+      "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz",
+      "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==",
+      "dev": true,
+      "requires": {
+        "@types/yargs-parser": "*"
+      }
+    },
+    "@types/yargs-parser": {
+      "version": "21.0.0",
+      "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz",
+      "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==",
+      "dev": true
+    },
     "@typescript-eslint/eslint-plugin": {
       "version": "5.48.2",
       "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.48.2.tgz",
@@ -10539,6 +13831,46 @@
         "typed-rest-client": "^1.8.4"
       }
     },
+    "babel-jest": {
+      "version": "29.5.0",
+      "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.5.0.tgz",
+      "integrity": "sha512-mA4eCDh5mSo2EcA9xQjVTpmbbNk32Zb3Q3QFQsNhaK56Q+yoXowzFodLux30HRgyOho5rsQ6B0P9QpMkvvnJ0Q==",
+      "dev": true,
+      "requires": {
+        "@jest/transform": "^29.5.0",
+        "@types/babel__core": "^7.1.14",
+        "babel-plugin-istanbul": "^6.1.1",
+        "babel-preset-jest": "^29.5.0",
+        "chalk": "^4.0.0",
+        "graceful-fs": "^4.2.9",
+        "slash": "^3.0.0"
+      }
+    },
+    "babel-plugin-istanbul": {
+      "version": "6.1.1",
+      "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz",
+      "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==",
+      "dev": true,
+      "requires": {
+        "@babel/helper-plugin-utils": "^7.0.0",
+        "@istanbuljs/load-nyc-config": "^1.0.0",
+        "@istanbuljs/schema": "^0.1.2",
+        "istanbul-lib-instrument": "^5.0.4",
+        "test-exclude": "^6.0.0"
+      }
+    },
+    "babel-plugin-jest-hoist": {
+      "version": "29.5.0",
+      "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.5.0.tgz",
+      "integrity": "sha512-zSuuuAlTMT4mzLj2nPnUm6fsE6270vdOfnpbJ+RmruU75UhLFvL0N2NgI7xpeS7NaB6hGqmd5pVpGTDYvi4Q3w==",
+      "dev": true,
+      "requires": {
+        "@babel/template": "^7.3.3",
+        "@babel/types": "^7.3.3",
+        "@types/babel__core": "^7.1.14",
+        "@types/babel__traverse": "^7.0.6"
+      }
+    },
     "babel-plugin-styled-components": {
       "version": "2.1.1",
       "resolved": "https://registry.npmjs.org/babel-plugin-styled-components/-/babel-plugin-styled-components-2.1.1.tgz",
@@ -10558,6 +13890,36 @@
       "integrity": "sha512-qrPaCSo9c8RHNRHIotaufGbuOBN8rtdC4QrrFFc43vyWCCz7Kl7GL1PGaXtMGQZUXrkCjNEgxDfmAuAabr/rlw==",
       "peer": true
     },
+    "babel-preset-current-node-syntax": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz",
+      "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==",
+      "dev": true,
+      "requires": {
+        "@babel/plugin-syntax-async-generators": "^7.8.4",
+        "@babel/plugin-syntax-bigint": "^7.8.3",
+        "@babel/plugin-syntax-class-properties": "^7.8.3",
+        "@babel/plugin-syntax-import-meta": "^7.8.3",
+        "@babel/plugin-syntax-json-strings": "^7.8.3",
+        "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3",
+        "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3",
+        "@babel/plugin-syntax-numeric-separator": "^7.8.3",
+        "@babel/plugin-syntax-object-rest-spread": "^7.8.3",
+        "@babel/plugin-syntax-optional-catch-binding": "^7.8.3",
+        "@babel/plugin-syntax-optional-chaining": "^7.8.3",
+        "@babel/plugin-syntax-top-level-await": "^7.8.3"
+      }
+    },
+    "babel-preset-jest": {
+      "version": "29.5.0",
+      "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.5.0.tgz",
+      "integrity": "sha512-JOMloxOqdiBSxMAzjRaH023/vvcaSaec49zvg+2LmNsktC7ei39LTJGw02J+9uUtTZUq6xbLyJ4dxe9sSmIuAg==",
+      "dev": true,
+      "requires": {
+        "babel-plugin-jest-hoist": "^29.5.0",
+        "babel-preset-current-node-syntax": "^1.0.0"
+      }
+    },
     "bail": {
       "version": "2.0.2",
       "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz",
@@ -10651,6 +14013,36 @@
       "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==",
       "dev": true
     },
+    "browserslist": {
+      "version": "4.21.9",
+      "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.9.tgz",
+      "integrity": "sha512-M0MFoZzbUrRU4KNfCrDLnvyE7gub+peetoTid3TBIqtunaDJyXlwhakT+/VkvSXcfIzFfK/nkCs4nmyTmxdNSg==",
+      "dev": true,
+      "requires": {
+        "caniuse-lite": "^1.0.30001503",
+        "electron-to-chromium": "^1.4.431",
+        "node-releases": "^2.0.12",
+        "update-browserslist-db": "^1.0.11"
+      }
+    },
+    "bs-logger": {
+      "version": "0.2.6",
+      "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz",
+      "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==",
+      "dev": true,
+      "requires": {
+        "fast-json-stable-stringify": "2.x"
+      }
+    },
+    "bser": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz",
+      "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==",
+      "dev": true,
+      "requires": {
+        "node-int64": "^0.4.0"
+      }
+    },
     "buffer": {
       "version": "5.7.1",
       "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
@@ -10666,6 +14058,12 @@
       "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==",
       "dev": true
     },
+    "buffer-from": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
+      "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
+      "dev": true
+    },
     "buffer-indexof-polyfill": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/buffer-indexof-polyfill/-/buffer-indexof-polyfill-1.0.2.tgz",
@@ -10773,6 +14171,12 @@
       "integrity": "sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==",
       "peer": true
     },
+    "caniuse-lite": {
+      "version": "1.0.30001511",
+      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001511.tgz",
+      "integrity": "sha512-NaWPJawcoedlghN4P7bDNeADD7K+rZaY6V8ZcME7PkEZo/nfOg+lnrUgRWiKbNxcQ4/toFKSxnS4WdbyPZnKkw==",
+      "dev": true
+    },
     "chainsaw": {
       "version": "0.1.0",
       "resolved": "https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz",
@@ -10791,6 +14195,12 @@
         "supports-color": "^7.1.0"
       }
     },
+    "char-regex": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz",
+      "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==",
+      "dev": true
+    },
     "character-entities": {
       "version": "2.0.2",
       "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz",
@@ -10861,6 +14271,18 @@
       "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz",
       "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ=="
     },
+    "ci-info": {
+      "version": "3.8.0",
+      "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz",
+      "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==",
+      "dev": true
+    },
+    "cjs-module-lexer": {
+      "version": "1.2.3",
+      "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz",
+      "integrity": "sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==",
+      "dev": true
+    },
     "clean-stack": {
       "version": "2.2.0",
       "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz",
@@ -10939,6 +14361,18 @@
         "mimic-response": "^1.0.0"
       }
     },
+    "co": {
+      "version": "4.6.0",
+      "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
+      "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==",
+      "dev": true
+    },
+    "collect-v8-coverage": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz",
+      "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==",
+      "dev": true
+    },
     "color-convert": {
       "version": "2.0.1",
       "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
@@ -11048,6 +14482,12 @@
         "easy-table": "1.1.0"
       }
     },
+    "convert-source-map": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
+      "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==",
+      "dev": true
+    },
     "cookie": {
       "version": "0.4.2",
       "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz",
@@ -11168,6 +14608,12 @@
         }
       }
     },
+    "dedent": {
+      "version": "0.7.0",
+      "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz",
+      "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==",
+      "dev": true
+    },
     "deep-extend": {
       "version": "0.6.0",
       "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
@@ -11180,6 +14626,12 @@
       "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
       "dev": true
     },
+    "deepmerge": {
+      "version": "4.3.1",
+      "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz",
+      "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==",
+      "dev": true
+    },
     "defaults": {
       "version": "1.0.4",
       "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz",
@@ -11218,6 +14670,12 @@
       "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz",
       "integrity": "sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w=="
     },
+    "detect-newline": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz",
+      "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==",
+      "dev": true
+    },
     "didyoumean": {
       "version": "1.2.2",
       "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz",
@@ -11228,6 +14686,12 @@
       "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz",
       "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w=="
     },
+    "diff-sequences": {
+      "version": "29.4.3",
+      "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.4.3.tgz",
+      "integrity": "sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA==",
+      "dev": true
+    },
     "dir-glob": {
       "version": "3.0.1",
       "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
@@ -11335,6 +14799,18 @@
         "wcwidth": ">=1.0.1"
       }
     },
+    "electron-to-chromium": {
+      "version": "1.4.449",
+      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.449.tgz",
+      "integrity": "sha512-TxLRpRUj/107ATefeP8VIUWNOv90xJxZZbCW/eIbSZQiuiFANCx2b7u+GbVc9X4gU+xnbvypNMYVM/WArE1DNQ==",
+      "dev": true
+    },
+    "emittery": {
+      "version": "0.13.1",
+      "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz",
+      "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==",
+      "dev": true
+    },
     "emoji-regex": {
       "version": "8.0.0",
       "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
@@ -11373,6 +14849,15 @@
       "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz",
       "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA=="
     },
+    "error-ex": {
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
+      "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
+      "dev": true,
+      "requires": {
+        "is-arrayish": "^0.2.1"
+      }
+    },
     "es5-ext": {
       "version": "0.10.62",
       "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.62.tgz",
@@ -11581,6 +15066,12 @@
         "eslint-visitor-keys": "^3.3.0"
       }
     },
+    "esprima": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
+      "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
+      "dev": true
+    },
     "esquery": {
       "version": "1.4.0",
       "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz",
@@ -11660,12 +15151,31 @@
         }
       }
     },
+    "exit": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz",
+      "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==",
+      "dev": true
+    },
     "expand-template": {
       "version": "2.0.3",
       "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz",
       "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==",
       "dev": true
     },
+    "expect": {
+      "version": "29.5.0",
+      "resolved": "https://registry.npmjs.org/expect/-/expect-29.5.0.tgz",
+      "integrity": "sha512-yM7xqUrCO2JdpFo4XpM82t+PJBFybdqoQuJLDGeDX2ij8NZzqRHyu3Hp188/JX7SWqud+7t4MUdvcgGBICMHZg==",
+      "dev": true,
+      "requires": {
+        "@jest/expect-utils": "^29.5.0",
+        "jest-get-type": "^29.4.3",
+        "jest-matcher-utils": "^29.5.0",
+        "jest-message-util": "^29.5.0",
+        "jest-util": "^29.5.0"
+      }
+    },
     "ext": {
       "version": "1.7.0",
       "resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz",
@@ -11773,6 +15283,15 @@
         "reusify": "^1.0.4"
       }
     },
+    "fb-watchman": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz",
+      "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==",
+      "dev": true,
+      "requires": {
+        "bser": "2.1.1"
+      }
+    },
     "fd-slicer": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz",
@@ -12017,6 +15536,12 @@
         }
       }
     },
+    "gensync": {
+      "version": "1.0.0-beta.2",
+      "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
+      "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==",
+      "dev": true
+    },
     "get-caller-file": {
       "version": "2.0.5",
       "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
@@ -12033,6 +15558,12 @@
         "has-symbols": "^1.0.3"
       }
     },
+    "get-package-type": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz",
+      "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==",
+      "dev": true
+    },
     "get-stdin": {
       "version": "8.0.0",
       "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-8.0.0.tgz",
@@ -12207,6 +15738,12 @@
         "lru-cache": "^6.0.0"
       }
     },
+    "html-escaper": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz",
+      "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==",
+      "dev": true
+    },
     "htmlparser2": {
       "version": "8.0.1",
       "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.1.tgz",
@@ -12301,6 +15838,16 @@
         "resolve-from": "^4.0.0"
       }
     },
+    "import-local": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz",
+      "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==",
+      "dev": true,
+      "requires": {
+        "pkg-dir": "^4.2.0",
+        "resolve-cwd": "^3.0.0"
+      }
+    },
     "imurmurhash": {
       "version": "0.1.4",
       "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
@@ -12386,6 +15933,12 @@
       "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz",
       "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ=="
     },
+    "is-arrayish": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
+      "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==",
+      "dev": true
+    },
     "is-binary-path": {
       "version": "2.1.0",
       "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
@@ -12417,6 +15970,12 @@
       "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
       "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="
     },
+    "is-generator-fn": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz",
+      "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==",
+      "dev": true
+    },
     "is-glob": {
       "version": "4.0.3",
       "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
@@ -12468,21 +16027,582 @@
       "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz",
       "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw=="
     },
-    "isarray": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
-      "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==",
-      "dev": true
+    "isarray": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+      "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==",
+      "dev": true
+    },
+    "isexe": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+      "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="
+    },
+    "istanbul-lib-coverage": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz",
+      "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==",
+      "dev": true
+    },
+    "istanbul-lib-instrument": {
+      "version": "5.2.1",
+      "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz",
+      "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==",
+      "dev": true,
+      "requires": {
+        "@babel/core": "^7.12.3",
+        "@babel/parser": "^7.14.7",
+        "@istanbuljs/schema": "^0.1.2",
+        "istanbul-lib-coverage": "^3.2.0",
+        "semver": "^6.3.0"
+      },
+      "dependencies": {
+        "semver": {
+          "version": "6.3.0",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+          "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+          "dev": true
+        }
+      }
+    },
+    "istanbul-lib-report": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz",
+      "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==",
+      "dev": true,
+      "requires": {
+        "istanbul-lib-coverage": "^3.0.0",
+        "make-dir": "^3.0.0",
+        "supports-color": "^7.1.0"
+      }
+    },
+    "istanbul-lib-source-maps": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz",
+      "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==",
+      "dev": true,
+      "requires": {
+        "debug": "^4.1.1",
+        "istanbul-lib-coverage": "^3.0.0",
+        "source-map": "^0.6.1"
+      }
+    },
+    "istanbul-reports": {
+      "version": "3.1.5",
+      "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz",
+      "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==",
+      "dev": true,
+      "requires": {
+        "html-escaper": "^2.0.0",
+        "istanbul-lib-report": "^3.0.0"
+      }
+    },
+    "iterare": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/iterare/-/iterare-1.2.1.tgz",
+      "integrity": "sha512-RKYVTCjAnRthyJes037NX/IiqeidgN1xc3j1RjFfECFp28A1GVwK9nA+i0rJPaHqSZwygLzRnFlzUuHFoWWy+Q=="
+    },
+    "jest": {
+      "version": "29.5.0",
+      "resolved": "https://registry.npmjs.org/jest/-/jest-29.5.0.tgz",
+      "integrity": "sha512-juMg3he2uru1QoXX078zTa7pO85QyB9xajZc6bU+d9yEGwrKX6+vGmJQ3UdVZsvTEUARIdObzH68QItim6OSSQ==",
+      "dev": true,
+      "requires": {
+        "@jest/core": "^29.5.0",
+        "@jest/types": "^29.5.0",
+        "import-local": "^3.0.2",
+        "jest-cli": "^29.5.0"
+      }
+    },
+    "jest-changed-files": {
+      "version": "29.5.0",
+      "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.5.0.tgz",
+      "integrity": "sha512-IFG34IUMUaNBIxjQXF/iu7g6EcdMrGRRxaUSw92I/2g2YC6vCdTltl4nHvt7Ci5nSJwXIkCu8Ka1DKF+X7Z1Ag==",
+      "dev": true,
+      "requires": {
+        "execa": "^5.0.0",
+        "p-limit": "^3.1.0"
+      }
+    },
+    "jest-circus": {
+      "version": "29.5.0",
+      "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.5.0.tgz",
+      "integrity": "sha512-gq/ongqeQKAplVxqJmbeUOJJKkW3dDNPY8PjhJ5G0lBRvu0e3EWGxGy5cI4LAGA7gV2UHCtWBI4EMXK8c9nQKA==",
+      "dev": true,
+      "requires": {
+        "@jest/environment": "^29.5.0",
+        "@jest/expect": "^29.5.0",
+        "@jest/test-result": "^29.5.0",
+        "@jest/types": "^29.5.0",
+        "@types/node": "*",
+        "chalk": "^4.0.0",
+        "co": "^4.6.0",
+        "dedent": "^0.7.0",
+        "is-generator-fn": "^2.0.0",
+        "jest-each": "^29.5.0",
+        "jest-matcher-utils": "^29.5.0",
+        "jest-message-util": "^29.5.0",
+        "jest-runtime": "^29.5.0",
+        "jest-snapshot": "^29.5.0",
+        "jest-util": "^29.5.0",
+        "p-limit": "^3.1.0",
+        "pretty-format": "^29.5.0",
+        "pure-rand": "^6.0.0",
+        "slash": "^3.0.0",
+        "stack-utils": "^2.0.3"
+      }
+    },
+    "jest-cli": {
+      "version": "29.5.0",
+      "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.5.0.tgz",
+      "integrity": "sha512-L1KcP1l4HtfwdxXNFCL5bmUbLQiKrakMUriBEcc1Vfz6gx31ORKdreuWvmQVBit+1ss9NNR3yxjwfwzZNdQXJw==",
+      "dev": true,
+      "requires": {
+        "@jest/core": "^29.5.0",
+        "@jest/test-result": "^29.5.0",
+        "@jest/types": "^29.5.0",
+        "chalk": "^4.0.0",
+        "exit": "^0.1.2",
+        "graceful-fs": "^4.2.9",
+        "import-local": "^3.0.2",
+        "jest-config": "^29.5.0",
+        "jest-util": "^29.5.0",
+        "jest-validate": "^29.5.0",
+        "prompts": "^2.0.1",
+        "yargs": "^17.3.1"
+      },
+      "dependencies": {
+        "ansi-regex": {
+          "version": "5.0.1",
+          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+          "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+          "dev": true
+        },
+        "cliui": {
+          "version": "8.0.1",
+          "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
+          "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
+          "dev": true,
+          "requires": {
+            "string-width": "^4.2.0",
+            "strip-ansi": "^6.0.1",
+            "wrap-ansi": "^7.0.0"
+          }
+        },
+        "strip-ansi": {
+          "version": "6.0.1",
+          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+          "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+          "dev": true,
+          "requires": {
+            "ansi-regex": "^5.0.1"
+          }
+        },
+        "yargs": {
+          "version": "17.7.2",
+          "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
+          "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
+          "dev": true,
+          "requires": {
+            "cliui": "^8.0.1",
+            "escalade": "^3.1.1",
+            "get-caller-file": "^2.0.5",
+            "require-directory": "^2.1.1",
+            "string-width": "^4.2.3",
+            "y18n": "^5.0.5",
+            "yargs-parser": "^21.1.1"
+          }
+        },
+        "yargs-parser": {
+          "version": "21.1.1",
+          "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
+          "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
+          "dev": true
+        }
+      }
+    },
+    "jest-config": {
+      "version": "29.5.0",
+      "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.5.0.tgz",
+      "integrity": "sha512-kvDUKBnNJPNBmFFOhDbm59iu1Fii1Q6SxyhXfvylq3UTHbg6o7j/g8k2dZyXWLvfdKB1vAPxNZnMgtKJcmu3kA==",
+      "dev": true,
+      "requires": {
+        "@babel/core": "^7.11.6",
+        "@jest/test-sequencer": "^29.5.0",
+        "@jest/types": "^29.5.0",
+        "babel-jest": "^29.5.0",
+        "chalk": "^4.0.0",
+        "ci-info": "^3.2.0",
+        "deepmerge": "^4.2.2",
+        "glob": "^7.1.3",
+        "graceful-fs": "^4.2.9",
+        "jest-circus": "^29.5.0",
+        "jest-environment-node": "^29.5.0",
+        "jest-get-type": "^29.4.3",
+        "jest-regex-util": "^29.4.3",
+        "jest-resolve": "^29.5.0",
+        "jest-runner": "^29.5.0",
+        "jest-util": "^29.5.0",
+        "jest-validate": "^29.5.0",
+        "micromatch": "^4.0.4",
+        "parse-json": "^5.2.0",
+        "pretty-format": "^29.5.0",
+        "slash": "^3.0.0",
+        "strip-json-comments": "^3.1.1"
+      },
+      "dependencies": {
+        "glob": {
+          "version": "7.2.3",
+          "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+          "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
+          "dev": true,
+          "requires": {
+            "fs.realpath": "^1.0.0",
+            "inflight": "^1.0.4",
+            "inherits": "2",
+            "minimatch": "^3.1.1",
+            "once": "^1.3.0",
+            "path-is-absolute": "^1.0.0"
+          }
+        }
+      }
+    },
+    "jest-diff": {
+      "version": "29.5.0",
+      "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.5.0.tgz",
+      "integrity": "sha512-LtxijLLZBduXnHSniy0WMdaHjmQnt3g5sa16W4p0HqukYTTsyTW3GD1q41TyGl5YFXj/5B2U6dlh5FM1LIMgxw==",
+      "dev": true,
+      "requires": {
+        "chalk": "^4.0.0",
+        "diff-sequences": "^29.4.3",
+        "jest-get-type": "^29.4.3",
+        "pretty-format": "^29.5.0"
+      }
+    },
+    "jest-docblock": {
+      "version": "29.4.3",
+      "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.4.3.tgz",
+      "integrity": "sha512-fzdTftThczeSD9nZ3fzA/4KkHtnmllawWrXO69vtI+L9WjEIuXWs4AmyME7lN5hU7dB0sHhuPfcKofRsUb/2Fg==",
+      "dev": true,
+      "requires": {
+        "detect-newline": "^3.0.0"
+      }
+    },
+    "jest-each": {
+      "version": "29.5.0",
+      "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.5.0.tgz",
+      "integrity": "sha512-HM5kIJ1BTnVt+DQZ2ALp3rzXEl+g726csObrW/jpEGl+CDSSQpOJJX2KE/vEg8cxcMXdyEPu6U4QX5eruQv5hA==",
+      "dev": true,
+      "requires": {
+        "@jest/types": "^29.5.0",
+        "chalk": "^4.0.0",
+        "jest-get-type": "^29.4.3",
+        "jest-util": "^29.5.0",
+        "pretty-format": "^29.5.0"
+      }
+    },
+    "jest-environment-node": {
+      "version": "29.5.0",
+      "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.5.0.tgz",
+      "integrity": "sha512-ExxuIK/+yQ+6PRGaHkKewYtg6hto2uGCgvKdb2nfJfKXgZ17DfXjvbZ+jA1Qt9A8EQSfPnt5FKIfnOO3u1h9qw==",
+      "dev": true,
+      "requires": {
+        "@jest/environment": "^29.5.0",
+        "@jest/fake-timers": "^29.5.0",
+        "@jest/types": "^29.5.0",
+        "@types/node": "*",
+        "jest-mock": "^29.5.0",
+        "jest-util": "^29.5.0"
+      }
+    },
+    "jest-get-type": {
+      "version": "29.4.3",
+      "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.4.3.tgz",
+      "integrity": "sha512-J5Xez4nRRMjk8emnTpWrlkyb9pfRQQanDrvWHhsR1+VUfbwxi30eVcZFlcdGInRibU4G5LwHXpI7IRHU0CY+gg==",
+      "dev": true
+    },
+    "jest-haste-map": {
+      "version": "29.5.0",
+      "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.5.0.tgz",
+      "integrity": "sha512-IspOPnnBro8YfVYSw6yDRKh/TiCdRngjxeacCps1cQ9cgVN6+10JUcuJ1EabrgYLOATsIAigxA0rLR9x/YlrSA==",
+      "dev": true,
+      "requires": {
+        "@jest/types": "^29.5.0",
+        "@types/graceful-fs": "^4.1.3",
+        "@types/node": "*",
+        "anymatch": "^3.0.3",
+        "fb-watchman": "^2.0.0",
+        "fsevents": "^2.3.2",
+        "graceful-fs": "^4.2.9",
+        "jest-regex-util": "^29.4.3",
+        "jest-util": "^29.5.0",
+        "jest-worker": "^29.5.0",
+        "micromatch": "^4.0.4",
+        "walker": "^1.0.8"
+      }
+    },
+    "jest-leak-detector": {
+      "version": "29.5.0",
+      "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.5.0.tgz",
+      "integrity": "sha512-u9YdeeVnghBUtpN5mVxjID7KbkKE1QU4f6uUwuxiY0vYRi9BUCLKlPEZfDGR67ofdFmDz9oPAy2G92Ujrntmow==",
+      "dev": true,
+      "requires": {
+        "jest-get-type": "^29.4.3",
+        "pretty-format": "^29.5.0"
+      }
+    },
+    "jest-matcher-utils": {
+      "version": "29.5.0",
+      "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.5.0.tgz",
+      "integrity": "sha512-lecRtgm/rjIK0CQ7LPQwzCs2VwW6WAahA55YBuI+xqmhm7LAaxokSB8C97yJeYyT+HvQkH741StzpU41wohhWw==",
+      "dev": true,
+      "requires": {
+        "chalk": "^4.0.0",
+        "jest-diff": "^29.5.0",
+        "jest-get-type": "^29.4.3",
+        "pretty-format": "^29.5.0"
+      }
+    },
+    "jest-message-util": {
+      "version": "29.5.0",
+      "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.5.0.tgz",
+      "integrity": "sha512-Kijeg9Dag6CKtIDA7O21zNTACqD5MD/8HfIV8pdD94vFyFuer52SigdC3IQMhab3vACxXMiFk+yMHNdbqtyTGA==",
+      "dev": true,
+      "requires": {
+        "@babel/code-frame": "^7.12.13",
+        "@jest/types": "^29.5.0",
+        "@types/stack-utils": "^2.0.0",
+        "chalk": "^4.0.0",
+        "graceful-fs": "^4.2.9",
+        "micromatch": "^4.0.4",
+        "pretty-format": "^29.5.0",
+        "slash": "^3.0.0",
+        "stack-utils": "^2.0.3"
+      }
+    },
+    "jest-mock": {
+      "version": "29.5.0",
+      "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.5.0.tgz",
+      "integrity": "sha512-GqOzvdWDE4fAV2bWQLQCkujxYWL7RxjCnj71b5VhDAGOevB3qj3Ovg26A5NI84ZpODxyzaozXLOh2NCgkbvyaw==",
+      "dev": true,
+      "requires": {
+        "@jest/types": "^29.5.0",
+        "@types/node": "*",
+        "jest-util": "^29.5.0"
+      }
+    },
+    "jest-pnp-resolver": {
+      "version": "1.2.3",
+      "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz",
+      "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==",
+      "dev": true,
+      "requires": {}
+    },
+    "jest-regex-util": {
+      "version": "29.4.3",
+      "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.4.3.tgz",
+      "integrity": "sha512-O4FglZaMmWXbGHSQInfXewIsd1LMn9p3ZXB/6r4FOkyhX2/iP/soMG98jGvk/A3HAN78+5VWcBGO0BJAPRh4kg==",
+      "dev": true
+    },
+    "jest-resolve": {
+      "version": "29.5.0",
+      "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.5.0.tgz",
+      "integrity": "sha512-1TzxJ37FQq7J10jPtQjcc+MkCkE3GBpBecsSUWJ0qZNJpmg6m0D9/7II03yJulm3H/fvVjgqLh/k2eYg+ui52w==",
+      "dev": true,
+      "requires": {
+        "chalk": "^4.0.0",
+        "graceful-fs": "^4.2.9",
+        "jest-haste-map": "^29.5.0",
+        "jest-pnp-resolver": "^1.2.2",
+        "jest-util": "^29.5.0",
+        "jest-validate": "^29.5.0",
+        "resolve": "^1.20.0",
+        "resolve.exports": "^2.0.0",
+        "slash": "^3.0.0"
+      }
+    },
+    "jest-resolve-dependencies": {
+      "version": "29.5.0",
+      "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.5.0.tgz",
+      "integrity": "sha512-sjV3GFr0hDJMBpYeUuGduP+YeCRbd7S/ck6IvL3kQ9cpySYKqcqhdLLC2rFwrcL7tz5vYibomBrsFYWkIGGjOg==",
+      "dev": true,
+      "requires": {
+        "jest-regex-util": "^29.4.3",
+        "jest-snapshot": "^29.5.0"
+      }
+    },
+    "jest-runner": {
+      "version": "29.5.0",
+      "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.5.0.tgz",
+      "integrity": "sha512-m7b6ypERhFghJsslMLhydaXBiLf7+jXy8FwGRHO3BGV1mcQpPbwiqiKUR2zU2NJuNeMenJmlFZCsIqzJCTeGLQ==",
+      "dev": true,
+      "requires": {
+        "@jest/console": "^29.5.0",
+        "@jest/environment": "^29.5.0",
+        "@jest/test-result": "^29.5.0",
+        "@jest/transform": "^29.5.0",
+        "@jest/types": "^29.5.0",
+        "@types/node": "*",
+        "chalk": "^4.0.0",
+        "emittery": "^0.13.1",
+        "graceful-fs": "^4.2.9",
+        "jest-docblock": "^29.4.3",
+        "jest-environment-node": "^29.5.0",
+        "jest-haste-map": "^29.5.0",
+        "jest-leak-detector": "^29.5.0",
+        "jest-message-util": "^29.5.0",
+        "jest-resolve": "^29.5.0",
+        "jest-runtime": "^29.5.0",
+        "jest-util": "^29.5.0",
+        "jest-watcher": "^29.5.0",
+        "jest-worker": "^29.5.0",
+        "p-limit": "^3.1.0",
+        "source-map-support": "0.5.13"
+      }
+    },
+    "jest-runtime": {
+      "version": "29.5.0",
+      "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.5.0.tgz",
+      "integrity": "sha512-1Hr6Hh7bAgXQP+pln3homOiEZtCDZFqwmle7Ew2j8OlbkIu6uE3Y/etJQG8MLQs3Zy90xrp2C0BRrtPHG4zryw==",
+      "dev": true,
+      "requires": {
+        "@jest/environment": "^29.5.0",
+        "@jest/fake-timers": "^29.5.0",
+        "@jest/globals": "^29.5.0",
+        "@jest/source-map": "^29.4.3",
+        "@jest/test-result": "^29.5.0",
+        "@jest/transform": "^29.5.0",
+        "@jest/types": "^29.5.0",
+        "@types/node": "*",
+        "chalk": "^4.0.0",
+        "cjs-module-lexer": "^1.0.0",
+        "collect-v8-coverage": "^1.0.0",
+        "glob": "^7.1.3",
+        "graceful-fs": "^4.2.9",
+        "jest-haste-map": "^29.5.0",
+        "jest-message-util": "^29.5.0",
+        "jest-mock": "^29.5.0",
+        "jest-regex-util": "^29.4.3",
+        "jest-resolve": "^29.5.0",
+        "jest-snapshot": "^29.5.0",
+        "jest-util": "^29.5.0",
+        "slash": "^3.0.0",
+        "strip-bom": "^4.0.0"
+      },
+      "dependencies": {
+        "glob": {
+          "version": "7.2.3",
+          "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+          "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
+          "dev": true,
+          "requires": {
+            "fs.realpath": "^1.0.0",
+            "inflight": "^1.0.4",
+            "inherits": "2",
+            "minimatch": "^3.1.1",
+            "once": "^1.3.0",
+            "path-is-absolute": "^1.0.0"
+          }
+        }
+      }
+    },
+    "jest-snapshot": {
+      "version": "29.5.0",
+      "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.5.0.tgz",
+      "integrity": "sha512-x7Wolra5V0tt3wRs3/ts3S6ciSQVypgGQlJpz2rsdQYoUKxMxPNaoHMGJN6qAuPJqS+2iQ1ZUn5kl7HCyls84g==",
+      "dev": true,
+      "requires": {
+        "@babel/core": "^7.11.6",
+        "@babel/generator": "^7.7.2",
+        "@babel/plugin-syntax-jsx": "^7.7.2",
+        "@babel/plugin-syntax-typescript": "^7.7.2",
+        "@babel/traverse": "^7.7.2",
+        "@babel/types": "^7.3.3",
+        "@jest/expect-utils": "^29.5.0",
+        "@jest/transform": "^29.5.0",
+        "@jest/types": "^29.5.0",
+        "@types/babel__traverse": "^7.0.6",
+        "@types/prettier": "^2.1.5",
+        "babel-preset-current-node-syntax": "^1.0.0",
+        "chalk": "^4.0.0",
+        "expect": "^29.5.0",
+        "graceful-fs": "^4.2.9",
+        "jest-diff": "^29.5.0",
+        "jest-get-type": "^29.4.3",
+        "jest-matcher-utils": "^29.5.0",
+        "jest-message-util": "^29.5.0",
+        "jest-util": "^29.5.0",
+        "natural-compare": "^1.4.0",
+        "pretty-format": "^29.5.0",
+        "semver": "^7.3.5"
+      }
+    },
+    "jest-util": {
+      "version": "29.5.0",
+      "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz",
+      "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==",
+      "dev": true,
+      "requires": {
+        "@jest/types": "^29.5.0",
+        "@types/node": "*",
+        "chalk": "^4.0.0",
+        "ci-info": "^3.2.0",
+        "graceful-fs": "^4.2.9",
+        "picomatch": "^2.2.3"
+      }
+    },
+    "jest-validate": {
+      "version": "29.5.0",
+      "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.5.0.tgz",
+      "integrity": "sha512-pC26etNIi+y3HV8A+tUGr/lph9B18GnzSRAkPaaZJIE1eFdiYm6/CewuiJQ8/RlfHd1u/8Ioi8/sJ+CmbA+zAQ==",
+      "dev": true,
+      "requires": {
+        "@jest/types": "^29.5.0",
+        "camelcase": "^6.2.0",
+        "chalk": "^4.0.0",
+        "jest-get-type": "^29.4.3",
+        "leven": "^3.1.0",
+        "pretty-format": "^29.5.0"
+      }
     },
-    "isexe": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
-      "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="
+    "jest-watcher": {
+      "version": "29.5.0",
+      "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.5.0.tgz",
+      "integrity": "sha512-KmTojKcapuqYrKDpRwfqcQ3zjMlwu27SYext9pt4GlF5FUgB+7XE1mcCnSm6a4uUpFyQIkb6ZhzZvHl+jiBCiA==",
+      "dev": true,
+      "requires": {
+        "@jest/test-result": "^29.5.0",
+        "@jest/types": "^29.5.0",
+        "@types/node": "*",
+        "ansi-escapes": "^4.2.1",
+        "chalk": "^4.0.0",
+        "emittery": "^0.13.1",
+        "jest-util": "^29.5.0",
+        "string-length": "^4.0.1"
+      }
     },
-    "iterare": {
-      "version": "1.2.1",
-      "resolved": "https://registry.npmjs.org/iterare/-/iterare-1.2.1.tgz",
-      "integrity": "sha512-RKYVTCjAnRthyJes037NX/IiqeidgN1xc3j1RjFfECFp28A1GVwK9nA+i0rJPaHqSZwygLzRnFlzUuHFoWWy+Q=="
+    "jest-worker": {
+      "version": "29.5.0",
+      "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.5.0.tgz",
+      "integrity": "sha512-NcrQnevGoSp4b5kg+akIpthoAFHxPBcb5P6mYPY0fUNT+sSvmtu6jlkEle3anczUKIKEbMxFimk9oTP/tpIPgA==",
+      "dev": true,
+      "requires": {
+        "@types/node": "*",
+        "jest-util": "^29.5.0",
+        "merge-stream": "^2.0.0",
+        "supports-color": "^8.0.0"
+      },
+      "dependencies": {
+        "supports-color": {
+          "version": "8.1.1",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
+          "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
+          "dev": true,
+          "requires": {
+            "has-flag": "^4.0.0"
+          }
+        }
+      }
     },
     "jiti": {
       "version": "1.18.2",
@@ -12512,14 +16632,19 @@
     "jsesc": {
       "version": "2.5.2",
       "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz",
-      "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==",
-      "peer": true
+      "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA=="
     },
     "json-buffer": {
       "version": "3.0.1",
       "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
       "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ=="
     },
+    "json-parse-even-better-errors": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
+      "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==",
+      "dev": true
+    },
     "json-schema-to-typescript": {
       "version": "12.0.0",
       "resolved": "https://registry.npmjs.org/json-schema-to-typescript/-/json-schema-to-typescript-12.0.0.tgz",
@@ -12595,6 +16720,12 @@
       "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
       "dev": true
     },
+    "json5": {
+      "version": "2.2.3",
+      "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
+      "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
+      "dev": true
+    },
     "jsonfile": {
       "version": "6.1.0",
       "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
@@ -12690,6 +16821,12 @@
       "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
       "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
     },
+    "lodash.memoize": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",
+      "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==",
+      "dev": true
+    },
     "lodash.merge": {
       "version": "4.6.2",
       "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
@@ -12762,6 +16899,29 @@
         }
       }
     },
+    "make-dir": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
+      "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
+      "dev": true,
+      "requires": {
+        "semver": "^6.0.0"
+      },
+      "dependencies": {
+        "semver": {
+          "version": "6.3.0",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+          "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+          "dev": true
+        }
+      }
+    },
+    "make-error": {
+      "version": "1.3.6",
+      "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
+      "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
+      "dev": true
+    },
     "make-fetch-happen": {
       "version": "10.2.1",
       "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-10.2.1.tgz",
@@ -12807,6 +16967,15 @@
         }
       }
     },
+    "makeerror": {
+      "version": "1.0.12",
+      "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz",
+      "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==",
+      "dev": true,
+      "requires": {
+        "tmpl": "1.0.5"
+      }
+    },
     "markdown-it": {
       "version": "12.3.2",
       "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz",
@@ -13468,6 +17637,18 @@
       "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.6.0.tgz",
       "integrity": "sha512-NTZVKn9IylLwUzaKjkas1e4u2DLNcV4rdYagA4PWdPwW87Bi7z+BznyKSRwS/761tV/lzCGXplWsiaMjLqP2zQ=="
     },
+    "node-int64": {
+      "version": "0.4.0",
+      "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz",
+      "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==",
+      "dev": true
+    },
+    "node-releases": {
+      "version": "2.0.12",
+      "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.12.tgz",
+      "integrity": "sha512-QzsYKWhXTWx8h1kIvqfnC++o0pEmpRQA/aenALsL2F4pqNVr7YzcdMlDij5WBnwftRbJCNJL/O7zdKaxKPHqgQ==",
+      "dev": true
+    },
     "nopt": {
       "version": "6.0.0",
       "resolved": "https://registry.npmjs.org/nopt/-/nopt-6.0.0.tgz",
@@ -13628,6 +17809,12 @@
         "aggregate-error": "^3.0.0"
       }
     },
+    "p-try": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
+      "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
+      "dev": true
+    },
     "parent-module": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
@@ -13637,6 +17824,18 @@
         "callsites": "^3.0.0"
       }
     },
+    "parse-json": {
+      "version": "5.2.0",
+      "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
+      "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==",
+      "dev": true,
+      "requires": {
+        "@babel/code-frame": "^7.0.0",
+        "error-ex": "^1.3.1",
+        "json-parse-even-better-errors": "^2.3.0",
+        "lines-and-columns": "^1.1.6"
+      }
+    },
     "parse-semver": {
       "version": "1.1.1",
       "resolved": "https://registry.npmjs.org/parse-semver/-/parse-semver-1.1.1.tgz",
@@ -13740,6 +17939,54 @@
       "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz",
       "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ=="
     },
+    "pkg-dir": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz",
+      "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==",
+      "dev": true,
+      "requires": {
+        "find-up": "^4.0.0"
+      },
+      "dependencies": {
+        "find-up": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
+          "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+          "dev": true,
+          "requires": {
+            "locate-path": "^5.0.0",
+            "path-exists": "^4.0.0"
+          }
+        },
+        "locate-path": {
+          "version": "5.0.0",
+          "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
+          "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+          "dev": true,
+          "requires": {
+            "p-locate": "^4.1.0"
+          }
+        },
+        "p-limit": {
+          "version": "2.3.0",
+          "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+          "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+          "dev": true,
+          "requires": {
+            "p-try": "^2.0.0"
+          }
+        },
+        "p-locate": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
+          "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
+          "dev": true,
+          "requires": {
+            "p-limit": "^2.2.0"
+          }
+        }
+      }
+    },
     "postcss": {
       "version": "8.4.24",
       "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.24.tgz",
@@ -13807,9 +18054,9 @@
       "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ=="
     },
     "posthog-js": {
-      "version": "1.63.3",
-      "resolved": "https://registry.npmjs.org/posthog-js/-/posthog-js-1.63.3.tgz",
-      "integrity": "sha512-Ob2x1ENxx/mWAdhLhc6ouKAph9LwmitBy7M+hiaFoS0T9g7OVL4lYdrJbODbYV+HX/HeO3bsnQwYO1QLPWm/YA==",
+      "version": "1.68.5",
+      "resolved": "https://registry.npmjs.org/posthog-js/-/posthog-js-1.68.5.tgz",
+      "integrity": "sha512-EqQuIX0k564T2fhmzQK2Gcb8s/XRhHTpk6JOeGtJV7lpMI8Hffe+gGjGHcqIc4RoOg3LjAGYNHj6XgN+QPggLg==",
       "requires": {
         "fflate": "^0.4.1"
       }
@@ -13846,6 +18093,25 @@
       "integrity": "sha512-vIS4Rlc2FNh0BySk3Wkd6xmwxB0FpOndW5fisM5H8hsZSxU2VWVB5CWIkIjWvrHjIhxk2g3bfMKM87zNTrZddw==",
       "dev": true
     },
+    "pretty-format": {
+      "version": "29.5.0",
+      "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz",
+      "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==",
+      "dev": true,
+      "requires": {
+        "@jest/schemas": "^29.4.3",
+        "ansi-styles": "^5.0.0",
+        "react-is": "^18.0.0"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "5.2.0",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
+          "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
+          "dev": true
+        }
+      }
+    },
     "process-exists": {
       "version": "4.1.0",
       "resolved": "https://registry.npmjs.org/process-exists/-/process-exists-4.1.0.tgz",
@@ -13881,6 +18147,24 @@
         "retry": "^0.12.0"
       }
     },
+    "prompts": {
+      "version": "2.4.2",
+      "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz",
+      "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==",
+      "dev": true,
+      "requires": {
+        "kleur": "^3.0.3",
+        "sisteransi": "^1.0.5"
+      },
+      "dependencies": {
+        "kleur": {
+          "version": "3.0.3",
+          "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz",
+          "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==",
+          "dev": true
+        }
+      }
+    },
     "prop-types": {
       "version": "15.8.1",
       "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
@@ -13928,6 +18212,12 @@
       "integrity": "sha512-vKAcKbHEGA3cKbkNWwsA9MjHgIg4/X/xO/PnVQ/Pxt5eNC8/F726fGNlUlwwPej7NkmTg9OBWP4ovYvtdPtmXw==",
       "dev": true
     },
+    "pure-rand": {
+      "version": "6.0.2",
+      "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.0.2.tgz",
+      "integrity": "sha512-6Yg0ekpKICSjPswYOuC5sku/TSWaRYlA0qsXqJgM/d/4pLPHPuTxK7Nbf7jFKzAeedUhR8C7K9Uv63FBsSo8xQ==",
+      "dev": true
+    },
     "qs": {
       "version": "6.11.0",
       "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
@@ -14159,12 +18449,35 @@
       "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz",
       "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g=="
     },
+    "resolve-cwd": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz",
+      "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==",
+      "dev": true,
+      "requires": {
+        "resolve-from": "^5.0.0"
+      },
+      "dependencies": {
+        "resolve-from": {
+          "version": "5.0.0",
+          "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
+          "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==",
+          "dev": true
+        }
+      }
+    },
     "resolve-from": {
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
       "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
       "dev": true
     },
+    "resolve.exports": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz",
+      "integrity": "sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==",
+      "dev": true
+    },
     "responselike": {
       "version": "2.0.1",
       "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz",
@@ -14288,9 +18601,9 @@
       }
     },
     "semver": {
-      "version": "7.3.8",
-      "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
-      "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
+      "version": "7.5.3",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz",
+      "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==",
       "requires": {
         "lru-cache": "^6.0.0"
       }
@@ -14367,6 +18680,12 @@
         "simple-concat": "^1.0.0"
       }
     },
+    "sisteransi": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz",
+      "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==",
+      "dev": true
+    },
     "slash": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
@@ -14397,11 +18716,27 @@
         "socks": "^2.6.2"
       }
     },
+    "source-map": {
+      "version": "0.6.1",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+      "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+      "dev": true
+    },
     "source-map-js": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
       "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw=="
     },
+    "source-map-support": {
+      "version": "0.5.13",
+      "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz",
+      "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==",
+      "dev": true,
+      "requires": {
+        "buffer-from": "^1.0.0",
+        "source-map": "^0.6.0"
+      }
+    },
     "space-separated-tokens": {
       "version": "2.0.2",
       "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz",
@@ -14413,6 +18748,12 @@
       "integrity": "sha512-n98l9E2RMSJ9ON1AKisHzz7V42VDiBQGY6PB1BwRglz99wpVsSuGzQ+jOi6lFXBGVTCrRpltvjm+/XA+tpeJrg==",
       "dev": true
     },
+    "sprintf-js": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
+      "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==",
+      "dev": true
+    },
     "ssri": {
       "version": "9.0.1",
       "resolved": "https://registry.npmjs.org/ssri/-/ssri-9.0.1.tgz",
@@ -14421,6 +18762,23 @@
         "minipass": "^3.1.1"
       }
     },
+    "stack-utils": {
+      "version": "2.0.6",
+      "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz",
+      "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==",
+      "dev": true,
+      "requires": {
+        "escape-string-regexp": "^2.0.0"
+      },
+      "dependencies": {
+        "escape-string-regexp": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz",
+          "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==",
+          "dev": true
+        }
+      }
+    },
     "string_decoder": {
       "version": "1.1.1",
       "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
@@ -14436,6 +18794,33 @@
         }
       }
     },
+    "string-length": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz",
+      "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==",
+      "dev": true,
+      "requires": {
+        "char-regex": "^1.0.2",
+        "strip-ansi": "^6.0.0"
+      },
+      "dependencies": {
+        "ansi-regex": {
+          "version": "5.0.1",
+          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+          "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+          "dev": true
+        },
+        "strip-ansi": {
+          "version": "6.0.1",
+          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+          "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+          "dev": true,
+          "requires": {
+            "ansi-regex": "^5.0.1"
+          }
+        }
+      }
+    },
     "string-width": {
       "version": "4.2.3",
       "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
@@ -14469,6 +18854,12 @@
         "ansi-regex": "^6.0.1"
       }
     },
+    "strip-bom": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz",
+      "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==",
+      "dev": true
+    },
     "strip-final-newline": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz",
@@ -14683,6 +19074,33 @@
         "execa": "^5.1.1"
       }
     },
+    "test-exclude": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz",
+      "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==",
+      "dev": true,
+      "requires": {
+        "@istanbuljs/schema": "^0.1.2",
+        "glob": "^7.1.4",
+        "minimatch": "^3.0.4"
+      },
+      "dependencies": {
+        "glob": {
+          "version": "7.2.3",
+          "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+          "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
+          "dev": true,
+          "requires": {
+            "fs.realpath": "^1.0.0",
+            "inflight": "^1.0.4",
+            "inherits": "2",
+            "minimatch": "^3.1.1",
+            "once": "^1.3.0",
+            "path-is-absolute": "^1.0.0"
+          }
+        }
+      }
+    },
     "text-table": {
       "version": "0.2.0",
       "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
@@ -14730,11 +19148,16 @@
         "rimraf": "^3.0.0"
       }
     },
+    "tmpl": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz",
+      "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==",
+      "dev": true
+    },
     "to-fast-properties": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
-      "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==",
-      "peer": true
+      "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog=="
     },
     "to-regex-range": {
       "version": "5.0.1",
@@ -14776,6 +19199,30 @@
       "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz",
       "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA=="
     },
+    "ts-jest": {
+      "version": "29.1.1",
+      "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.1.1.tgz",
+      "integrity": "sha512-D6xjnnbP17cC85nliwGiL+tpoKN0StpgE0TeOjXQTU6MVCfsB4v7aW05CgQ/1OywGb0x/oy9hHFnN+sczTiRaA==",
+      "dev": true,
+      "requires": {
+        "bs-logger": "0.x",
+        "fast-json-stable-stringify": "2.x",
+        "jest-util": "^29.0.0",
+        "json5": "^2.2.3",
+        "lodash.memoize": "4.x",
+        "make-error": "1.x",
+        "semver": "^7.5.3",
+        "yargs-parser": "^21.0.1"
+      },
+      "dependencies": {
+        "yargs-parser": {
+          "version": "21.1.1",
+          "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
+          "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
+          "dev": true
+        }
+      }
+    },
     "tslib": {
       "version": "1.14.1",
       "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
@@ -14820,6 +19267,12 @@
         "prelude-ls": "^1.2.1"
       }
     },
+    "type-detect": {
+      "version": "4.0.8",
+      "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz",
+      "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==",
+      "dev": true
+    },
     "type-fest": {
       "version": "0.20.2",
       "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
@@ -14972,6 +19425,16 @@
         "setimmediate": "~1.0.4"
       }
     },
+    "update-browserslist-db": {
+      "version": "1.0.11",
+      "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz",
+      "integrity": "sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==",
+      "dev": true,
+      "requires": {
+        "escalade": "^3.1.1",
+        "picocolors": "^1.0.0"
+      }
+    },
     "uri-js": {
       "version": "4.4.1",
       "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
@@ -15014,6 +19477,25 @@
         "sade": "^1.7.3"
       }
     },
+    "v8-to-istanbul": {
+      "version": "9.1.0",
+      "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.1.0.tgz",
+      "integrity": "sha512-6z3GW9x8G1gd+JIIgQQQxXuiJtCXeAjp6RaPEPLv62mH3iPHPxV6W3robxtCzNErRo6ZwTmzWhsbNvjyEBKzKA==",
+      "dev": true,
+      "requires": {
+        "@jridgewell/trace-mapping": "^0.3.12",
+        "@types/istanbul-lib-coverage": "^2.0.1",
+        "convert-source-map": "^1.6.0"
+      },
+      "dependencies": {
+        "convert-source-map": {
+          "version": "1.9.0",
+          "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz",
+          "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==",
+          "dev": true
+        }
+      }
+    },
     "vfile": {
       "version": "5.3.7",
       "resolved": "https://registry.npmjs.org/vfile/-/vfile-5.3.7.tgz",
@@ -15180,6 +19662,15 @@
       "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.2.tgz",
       "integrity": "sha512-zHhCWatviizPIq9B7Vh9uvrH6x3sK8itC84HkamnBWoDFJtzBf7SWlpLCZUit72b3os45h6RWQNC9xHRDF8dRA=="
     },
+    "walker": {
+      "version": "1.0.8",
+      "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz",
+      "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==",
+      "dev": true,
+      "requires": {
+        "makeerror": "1.0.12"
+      }
+    },
     "wcwidth": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz",
@@ -15260,6 +19751,16 @@
       "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
       "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
     },
+    "write-file-atomic": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz",
+      "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==",
+      "dev": true,
+      "requires": {
+        "imurmurhash": "^0.1.4",
+        "signal-exit": "^3.0.7"
+      }
+    },
     "ws": {
       "version": "8.13.0",
       "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz",
diff --git a/extension/package.json b/extension/package.json
index 58ff2b61..212bb2d3 100644
--- a/extension/package.json
+++ b/extension/package.json
@@ -14,10 +14,10 @@
   "displayName": "Continue",
   "pricing": "Free",
   "description": "The open-source coding autopilot",
-  "version": "0.0.104",
+  "version": "0.0.105",
   "publisher": "Continue",
   "engines": {
-    "vscode": "^1.60.0"
+    "vscode": "^1.67.0"
   },
   "categories": [
     "Other",
@@ -209,6 +209,7 @@
     "pretest": "npm run compile && npm run lint",
     "lint": "eslint src --ext ts",
     "test": "node ./out/test/runTest.js",
+    "jest": "jest --config ./jest.config.js",
     "package": "cp ./config/prod_config.json ./config/config.json && mkdir -p ./build && vsce package --out ./build && cp ./config/dev_config.json ./config/config.json",
     "full-package": "cd ../continuedev && poetry build && cp ./dist/continuedev-0.1.2-py3-none-any.whl ../extension/scripts/continuedev-0.1.2-py3-none-any.whl && cd ../extension && npm install && npm run typegen && npm run clientgen && cd react-app && npm install && npm run build && cd .. && npm run package",
     "install-extension": "code --install-extension ./build/continue-0.0.8.vsix",
@@ -218,12 +219,13 @@
   "devDependencies": {
     "@openapitools/openapi-generator-cli": "^2.5.2",
     "@types/glob": "^8.0.0",
+    "@types/jest": "^29.5.2",
     "@types/mocha": "^10.0.1",
     "@types/node": "16.x",
     "@types/node-fetch": "^2.6.2",
     "@types/react-dom": "^18.2.4",
     "@types/styled-components": "^5.1.26",
-    "@types/vscode": "1.60",
+    "@types/vscode": "1.67",
     "@types/ws": "^8.5.4",
     "@typescript-eslint/eslint-plugin": "^5.45.0",
     "@typescript-eslint/parser": "^5.45.0",
@@ -231,8 +233,10 @@
     "esbuild": "^0.17.19",
     "eslint": "^8.28.0",
     "glob": "^8.0.3",
+    "jest": "^29.5.0",
     "json-schema-to-typescript": "^12.0.0",
     "mocha": "^10.1.0",
+    "ts-jest": "^29.1.1",
     "typescript": "^4.9.3",
     "vsce": "^2.15.0"
   },
@@ -248,7 +252,7 @@
     "downshift": "^7.6.0",
     "fkill": "^8.1.0",
     "highlight.js": "^11.7.0",
-    "posthog-js": "^1.63.3",
+    "posthog-js": "^1.68.3",
     "react-markdown": "^8.0.7",
     "react-redux": "^8.0.5",
     "strip-ansi": "^7.1.0",
diff --git a/extension/react-app/src/components/ComboBox.tsx b/extension/react-app/src/components/ComboBox.tsx
index f299c3a2..d9cd0d3d 100644
--- a/extension/react-app/src/components/ComboBox.tsx
+++ b/extension/react-app/src/components/ComboBox.tsx
@@ -269,7 +269,7 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
 
         <span className="text-trueGray-400 ml-auto mr-4 text-xs">
           Highlight code to include as context.{" "}
-          {highlightedCodeSections.length > 0 &&
+          {highlightedCodeSections.length === 0 &&
             "Otherwise using entire currently open file."}
         </span>
       </div>
diff --git a/extension/react-app/src/tabs/gui.tsx b/extension/react-app/src/tabs/gui.tsx
index e0b32a24..58aab984 100644
--- a/extension/react-app/src/tabs/gui.tsx
+++ b/extension/react-app/src/tabs/gui.tsx
@@ -215,30 +215,35 @@ function GUI(props: GUIProps) {
       mainTextInputRef.current.value = "";
       if (!client) return;
 
+      setWaitingForSteps(true);
+
       if (
-        history?.timeline.length &&
-        history.timeline[history.current_index].step.name ===
-          "Waiting for user input"
+        history &&
+        history.current_index >= 0 &&
+        history.current_index < history.timeline.length
       ) {
-        if (input.trim() === "") return;
-        onStepUserInput(input, history!.current_index);
-      } else if (
-        history?.timeline.length &&
-        history.timeline[history.current_index].step.name ===
+        if (
+          history.timeline[history.current_index].step.name ===
+          "Waiting for user input"
+        ) {
+          if (input.trim() === "") return;
+          onStepUserInput(input, history!.current_index);
+          return;
+        } else if (
+          history.timeline[history.current_index].step.name ===
           "Waiting for user confirmation"
-      ) {
-        onStepUserInput("ok", history!.current_index);
-      } else {
-        if (input.trim() === "") return;
-
-        client.sendMainInput(input);
-        setUserInputQueue((queue) => {
-          return [...queue, input];
-        });
+        ) {
+          onStepUserInput("ok", history!.current_index);
+          return;
+        }
       }
-    }
+      if (input.trim() === "") return;
 
-    setWaitingForSteps(true);
+      client.sendMainInput(input);
+      setUserInputQueue((queue) => {
+        return [...queue, input];
+      });
+    }
   };
 
   const onStepUserInput = (input: string, index: number) => {
diff --git a/extension/src/__mocks__/vscode.ts b/extension/src/__mocks__/vscode.ts
new file mode 100644
index 00000000..d415b5a0
--- /dev/null
+++ b/extension/src/__mocks__/vscode.ts
@@ -0,0 +1,7 @@
+const vscode = {
+  window: {
+    onDidChangeVisibleTextEditors: jest.fn(),
+  },
+};
+
+module.exports = vscode;
diff --git a/extension/src/activation/environmentSetup.ts b/extension/src/activation/environmentSetup.ts
index 4e6be9b3..71b774d9 100644
--- a/extension/src/activation/environmentSetup.ts
+++ b/extension/src/activation/environmentSetup.ts
@@ -4,7 +4,6 @@ const exec = util.promisify(require("child_process").exec);
 const { spawn } = require("child_process");
 import * as path from "path";
 import * as fs from "fs";
-import rebuild from "@electron/rebuild";
 import { getContinueServerUrl } from "../bridge";
 import fetch from "node-fetch";
 import * as vscode from "vscode";
@@ -60,7 +59,7 @@ async function runCommand(cmd: string): Promise<[string, string | undefined]> {
   return [stdout, stderr];
 }
 
-async function getPythonPipCommands() {
+export async function getPythonPipCommands() {
   var [stdout, stderr] = await runCommand("python3 --version");
   let pythonCmd = "python3";
   if (stderr) {
@@ -111,10 +110,8 @@ async function getPythonPipCommands() {
       );
       throw new Error("Python3.8 or greater is not installed.");
     }
-  } else {
-    pythonCmd = `python${major}.${minor}`;
-    pipCmd = `pip${major}.${minor}`;
   }
+
   return [pythonCmd, pipCmd];
 }
 
@@ -368,16 +365,6 @@ export async function startContinuePythonServer() {
   });
 }
 
-async function installNodeModules() {
-  console.log("Rebuilding node-pty for Continue extension...");
-  await rebuild({
-    buildPath: getExtensionUri().fsPath, // Folder containing node_modules
-    electronVersion: "19.1.8",
-    onlyModules: ["node-pty"],
-  });
-  console.log("Successfully rebuilt node-pty");
-}
-
 export function isPythonEnvSetup(): boolean {
   let pathToEnvCfg = getExtensionUri().fsPath + "/scripts/env/pyvenv.cfg";
   return fs.existsSync(path.join(pathToEnvCfg));
diff --git a/extension/src/activation/test/environmentSetup.test.ts b/extension/src/activation/test/environmentSetup.test.ts
new file mode 100644
index 00000000..ca487416
--- /dev/null
+++ b/extension/src/activation/test/environmentSetup.test.ts
@@ -0,0 +1,70 @@
+const child_process = require("child_process");
+import { platform } from "os";
+import { getPythonPipCommands } from "../environmentSetup";
+
+jest.mock("os");
+jest.mock("child_process");
+
+function mockPythonVersionMappings(mappings: { [pythonCmd: string]: string }) {
+  (child_process.exec as jest.Mock).mockImplementation(
+    (command: string, options: any) => {
+      const pythonCmd = command.split(" ")[0];
+      if (pythonCmd in mappings) {
+        return Promise.resolve([mappings[pythonCmd], ""]);
+      } else {
+        return Promise.resolve(["", stubStderr]);
+      }
+    }
+  );
+}
+
+const stubStderr =
+  "This is a stub stderr, but will be checked only for existence.";
+describe("getPythonPipCommands", () => {
+  describe("on Windows", () => {
+    it("should return the correct Python and Pip commands", async () => {
+      (platform as jest.Mock).mockReturnValue("win32");
+      mockPythonVersionMappings({
+        python: "Python 3.8.0",
+      });
+
+      const [pythonCmd, pipCmd] = await getPythonPipCommands();
+
+      expect(pythonCmd).toBe("python");
+      expect(pipCmd).toBe("pip");
+
+      jest.restoreAllMocks();
+    });
+    describe("on MacOS", () => {
+      (platform as jest.Mock).mockReturnValue("darwin");
+      it("should check through all python versions after finding 3.7", async () => {
+        mockPythonVersionMappings({
+          python: "",
+          python3: "Python 3.7.0",
+          "python3.11": "Python 3.11.0",
+        });
+
+        const [pythonCmd, pipCmd] = await getPythonPipCommands();
+
+        expect(pythonCmd).toBe("python3.11");
+        expect(pipCmd).toBe("pip3.11");
+
+        jest.restoreAllMocks();
+      });
+
+      it("should use python3 if that maps to valid version", async () => {
+        mockPythonVersionMappings({
+          python: "",
+          python3: "Python 3.8.0",
+        });
+
+        const [pythonCmd, pipCmd] = await getPythonPipCommands();
+
+        expect(pythonCmd).toBe("python3");
+        expect(pipCmd).toBe("pip3");
+
+        jest.restoreAllMocks();
+      });
+    });
+  });
+});
diff --git a/extension/src/test/suite/terminalEmulator.test.ts b/extension/src/test/suite/terminalEmulator.test.ts
deleted file mode 100644
index c4c159a4..00000000
--- a/extension/src/test/suite/terminalEmulator.test.ts
+++ /dev/null
@@ -1,28 +0,0 @@
-import { test, describe } from "mocha";
-import * as assert from "assert";
-import { PythonTracebackSnooper } from "../../terminal/snoopers";
-
-suite("Snoopers", () => {
-  suite("PythonTracebackSnooper", () => {
-    test("should detect traceback given all at once", async () => {
-      let traceback = `Traceback (most recent call last):
-              File "/Users/natesesti/Desktop/continue/extension/examples/python/main.py", line 10, in <module>
-                sum(first, second)
-              File "/Users/natesesti/Desktop/continue/extension/examples/python/sum.py", line 2, in sum
-                return a + b
-            TypeError: unsupported operand type(s) for +: 'int' and 'str'`;
-      let returnedTraceback = await new Promise((resolve) => {
-        let callback = (data: string) => {
-          resolve(data);
-        };
-        let snooper = new PythonTracebackSnooper(callback);
-        snooper.onData(traceback);
-      });
-      assert(
-        returnedTraceback === traceback,
-        "Detected \n" + returnedTraceback
-      );
-    });
-    test("should detect traceback given in chunks", () => {});
-  });
-});
-- 
cgit v1.2.3-70-g09d2


From 2ec0b4118bd092a528a1171df6ae4ffcd7cfb33b Mon Sep 17 00:00:00 2001
From: Nate Sesti <sestinj@gmail.com>
Date: Tue, 4 Jul 2023 12:47:28 -0700
Subject: better control over context

---
 extension/react-app/src/components/ComboBox.tsx    | 57 +++++++++++++++++++---
 .../src/components/HeaderButtonWithText.tsx        |  2 +
 extension/react-app/src/components/PillButton.tsx  |  9 ++--
 extension/react-app/src/components/index.ts        | 13 +++--
 extension/react-app/src/tabs/gui.tsx               | 23 +++++++--
 5 files changed, 82 insertions(+), 22 deletions(-)

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

diff --git a/extension/react-app/src/components/ComboBox.tsx b/extension/react-app/src/components/ComboBox.tsx
index 742c643b..bdb8850d 100644
--- a/extension/react-app/src/components/ComboBox.tsx
+++ b/extension/react-app/src/components/ComboBox.tsx
@@ -1,4 +1,4 @@
-import React, { useCallback, useEffect } from "react";
+import React, { useCallback, useEffect, useState } from "react";
 import { useCombobox } from "downshift";
 import styled from "styled-components";
 import {
@@ -10,7 +10,10 @@ import {
 import CodeBlock from "./CodeBlock";
 import { RangeInFile } from "../../../src/client";
 import PillButton from "./PillButton";
+import HeaderButtonWithText from "./HeaderButtonWithText";
+import { Trash, LockClosed, LockOpen } from "@styled-icons/heroicons-outline";
 
+// #region styled components
 const mainInputFontSize = 16;
 
 const ContextDropdown = styled.div`
@@ -87,13 +90,16 @@ const Li = styled.li<{
   cursor: pointer;
 `;
 
+// #endregion
+
 interface ComboBoxProps {
   items: { name: string; description: string }[];
   onInputValueChange: (inputValue: string) => void;
   disabled?: boolean;
-  onEnter?: (e: React.KeyboardEvent<HTMLInputElement>) => void;
-  highlightedCodeSections?: (RangeInFile & { contents: string })[];
-  deleteContextItem?: (idx: number) => void;
+  onEnter: (e: React.KeyboardEvent<HTMLInputElement>) => void;
+  highlightedCodeSections: (RangeInFile & { contents: string })[];
+  deleteContextItems: (indices: number[]) => void;
+  onTogglePin: () => void;
 }
 
 const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
@@ -104,6 +110,7 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
   const [hoveringButton, setHoveringButton] = React.useState(false);
   const [hoveringContextDropdown, setHoveringContextDropdown] =
     React.useState(false);
+  const [pinned, setPinned] = useState(false);
   const [highlightedCodeSections, setHighlightedCodeSections] = React.useState(
     props.highlightedCodeSections || [
       {
@@ -242,12 +249,46 @@ 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="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}
+            title={
+              hoveringButton
+                ? `${section.filepath} (${section.range.start.line + 1}-${
+                    section.range.end.line + 1
+                  })`
+                : section.filepath
+            }
             onDelete={() => {
-              if (props.deleteContextItem) {
-                props.deleteContextItem(idx);
+              if (props.deleteContextItems) {
+                props.deleteContextItems([idx]);
               }
               setHighlightedCodeSections((prev) => {
                 const newSections = [...prev];
@@ -280,7 +321,7 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
         onMouseLeave={() => {
           setHoveringContextDropdown(false);
         }}
-        hidden={!hoveringContextDropdown && !hoveringButton}
+        hidden={true || (!hoveringContextDropdown && !hoveringButton)}
       >
         {highlightedCodeSections.map((section, idx) => (
           <>
diff --git a/extension/react-app/src/components/HeaderButtonWithText.tsx b/extension/react-app/src/components/HeaderButtonWithText.tsx
index 30931f86..3ddac93c 100644
--- a/extension/react-app/src/components/HeaderButtonWithText.tsx
+++ b/extension/react-app/src/components/HeaderButtonWithText.tsx
@@ -7,12 +7,14 @@ interface HeaderButtonWithTextProps {
   onClick?: (e: any) => void;
   children: React.ReactNode;
   disabled?: boolean;
+  inverted?: boolean;
 }
 
 const HeaderButtonWithText = (props: HeaderButtonWithTextProps) => {
   const [hover, setHover] = useState(false);
   return (
     <HeaderButton
+      inverted={props.inverted}
       disabled={props.disabled}
       style={{ padding: "1px", paddingLeft: hover ? "4px" : "1px" }}
       onMouseEnter={() => {
diff --git a/extension/react-app/src/components/PillButton.tsx b/extension/react-app/src/components/PillButton.tsx
index 33451db5..55fe1ac6 100644
--- a/extension/react-app/src/components/PillButton.tsx
+++ b/extension/react-app/src/components/PillButton.tsx
@@ -1,6 +1,7 @@
 import { useState } from "react";
 import styled from "styled-components";
 import { defaultBorderRadius } from ".";
+import { XMark } from "@styled-icons/heroicons-outline";
 
 const Button = styled.button`
   border: none;
@@ -42,13 +43,12 @@ const PillButton = (props: PillButtonProps) => {
       <div
         style={{ display: "grid", gridTemplateColumns: "1fr auto", gap: "4px" }}
       >
-        <span>{props.title}</span>
         <span
           style={{
             cursor: "pointer",
             color: "red",
-            borderLeft: "1px solid black",
-            paddingLeft: "4px",
+            borderRight: "1px solid black",
+            paddingRight: "4px",
           }}
           hidden={!isHovered}
           onClick={() => {
@@ -56,8 +56,9 @@ const PillButton = (props: PillButtonProps) => {
             props.onHover?.(false);
           }}
         >
-          X
+          <XMark style={{ padding: "0px" }} size="1.2em" strokeWidth="2px" />
         </span>
+        <span>{props.title}</span>
       </div>
     </Button>
   );
diff --git a/extension/react-app/src/components/index.ts b/extension/react-app/src/components/index.ts
index 429a7df5..db1925ed 100644
--- a/extension/react-app/src/components/index.ts
+++ b/extension/react-app/src/components/index.ts
@@ -124,16 +124,19 @@ export const appear = keyframes`
     }
 `;
 
-export const HeaderButton = styled.button`
-  background-color: transparent;
+export const HeaderButton = styled.button<{ inverted: boolean | undefined }>`
+  background-color: ${({ inverted }) => (inverted ? "white" : "transparent")};
+  color: ${({ inverted }) => (inverted ? "black" : "white")};
+
   border: 1px solid white;
   border-radius: ${defaultBorderRadius};
   cursor: pointer;
-  color: white;
 
   &:hover {
-    background-color: white;
-    color: black;
+    background-color: ${({ inverted }) =>
+      typeof inverted === "undefined" || inverted ? "white" : "transparent"};
+    color: ${({ inverted }) =>
+      typeof inverted === "undefined" || inverted ? "black" : "white"};
   }
   display: flex;
   align-items: center;
diff --git a/extension/react-app/src/tabs/gui.tsx b/extension/react-app/src/tabs/gui.tsx
index 0a9e48fb..c2ff101a 100644
--- a/extension/react-app/src/tabs/gui.tsx
+++ b/extension/react-app/src/tabs/gui.tsx
@@ -70,10 +70,13 @@ 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([
+    { filepath: "abc.txt", range: { start: { line: 2 }, end: { line: 4 } } },
+  ]);
   const [availableSlashCommands, setAvailableSlashCommands] = useState<
     { name: string; description: string }[]
   >([]);
+  const [pinned, setPinned] = useState(false);
   const [showDataSharingInfo, setShowDataSharingInfo] = useState(false);
   const [stepsOpen, setStepsOpen] = useState<boolean[]>([
     true,
@@ -185,9 +188,9 @@ function GUI(props: GUIProps) {
 
   const mainTextInputRef = useRef<HTMLInputElement>(null);
 
-  const deleteContextItem = useCallback(
-    (idx: number) => {
-      client?.deleteContextAtIndices([idx]);
+  const deleteContextItems = useCallback(
+    (indices: number[]) => {
+      client?.deleteContextAtIndices(indices);
     },
     [client]
   );
@@ -241,6 +244,13 @@ function GUI(props: GUIProps) {
       setUserInputQueue((queue) => {
         return [...queue, input];
       });
+
+      // Delete all context items unless locked
+      if (!pinned) {
+        client?.deleteContextAtIndices(
+          highlightedRanges.map((_, index) => index)
+        );
+      }
     }
   };
 
@@ -345,7 +355,10 @@ function GUI(props: GUIProps) {
           onInputValueChange={() => {}}
           items={availableSlashCommands}
           highlightedCodeSections={highlightedRanges}
-          deleteContextItem={deleteContextItem}
+          deleteContextItems={deleteContextItems}
+          onTogglePin={() => {
+            setPinned((prev: boolean) => !prev);
+          }}
         />
         <ContinueButton onClick={onMainTextInput} />
       </TopGUIDiv>
-- 
cgit v1.2.3-70-g09d2


From 4b1d10f3bae1f1c80ecf74993f18f318c7b22b7f Mon Sep 17 00:00:00 2001
From: Nate Sesti <sestinj@gmail.com>
Date: Tue, 4 Jul 2023 13:43:09 -0700
Subject: many fixes

---
 continuedev/src/continuedev/core/autopilot.py             | 11 ++++++++---
 continuedev/src/continuedev/core/main.py                  |  7 +++----
 continuedev/src/continuedev/core/sdk.py                   | 13 ++++++++++++-
 continuedev/src/continuedev/steps/chat.py                 |  1 +
 extension/package-lock.json                               |  4 ++--
 extension/package.json                                    |  4 ++--
 extension/react-app/src/components/ComboBox.tsx           | 10 +++-------
 extension/react-app/src/components/PillButton.tsx         |  1 -
 extension/react-app/src/components/UserInputContainer.tsx |  6 ++++--
 extension/react-app/src/tabs/gui.tsx                      |  5 ++---
 10 files changed, 37 insertions(+), 25 deletions(-)

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

diff --git a/continuedev/src/continuedev/core/autopilot.py b/continuedev/src/continuedev/core/autopilot.py
index 05e48f40..313ceded 100644
--- a/continuedev/src/continuedev/core/autopilot.py
+++ b/continuedev/src/continuedev/core/autopilot.py
@@ -144,9 +144,7 @@ class Autopilot(ContinueBaseModel):
     async def handle_highlighted_code(self, range_in_files: List[RangeInFileWithContents]):
         workspace_path = self.continue_sdk.ide.workspace_directory
         for rif in range_in_files:
-            rif.filepath = os.path.relpath(rif.filepath, workspace_path)
-            if rif.filepath.startswith(".."):
-                rif.filepath = os.path.basename(rif.filepath)
+            rif.filepath = os.path.basename(rif.filepath)
 
         # If current range overlaps with any others, delete them and only keep the new range
         new_ranges = []
@@ -156,6 +154,13 @@ class Autopilot(ContinueBaseModel):
                 if rif.filepath == new_rif.filepath and rif.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:
+                    found_overlap = True
+                    break
+
             if not found_overlap:
                 new_ranges.append(rif)
 
diff --git a/continuedev/src/continuedev/core/main.py b/continuedev/src/continuedev/core/main.py
index 9a6617f4..8bad09d1 100644
--- a/continuedev/src/continuedev/core/main.py
+++ b/continuedev/src/continuedev/core/main.py
@@ -107,11 +107,9 @@ class HistoryNode(ContinueBaseModel):
             return self.step.chat_context
         return self.step.chat_context + [
             ChatMessage(
-                role="function",
+                role="assistant",
                 name=self.step.__class__.__name__,
-                content=json.dumps({
-                    "description": self.step.description or "Function complete",
-                }),
+                content=self.step.description or f"Ran function {self.step.name}",
                 summary=f"Called function {self.step.name}"
             )]
 
@@ -200,6 +198,7 @@ class SlashCommandDescription(ContinueBaseModel):
     name: str
     description: str
 
+
 class FullState(ContinueBaseModel):
     """A full state of the program, including the history"""
     history: History
diff --git a/continuedev/src/continuedev/core/sdk.py b/continuedev/src/continuedev/core/sdk.py
index 988ac6b0..fe975b99 100644
--- a/continuedev/src/continuedev/core/sdk.py
+++ b/continuedev/src/continuedev/core/sdk.py
@@ -97,7 +97,18 @@ class ContinueSDK(AbstractContinueSDK):
     async def _ensure_absolute_path(self, path: str) -> str:
         if os.path.isabs(path):
             return path
-        return os.path.join(self.ide.workspace_directory, path)
+
+        # Else if in workspace
+        workspace_path = os.path.join(self.ide.workspace_directory, path)
+        if os.path.exists(workspace_path):
+            return workspace_path
+        else:
+            # Check if it matches any of the open files, then use that absolute path
+            open_files = await self.ide.getOpenFiles()
+            for open_file in open_files:
+                if os.path.basename(open_file) == os.path.basename(path):
+                    return open_file
+            raise Exception(f"Path {path} does not exist")
 
     async def run_step(self, step: Step) -> Coroutine[Observation, None, None]:
         return await self.__autopilot._run_singular_step(step)
diff --git a/continuedev/src/continuedev/steps/chat.py b/continuedev/src/continuedev/steps/chat.py
index 49dd98e4..db3f9d7f 100644
--- a/continuedev/src/continuedev/steps/chat.py
+++ b/continuedev/src/continuedev/steps/chat.py
@@ -149,6 +149,7 @@ class ChatWithFunctions(Step):
     name: str = "Input"
     manage_own_chat_context: bool = True
     description: str = ""
+    hide: bool = True
 
     async def run(self, sdk: ContinueSDK):
         await sdk.update_ui()
diff --git a/extension/package-lock.json b/extension/package-lock.json
index c9b8b757..94823004 100644
--- a/extension/package-lock.json
+++ b/extension/package-lock.json
@@ -1,12 +1,12 @@
 {
   "name": "continue",
-  "version": "0.0.106",
+  "version": "0.0.107",
   "lockfileVersion": 2,
   "requires": true,
   "packages": {
     "": {
       "name": "continue",
-      "version": "0.0.106",
+      "version": "0.0.107",
       "license": "Apache-2.0",
       "dependencies": {
         "@electron/rebuild": "^3.2.10",
diff --git a/extension/package.json b/extension/package.json
index 184d16e2..6434efc3 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.106",
+  "version": "0.0.107",
   "publisher": "Continue",
   "engines": {
     "vscode": "^1.67.0"
@@ -55,7 +55,7 @@
         },
         "continue.OPENAI_API_KEY": {
           "type": "password",
-          "default": "",
+          "default": null,
           "description": "The OpenAI API key to use for code generation."
         },
         "continue.dataSwitch": {
diff --git a/extension/react-app/src/components/ComboBox.tsx b/extension/react-app/src/components/ComboBox.tsx
index bdb8850d..3e1f3e16 100644
--- a/extension/react-app/src/components/ComboBox.tsx
+++ b/extension/react-app/src/components/ComboBox.tsx
@@ -279,13 +279,9 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
         )}
         {highlightedCodeSections.map((section, idx) => (
           <PillButton
-            title={
-              hoveringButton
-                ? `${section.filepath} (${section.range.start.line + 1}-${
-                    section.range.end.line + 1
-                  })`
-                : section.filepath
-            }
+            title={`${section.filepath} (${section.range.start.line + 1}-${
+              section.range.end.line + 1
+            })`}
             onDelete={() => {
               if (props.deleteContextItems) {
                 props.deleteContextItems([idx]);
diff --git a/extension/react-app/src/components/PillButton.tsx b/extension/react-app/src/components/PillButton.tsx
index 55fe1ac6..2352c3ad 100644
--- a/extension/react-app/src/components/PillButton.tsx
+++ b/extension/react-app/src/components/PillButton.tsx
@@ -50,7 +50,6 @@ const PillButton = (props: PillButtonProps) => {
             borderRight: "1px solid black",
             paddingRight: "4px",
           }}
-          hidden={!isHovered}
           onClick={() => {
             props.onDelete?.();
             props.onHover?.(false);
diff --git a/extension/react-app/src/components/UserInputContainer.tsx b/extension/react-app/src/components/UserInputContainer.tsx
index 59453169..44fdba38 100644
--- a/extension/react-app/src/components/UserInputContainer.tsx
+++ b/extension/react-app/src/components/UserInputContainer.tsx
@@ -6,10 +6,12 @@ import HeaderButtonWithText from "./HeaderButtonWithText";
 import { Play, XMark } from "@styled-icons/heroicons-outline";
 import { RootStore } from "../redux/store";
 import { useSelector } from "react-redux";
+import { HistoryNode } from "../../../schema/HistoryNode";
 
 interface UserInputContainerProps {
   onDelete: () => void;
   children: string;
+  historyNode: HistoryNode;
 }
 
 const StyledDiv = styled.div`
@@ -26,7 +28,7 @@ const StyledDiv = styled.div`
 
 const UserInputContainer = (props: UserInputContainerProps) => {
   return (
-    <StyledDiv>
+    <StyledDiv hidden={props.historyNode.step.hide as any}>
       {props.children}
       <div style={{ marginLeft: "auto" }}>
         <HeaderButtonWithText
@@ -36,7 +38,7 @@ const UserInputContainer = (props: UserInputContainerProps) => {
           }}
           text="Delete"
         >
-          <XMark size="1.6em" onClick={props.onDelete} />
+          <XMark size="1.6em" />
         </HeaderButtonWithText>
       </div>
     </StyledDiv>
diff --git a/extension/react-app/src/tabs/gui.tsx b/extension/react-app/src/tabs/gui.tsx
index c2ff101a..8bfadc05 100644
--- a/extension/react-app/src/tabs/gui.tsx
+++ b/extension/react-app/src/tabs/gui.tsx
@@ -70,9 +70,7 @@ function GUI(props: GUIProps) {
   const [usingFastModel, setUsingFastModel] = useState(false);
   const [waitingForSteps, setWaitingForSteps] = useState(false);
   const [userInputQueue, setUserInputQueue] = useState<string[]>([]);
-  const [highlightedRanges, setHighlightedRanges] = useState([
-    { filepath: "abc.txt", range: { start: { line: 2 }, end: { line: 4 } } },
-  ]);
+  const [highlightedRanges, setHighlightedRanges] = useState([]);
   const [availableSlashCommands, setAvailableSlashCommands] = useState<
     { name: string; description: string }[]
   >([]);
@@ -296,6 +294,7 @@ function GUI(props: GUIProps) {
               onDelete={() => {
                 client?.deleteAtIndex(index);
               }}
+              historyNode={node}
             >
               {node.step.description as string}
             </UserInputContainer>
-- 
cgit v1.2.3-70-g09d2


From 8f080c4d2447e3eb66db448c08324ee71614709e Mon Sep 17 00:00:00 2001
From: Nate Sesti <sestinj@gmail.com>
Date: Wed, 5 Jul 2023 01:04:33 -0700
Subject: highlighted code improvements

---
 continuedev/src/continuedev/core/autopilot.py      | 11 ++++++++-
 continuedev/src/continuedev/core/main.py           |  1 +
 continuedev/src/continuedev/server/gui.py          |  7 ++++++
 continuedev/src/continuedev/steps/core/core.py     |  1 +
 extension/react-app/src/components/ComboBox.tsx    | 27 ++++++++++++++++++----
 extension/react-app/src/components/PillButton.tsx  | 27 +++++++---------------
 .../src/components/UserInputContainer.tsx          |  4 +++-
 .../src/hooks/ContinueGUIClientProtocol.ts         |  2 ++
 .../react-app/src/hooks/useContinueGUIProtocol.ts  |  4 ++++
 extension/react-app/src/tabs/gui.tsx               |  6 +++++
 10 files changed, 65 insertions(+), 25 deletions(-)

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

diff --git a/continuedev/src/continuedev/core/autopilot.py b/continuedev/src/continuedev/core/autopilot.py
index 313ceded..29be3b79 100644
--- a/continuedev/src/continuedev/core/autopilot.py
+++ b/continuedev/src/continuedev/core/autopilot.py
@@ -69,7 +69,8 @@ class Autopilot(ContinueBaseModel):
             user_input_queue=self._main_user_input_queue,
             default_model=self.continue_sdk.config.default_model,
             highlighted_ranges=self._highlighted_ranges,
-            slash_commands=self.get_available_slash_commands()
+            slash_commands=self.get_available_slash_commands(),
+            adding_highlighted_code=self._adding_highlighted_code,
         )
 
     def get_available_slash_commands(self) -> List[Dict]:
@@ -140,8 +141,12 @@ class Autopilot(ContinueBaseModel):
                     await self._run_singular_step(step)
 
     _highlighted_ranges: List[RangeInFileWithContents] = []
+    _adding_highlighted_code: bool = False
 
     async def handle_highlighted_code(self, range_in_files: List[RangeInFileWithContents]):
+        if not self._adding_highlighted_code:
+            return
+
         workspace_path = self.continue_sdk.ide.workspace_directory
         for rif in range_in_files:
             rif.filepath = os.path.basename(rif.filepath)
@@ -186,6 +191,10 @@ class Autopilot(ContinueBaseModel):
         self._highlighted_ranges = kept_ranges
         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 _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:
diff --git a/continuedev/src/continuedev/core/main.py b/continuedev/src/continuedev/core/main.py
index 8bad09d1..28fd964e 100644
--- a/continuedev/src/continuedev/core/main.py
+++ b/continuedev/src/continuedev/core/main.py
@@ -207,6 +207,7 @@ class FullState(ContinueBaseModel):
     default_model: str
     highlighted_ranges: List[RangeInFileWithContents]
     slash_commands: List[SlashCommandDescription]
+    adding_highlighted_code: bool
 
 
 class ContinueSDK:
diff --git a/continuedev/src/continuedev/server/gui.py b/continuedev/src/continuedev/server/gui.py
index 4e960f7c..fa573b37 100644
--- a/continuedev/src/continuedev/server/gui.py
+++ b/continuedev/src/continuedev/server/gui.py
@@ -85,6 +85,8 @@ class GUIProtocolServer(AbstractGUIProtocolServer):
                 self.on_delete_at_index(data["index"])
             elif message_type == "delete_context_at_indices":
                 self.on_delete_context_at_indices(data["indices"])
+            elif message_type == "toggle_adding_highlighted_code":
+                self.on_toggle_adding_highlighted_code()
         except Exception as e:
             print(e)
 
@@ -128,6 +130,11 @@ class GUIProtocolServer(AbstractGUIProtocolServer):
             self.session.autopilot.delete_context_at_indices(indices)
         )
 
+    def on_toggle_adding_highlighted_code(self):
+        asyncio.create_task(
+            self.session.autopilot.toggle_adding_highlighted_code()
+        )
+
 
 @router.websocket("/ws")
 async def websocket_endpoint(websocket: WebSocket, session: Session = Depends(websocket_session)):
diff --git a/continuedev/src/continuedev/steps/core/core.py b/continuedev/src/continuedev/steps/core/core.py
index b215b317..c74412ba 100644
--- a/continuedev/src/continuedev/steps/core/core.py
+++ b/continuedev/src/continuedev/steps/core/core.py
@@ -286,6 +286,7 @@ class DefaultModelEditCodeStep(Step):
         return "```" in line or "<modified_code_to_edit>" in line or "<file_prefix>" in line or "</file_prefix>" in line or "<file_suffix>" in line or "</file_suffix>" in line or "<user_request>" in line or "</user_request>" in line or "<code_to_edit>" in line
 
     async def stream_rif(self, rif: RangeInFileWithContents, sdk: ContinueSDK):
+        await sdk.ide.saveFile(rif.filepath)
         full_file_contents = await sdk.ide.readFile(rif.filepath)
 
         file_prefix, contents, file_suffix, model_to_use = await self.get_prompt_parts(
diff --git a/extension/react-app/src/components/ComboBox.tsx b/extension/react-app/src/components/ComboBox.tsx
index 3e1f3e16..97f5b57e 100644
--- a/extension/react-app/src/components/ComboBox.tsx
+++ b/extension/react-app/src/components/ComboBox.tsx
@@ -11,7 +11,12 @@ import CodeBlock from "./CodeBlock";
 import { RangeInFile } from "../../../src/client";
 import PillButton from "./PillButton";
 import HeaderButtonWithText from "./HeaderButtonWithText";
-import { Trash, LockClosed, LockOpen } from "@styled-icons/heroicons-outline";
+import {
+  Trash,
+  LockClosed,
+  LockOpen,
+  Plus,
+} from "@styled-icons/heroicons-outline";
 
 // #region styled components
 const mainInputFontSize = 16;
@@ -100,6 +105,8 @@ interface ComboBoxProps {
   highlightedCodeSections: (RangeInFile & { contents: string })[];
   deleteContextItems: (indices: number[]) => void;
   onTogglePin: () => void;
+  onToggleAddContext: () => void;
+  addingHighlightedCode: boolean;
 }
 
 const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
@@ -249,6 +256,19 @@ 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
@@ -305,9 +325,8 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
         ))}
 
         <span className="text-trueGray-400 ml-auto mr-4 text-xs">
-          Highlight code to include as context.{" "}
-          {highlightedCodeSections.length === 0 &&
-            "Otherwise using entire currently open file."}
+          Highlight code to include as context. Currently open file included by
+          default. {highlightedCodeSections.length === 0 && ""}
         </span>
       </div>
       <ContextDropdown
diff --git a/extension/react-app/src/components/PillButton.tsx b/extension/react-app/src/components/PillButton.tsx
index 2352c3ad..5a02c6b2 100644
--- a/extension/react-app/src/components/PillButton.tsx
+++ b/extension/react-app/src/components/PillButton.tsx
@@ -15,6 +15,8 @@ const Button = styled.button`
     background-color: white;
     color: black;
   }
+
+  cursor: pointer;
 `;
 
 interface PillButtonProps {
@@ -39,26 +41,13 @@ const PillButton = (props: PillButtonProps) => {
           props.onHover(false);
         }
       }}
+      onClick={() => {
+        if (props.onDelete) {
+          props.onDelete();
+        }
+      }}
     >
-      <div
-        style={{ display: "grid", gridTemplateColumns: "1fr auto", gap: "4px" }}
-      >
-        <span
-          style={{
-            cursor: "pointer",
-            color: "red",
-            borderRight: "1px solid black",
-            paddingRight: "4px",
-          }}
-          onClick={() => {
-            props.onDelete?.();
-            props.onHover?.(false);
-          }}
-        >
-          <XMark style={{ padding: "0px" }} size="1.2em" strokeWidth="2px" />
-        </span>
-        <span>{props.title}</span>
-      </div>
+      {props.title}
     </Button>
   );
 };
diff --git a/extension/react-app/src/components/UserInputContainer.tsx b/extension/react-app/src/components/UserInputContainer.tsx
index 44fdba38..a72f6098 100644
--- a/extension/react-app/src/components/UserInputContainer.tsx
+++ b/extension/react-app/src/components/UserInputContainer.tsx
@@ -14,7 +14,7 @@ interface UserInputContainerProps {
   historyNode: HistoryNode;
 }
 
-const StyledDiv = styled.div`
+const StyledDiv = styled.div<{ hidden: boolean }>`
   background-color: rgb(50 50 50);
   padding: 8px;
   padding-left: 16px;
@@ -24,6 +24,8 @@ const StyledDiv = styled.div`
   font-size: 13px;
   display: flex;
   align-items: center;
+  visibility: ${(props) => (props.hidden ? "hidden" : "visible")};
+  height: ${(props) => (props.hidden ? "0px" : "auto")};
 `;
 
 const UserInputContainer = (props: UserInputContainerProps) => {
diff --git a/extension/react-app/src/hooks/ContinueGUIClientProtocol.ts b/extension/react-app/src/hooks/ContinueGUIClientProtocol.ts
index 96ea7ab3..f123bb2b 100644
--- a/extension/react-app/src/hooks/ContinueGUIClientProtocol.ts
+++ b/extension/react-app/src/hooks/ContinueGUIClientProtocol.ts
@@ -22,6 +22,8 @@ abstract class AbstractContinueGUIClientProtocol {
   abstract deleteAtIndex(index: number): void;
 
   abstract deleteContextAtIndices(indices: number[]): void;
+
+  abstract toggleAddingHighlightedCode(): void;
 }
 
 export default AbstractContinueGUIClientProtocol;
diff --git a/extension/react-app/src/hooks/useContinueGUIProtocol.ts b/extension/react-app/src/hooks/useContinueGUIProtocol.ts
index e950387c..49f200ae 100644
--- a/extension/react-app/src/hooks/useContinueGUIProtocol.ts
+++ b/extension/react-app/src/hooks/useContinueGUIProtocol.ts
@@ -74,6 +74,10 @@ class ContinueGUIClientProtocol extends AbstractContinueGUIClientProtocol {
   deleteContextAtIndices(indices: number[]) {
     this.messenger.send("delete_context_at_indices", { indices });
   }
+
+  toggleAddingHighlightedCode(): void {
+    this.messenger.send("toggle_adding_highlighted_code", {});
+  }
 }
 
 export default ContinueGUIClientProtocol;
diff --git a/extension/react-app/src/tabs/gui.tsx b/extension/react-app/src/tabs/gui.tsx
index bbf0b126..851045d5 100644
--- a/extension/react-app/src/tabs/gui.tsx
+++ b/extension/react-app/src/tabs/gui.tsx
@@ -71,6 +71,7 @@ function GUI(props: GUIProps) {
   const [waitingForSteps, setWaitingForSteps] = useState(false);
   const [userInputQueue, setUserInputQueue] = useState<string[]>([]);
   const [highlightedRanges, setHighlightedRanges] = useState([]);
+  const [addingHighlightedCode, setAddingHighlightedCode] = useState(false);
   const [availableSlashCommands, setAvailableSlashCommands] = useState<
     { name: string; description: string }[]
   >([]);
@@ -157,6 +158,7 @@ function GUI(props: GUIProps) {
       setHistory(state.history);
       setHighlightedRanges(state.highlighted_ranges);
       setUserInputQueue(state.user_input_queue);
+      setAddingHighlightedCode(state.adding_highlighted_code);
       setAvailableSlashCommands(
         state.slash_commands.map((c: any) => {
           return {
@@ -361,6 +363,10 @@ function GUI(props: GUIProps) {
           onTogglePin={() => {
             setPinned((prev: boolean) => !prev);
           }}
+          onToggleAddContext={() => {
+            client?.toggleAddingHighlightedCode();
+          }}
+          addingHighlightedCode={addingHighlightedCode}
         />
         <ContinueButton onClick={onMainTextInput} />
       </TopGUIDiv>
-- 
cgit v1.2.3-70-g09d2


From c5cee3f4c40e7ff00265929b3a593d62b4b50ada Mon Sep 17 00:00:00 2001
From: Nate Sesti <sestinj@gmail.com>
Date: Wed, 5 Jul 2023 01:51:46 -0700
Subject: details

---
 continuedev/src/continuedev/core/policy.py         | 64 ++++++++++++----------
 extension/package-lock.json                        |  4 +-
 extension/package.json                             |  2 +-
 extension/react-app/src/components/ComboBox.tsx    |  2 +-
 .../react-app/src/components/StepContainer.tsx     | 12 ++--
 .../src/components/UserInputContainer.tsx          | 10 ++--
 extension/react-app/src/tabs/gui.tsx               | 18 +++---
 7 files changed, 61 insertions(+), 51 deletions(-)

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

diff --git a/continuedev/src/continuedev/core/policy.py b/continuedev/src/continuedev/core/policy.py
index b0853380..ef753ee4 100644
--- a/continuedev/src/continuedev/core/policy.py
+++ b/continuedev/src/continuedev/core/policy.py
@@ -1,5 +1,5 @@
 from textwrap import dedent
-from typing import List, Tuple, Type
+from typing import List, Tuple, Type, Union
 
 from ..steps.welcome import WelcomeStep
 from .config import ContinueConfig
@@ -22,6 +22,34 @@ from ..libs.util.step_name_to_steps import get_step_from_name
 from ..steps.custom_command import CustomCommandStep
 
 
+def parse_slash_command(inp: str, config: ContinueConfig) -> Union[None, Step]:
+    """
+    Parses a slash command, returning the command name and the rest of the input.
+    """
+    if inp.startswith("/"):
+        command_name = inp.split(" ")[0]
+        after_command = " ".join(inp.split(" ")[1:])
+
+        for slash_command in config.slash_commands:
+            if slash_command.name == command_name[1:]:
+                params = slash_command.params
+                params["user_input"] = after_command
+                return get_step_from_name(slash_command.step_name, params)
+    return None
+
+
+def parse_custom_command(inp: str, config: ContinueConfig) -> Union[None, Step]:
+    command_name = inp.split(" ")[0]
+    after_command = " ".join(inp.split(" ")[1:])
+    for custom_cmd in config.custom_commands:
+        if custom_cmd.name == command_name[1:]:
+            slash_command = parse_slash_command(custom_cmd.prompt, config)
+            if slash_command is not None:
+                return slash_command
+            return CustomCommandStep(name=custom_cmd.name, prompt=custom_cmd.prompt, user_input=after_command)
+    return None
+
+
 class DemoPolicy(Policy):
     ran_code_last: bool = False
 
@@ -46,34 +74,14 @@ class DemoPolicy(Policy):
             # This could be defined with ObservationTypePolicy. Ergonomics not right though.
             user_input = observation.user_input
 
-            if user_input.startswith("/"):
-                command_name = user_input.split(" ")[0]
-                after_command = " ".join(user_input.split(" ")[1:])
-                for slash_command in config.slash_commands:
-                    if slash_command.name == command_name[1:]:
-                        params = slash_command.params
-                        params["user_input"] = after_command
-                        return get_step_from_name(slash_command.step_name, params)
+            slash_command = parse_slash_command(user_input)
+            if slash_command is not None:
+                return slash_command
 
-                for custom_cmd in config.custom_commands:
-                    if custom_cmd.name == command_name[1:]:
-                        return CustomCommandStep(name=custom_cmd.name, prompt=custom_cmd.prompt, user_input=after_command)
+            custom_command = parse_custom_command(user_input)
+            if custom_command is not None:
+                return custom_command
 
-            # return EditHighlightedCodeStep(user_input=user_input)
             return ChatWithFunctions(user_input=user_input)
-            return NLDecisionStep(user_input=user_input, steps=[
-                (EditHighlightedCodeStep(user_input=user_input),
-                 "Edit the highlighted code"),
-                # AnswerQuestionChroma(question=user_input),
-                # EditFileChroma(request=user_input),
-                (SimpleChatStep(user_input=user_input),
-                 "Respond to the user with a chat message. Can answer questions about code or anything else."),
-            ], default_step=EditHighlightedCodeStep(user_input=user_input))
-
-        state = history.get_current()
 
-        if observation is not None and isinstance(observation, TracebackObservation):
-            self.ran_code_last = False
-            return SolveTracebackStep(traceback=observation.traceback)
-        else:
-            return None
+        return None
diff --git a/extension/package-lock.json b/extension/package-lock.json
index 82c28a90..ce1a42ee 100644
--- a/extension/package-lock.json
+++ b/extension/package-lock.json
@@ -1,12 +1,12 @@
 {
   "name": "continue",
-  "version": "0.0.109",
+  "version": "0.0.110",
   "lockfileVersion": 2,
   "requires": true,
   "packages": {
     "": {
       "name": "continue",
-      "version": "0.0.109",
+      "version": "0.0.110",
       "license": "Apache-2.0",
       "dependencies": {
         "@electron/rebuild": "^3.2.10",
diff --git a/extension/package.json b/extension/package.json
index 001a696e..607c2ca6 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.109",
+  "version": "0.0.110",
   "publisher": "Continue",
   "engines": {
     "vscode": "^1.67.0"
diff --git a/extension/react-app/src/components/ComboBox.tsx b/extension/react-app/src/components/ComboBox.tsx
index 97f5b57e..73b7cc2d 100644
--- a/extension/react-app/src/components/ComboBox.tsx
+++ b/extension/react-app/src/components/ComboBox.tsx
@@ -324,7 +324,7 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
           />
         ))}
 
-        <span className="text-trueGray-400 ml-auto mr-4 text-xs">
+        <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>
diff --git a/extension/react-app/src/components/StepContainer.tsx b/extension/react-app/src/components/StepContainer.tsx
index 183ffeef..2aed2e72 100644
--- a/extension/react-app/src/components/StepContainer.tsx
+++ b/extension/react-app/src/components/StepContainer.tsx
@@ -11,11 +11,9 @@ import {
   ChevronDown,
   ChevronRight,
   ArrowPath,
-  XMark
+  XMark,
 } from "@styled-icons/heroicons-outline";
-import {
-  Stop,
-} from "@styled-icons/heroicons-solid";
+import { Stop } from "@styled-icons/heroicons-solid";
 import { HistoryNode } from "../../../schema/HistoryNode";
 import ReactMarkdown from "react-markdown";
 import HeaderButtonWithText from "./HeaderButtonWithText";
@@ -213,7 +211,11 @@ function StepContainer(props: StepContainerProps) {
                 text={props.historyNode.active ? "Stop" : "Delete"}
                 active={props.historyNode.active}
               >
-                {props.historyNode.active ? <Stop size="1.6em" onClick={props.onDelete} /> :<XMark size="1.6em" onClick={props.onDelete} />}
+                {props.historyNode.active ? (
+                  <Stop size="1.2em" onClick={props.onDelete} />
+                ) : (
+                  <XMark size="1.6em" onClick={props.onDelete} />
+                )}
               </HeaderButtonWithText>
               {props.historyNode.observation?.error ? (
                 <HeaderButtonWithText
diff --git a/extension/react-app/src/components/UserInputContainer.tsx b/extension/react-app/src/components/UserInputContainer.tsx
index a72f6098..28437d35 100644
--- a/extension/react-app/src/components/UserInputContainer.tsx
+++ b/extension/react-app/src/components/UserInputContainer.tsx
@@ -14,8 +14,8 @@ interface UserInputContainerProps {
   historyNode: HistoryNode;
 }
 
-const StyledDiv = styled.div<{ hidden: boolean }>`
-  background-color: rgb(50 50 50);
+const StyledDiv = styled.div`
+  background-color: rgb(45 45 45);
   padding: 8px;
   padding-left: 16px;
   padding-right: 16px;
@@ -24,14 +24,12 @@ const StyledDiv = styled.div<{ hidden: boolean }>`
   font-size: 13px;
   display: flex;
   align-items: center;
-  visibility: ${(props) => (props.hidden ? "hidden" : "visible")};
-  height: ${(props) => (props.hidden ? "0px" : "auto")};
 `;
 
 const UserInputContainer = (props: UserInputContainerProps) => {
   return (
-    <StyledDiv hidden={props.historyNode.step.hide as any}>
-      {props.children}
+    <StyledDiv>
+      <b>{props.children}</b>
       <div style={{ marginLeft: "auto" }}>
         <HeaderButtonWithText
           onClick={(e) => {
diff --git a/extension/react-app/src/tabs/gui.tsx b/extension/react-app/src/tabs/gui.tsx
index 851045d5..e5320c6a 100644
--- a/extension/react-app/src/tabs/gui.tsx
+++ b/extension/react-app/src/tabs/gui.tsx
@@ -295,14 +295,16 @@ function GUI(props: GUIProps) {
         )}
         {history?.timeline.map((node: HistoryNode, index: number) => {
           return node.step.name === "User Input" ? (
-            <UserInputContainer
-              onDelete={() => {
-                client?.deleteAtIndex(index);
-              }}
-              historyNode={node}
-            >
-              {node.step.description as string}
-            </UserInputContainer>
+            node.step.hide || (
+              <UserInputContainer
+                onDelete={() => {
+                  client?.deleteAtIndex(index);
+                }}
+                historyNode={node}
+              >
+                {node.step.description as string}
+              </UserInputContainer>
+            )
           ) : (
             <StepContainer
               isLast={index === history.timeline.length - 1}
-- 
cgit v1.2.3-70-g09d2


From dd5214994f167e4aa9ee986c6b441bc21ffadf42 Mon Sep 17 00:00:00 2001
From: Nate Sesti <sestinj@gmail.com>
Date: Wed, 5 Jul 2023 12:09:10 -0700
Subject: explain by default

---
 continuedev/src/continuedev/core/config.py      | 12 ++++++------
 continuedev/src/continuedev/core/policy.py      |  6 +++---
 extension/package-lock.json                     |  4 ++--
 extension/package.json                          |  2 +-
 extension/react-app/src/components/ComboBox.tsx |  5 +++++
 extension/src/diffs.ts                          |  8 +++++++-
 6 files changed, 24 insertions(+), 13 deletions(-)

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

diff --git a/continuedev/src/continuedev/core/config.py b/continuedev/src/continuedev/core/config.py
index 8f7e0b8c..ff7b8cb0 100644
--- a/continuedev/src/continuedev/core/config.py
+++ b/continuedev/src/continuedev/core/config.py
@@ -33,11 +33,11 @@ DEFAULT_SLASH_COMMANDS = [
         description="Edit code in the current file or the highlighted code",
         step_name="EditHighlightedCodeStep",
     ),
-    SlashCommand(
-        name="explain",
-        description="Reply to instructions or a question with previous steps and the highlighted code or current file as context",
-        step_name="SimpleChatStep",
-    ),
+    # SlashCommand(
+    #     name="explain",
+    #     description="Reply to instructions or a question with previous steps and the highlighted code or current file as context",
+    #     step_name="SimpleChatStep",
+    # ),
     SlashCommand(
         name="config",
         description="Open the config file to create new and edit existing slash commands",
@@ -129,7 +129,7 @@ def load_global_config() -> ContinueConfig:
         config_path = os.path.join(global_dir, 'config.json')
         if not os.path.exists(config_path):
             with open(config_path, 'w') as f:
-                json.dump(dict(ContinueConfig()), f)
+                json.dump(ContinueConfig().dict(), f)
         with open(config_path, 'r') as f:
             try:
                 config_dict = json.load(f)
diff --git a/continuedev/src/continuedev/core/policy.py b/continuedev/src/continuedev/core/policy.py
index ef753ee4..fc9266ab 100644
--- a/continuedev/src/continuedev/core/policy.py
+++ b/continuedev/src/continuedev/core/policy.py
@@ -74,14 +74,14 @@ class DemoPolicy(Policy):
             # This could be defined with ObservationTypePolicy. Ergonomics not right though.
             user_input = observation.user_input
 
-            slash_command = parse_slash_command(user_input)
+            slash_command = parse_slash_command(user_input, config)
             if slash_command is not None:
                 return slash_command
 
-            custom_command = parse_custom_command(user_input)
+            custom_command = parse_custom_command(user_input, config)
             if custom_command is not None:
                 return custom_command
 
-            return ChatWithFunctions(user_input=user_input)
+            return SimpleChatStep(user_input=user_input)
 
         return None
diff --git a/extension/package-lock.json b/extension/package-lock.json
index ce1a42ee..169b13b5 100644
--- a/extension/package-lock.json
+++ b/extension/package-lock.json
@@ -1,12 +1,12 @@
 {
   "name": "continue",
-  "version": "0.0.110",
+  "version": "0.0.111",
   "lockfileVersion": 2,
   "requires": true,
   "packages": {
     "": {
       "name": "continue",
-      "version": "0.0.110",
+      "version": "0.0.111",
       "license": "Apache-2.0",
       "dependencies": {
         "@electron/rebuild": "^3.2.10",
diff --git a/extension/package.json b/extension/package.json
index 607c2ca6..6a0f9eb3 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.110",
+  "version": "0.0.111",
   "publisher": "Continue",
   "engines": {
     "vscode": "^1.67.0"
diff --git a/extension/react-app/src/components/ComboBox.tsx b/extension/react-app/src/components/ComboBox.tsx
index 73b7cc2d..545be32a 100644
--- a/extension/react-app/src/components/ComboBox.tsx
+++ b/extension/react-app/src/components/ComboBox.tsx
@@ -195,6 +195,11 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
               ) {
                 // Prevent Downshift's default 'Enter' behavior.
                 (event.nativeEvent as any).preventDownshiftDefault = true;
+
+                // cmd+enter to /edit
+                if (event.metaKey) {
+                  event.currentTarget.value = `/edit ${event.currentTarget}`;
+                }
                 if (props.onEnter) props.onEnter(event);
                 setInputValue("");
                 const value = event.currentTarget.value;
diff --git a/extension/src/diffs.ts b/extension/src/diffs.ts
index 19ec80ab..b70c3b59 100644
--- a/extension/src/diffs.ts
+++ b/extension/src/diffs.ts
@@ -16,7 +16,7 @@ class DiffManager {
   // Doing this because virtual files are read-only
   private diffs: Map<string, DiffInfo> = new Map();
 
-  constructor() {
+  private setupDirectory() {
     // Make sure the diff directory exists
     if (!fs.existsSync(DIFF_DIRECTORY)) {
       fs.mkdirSync(DIFF_DIRECTORY, {
@@ -25,6 +25,10 @@ class DiffManager {
     }
   }
 
+  constructor() {
+    this.setupDirectory();
+  }
+
   private escapeFilepath(filepath: string): string {
     return filepath.replace(/\\/g, "_").replace(/\//g, "_");
   }
@@ -47,6 +51,8 @@ class DiffManager {
   }
 
   writeDiff(originalFilepath: string, newContent: string): string {
+    this.setupDirectory();
+
     // Create or update existing diff
     const newFilepath = path.join(
       DIFF_DIRECTORY,
-- 
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/components/ComboBox.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 d259979ef89f17957396fc7300e1ecf54214ae84 Mon Sep 17 00:00:00 2001
From: Nate Sesti <sestinj@gmail.com>
Date: Wed, 5 Jul 2023 20:35:59 -0700
Subject: stuff

---
 continuedev/src/continuedev/core/autopilot.py   |  4 ++++
 continuedev/src/continuedev/steps/core/core.py  | 19 +++++++++++--------
 extension/package-lock.json                     |  4 ++--
 extension/package.json                          |  6 +++---
 extension/react-app/src/components/ComboBox.tsx |  2 +-
 extension/src/diffs.ts                          | 22 ++++++++++++++++++----
 6 files changed, 39 insertions(+), 18 deletions(-)

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

diff --git a/continuedev/src/continuedev/core/autopilot.py b/continuedev/src/continuedev/core/autopilot.py
index 29be3b79..b1c4f471 100644
--- a/continuedev/src/continuedev/core/autopilot.py
+++ b/continuedev/src/continuedev/core/autopilot.py
@@ -147,6 +147,10 @@ class Autopilot(ContinueBaseModel):
         if not self._adding_highlighted_code:
             return
 
+        # Filter out rifs from ~/.continue/diffs folder
+        range_in_files = [
+            rif for rif in range_in_files if not os.path.dirname(rif.filepath) == os.path.expanduser("~/.continue/diffs")]
+
         workspace_path = self.continue_sdk.ide.workspace_directory
         for rif in range_in_files:
             rif.filepath = os.path.basename(rif.filepath)
diff --git a/continuedev/src/continuedev/steps/core/core.py b/continuedev/src/continuedev/steps/core/core.py
index c74412ba..3a7c8876 100644
--- a/continuedev/src/continuedev/steps/core/core.py
+++ b/continuedev/src/continuedev/steps/core/core.py
@@ -332,8 +332,9 @@ class DefaultModelEditCodeStep(Step):
 
             # Highlight the line to show progress
             line_to_highlight = current_line_in_file - len(current_block_lines)
-            await sdk.ide.highlightCode(RangeInFile(filepath=rif.filepath, range=Range.from_shorthand(
-                line_to_highlight, 0, line_to_highlight, 0)), "#FFFFFF22" if len(current_block_lines) == 0 else "#00FF0022")
+            if False:
+                await sdk.ide.highlightCode(RangeInFile(filepath=rif.filepath, range=Range.from_shorthand(
+                    line_to_highlight, 0, line_to_highlight, 0)), "#FFFFFF22" if len(current_block_lines) == 0 else "#00FF0022")
 
             if len(current_block_lines) == 0:
                 # Set this as the start of the next block
@@ -382,12 +383,14 @@ class DefaultModelEditCodeStep(Step):
                 replacement = "\n".join(current_block_lines)
                 start_line = current_block_start
                 end_line = current_block_start + index_of_last_line_in_block
-                await sdk.ide.showSuggestion(FileEdit(
-                    filepath=rif.filepath,
-                    range=Range.from_shorthand(
-                        start_line, 0, end_line, 0),
-                    replacement=replacement
-                ))
+
+                if False:
+                    await sdk.ide.showSuggestion(FileEdit(
+                        filepath=rif.filepath,
+                        range=Range.from_shorthand(
+                            start_line, 0, end_line, 0),
+                        replacement=replacement
+                    ))
 
                 # Reset current block / update variables
                 current_line_in_file += 1
diff --git a/extension/package-lock.json b/extension/package-lock.json
index 6e527583..b322acb7 100644
--- a/extension/package-lock.json
+++ b/extension/package-lock.json
@@ -1,12 +1,12 @@
 {
   "name": "continue",
-  "version": "0.0.112",
+  "version": "0.0.113",
   "lockfileVersion": 2,
   "requires": true,
   "packages": {
     "": {
       "name": "continue",
-      "version": "0.0.112",
+      "version": "0.0.113",
       "license": "Apache-2.0",
       "dependencies": {
         "@electron/rebuild": "^3.2.10",
diff --git a/extension/package.json b/extension/package.json
index 413e5b89..09703da4 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.112",
+  "version": "0.0.113",
   "publisher": "Continue",
   "engines": {
     "vscode": "^1.67.0"
@@ -130,12 +130,12 @@
         "key": "shift+ctrl+enter"
       },
       {
-        "command": "continue.acceptAllSuggestions",
+        "command": "continue.acceptDiff",
         "mac": "shift+cmd+enter",
         "key": "shift+ctrl+enter"
       },
       {
-        "command": "continue.rejectAllSuggestions",
+        "command": "continue.rejectDiff",
         "mac": "shift+cmd+backspace",
         "key": "shift+ctrl+backspace"
       }
diff --git a/extension/react-app/src/components/ComboBox.tsx b/extension/react-app/src/components/ComboBox.tsx
index 61c9ab1e..81b148b9 100644
--- a/extension/react-app/src/components/ComboBox.tsx
+++ b/extension/react-app/src/components/ComboBox.tsx
@@ -55,7 +55,7 @@ const MainTextInput = styled.textarea`
   }
 `;
 
-const UlMaxHeight = 200;
+const UlMaxHeight = 400;
 const Ul = styled.ul<{
   hidden: boolean;
   showAbove: boolean;
diff --git a/extension/src/diffs.ts b/extension/src/diffs.ts
index 178b1a9d..1b8888e8 100644
--- a/extension/src/diffs.ts
+++ b/extension/src/diffs.ts
@@ -92,7 +92,14 @@ class DiffManager {
     fs.unlinkSync(diffInfo.newFilepath);
   }
 
-  acceptDiff(newFilepath: string) {
+  acceptDiff(newFilepath?: string) {
+    // If no newFilepath is provided and there is only one in the dictionary, use that
+    if (!newFilepath && this.diffs.size === 1) {
+      newFilepath = Array.from(this.diffs.keys())[0];
+    }
+    if (!newFilepath) {
+      return;
+    }
     // Get the diff info, copy new file to original, then delete from record and close the corresponding editor
     const diffInfo = this.diffs.get(newFilepath);
     if (!diffInfo) {
@@ -105,7 +112,14 @@ class DiffManager {
     this.cleanUpDiff(diffInfo);
   }
 
-  rejectDiff(newFilepath: string) {
+  rejectDiff(newFilepath?: string) {
+    // If no newFilepath is provided and there is only one in the dictionary, use that
+    if (!newFilepath && this.diffs.size === 1) {
+      newFilepath = Array.from(this.diffs.keys())[0];
+    }
+    if (!newFilepath) {
+      return;
+    }
     const diffInfo = this.diffs.get(newFilepath);
     if (!diffInfo) {
       return;
@@ -117,10 +131,10 @@ class DiffManager {
 
 export const diffManager = new DiffManager();
 
-export async function acceptDiffCommand(newFilepath: string) {
+export async function acceptDiffCommand(newFilepath?: string) {
   diffManager.acceptDiff(newFilepath);
 }
 
-export async function rejectDiffCommand(newFilepath: string) {
+export async function rejectDiffCommand(newFilepath?: string) {
   diffManager.rejectDiff(newFilepath);
 }
-- 
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/components/ComboBox.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 1f4878f89549e6c9ccc3483a47b9f3a95c6ee9f4 Mon Sep 17 00:00:00 2001
From: Nate Sesti <sestinj@gmail.com>
Date: Thu, 6 Jul 2023 00:25:41 -0700
Subject: fixing command history and dropdown

---
 extension/package-lock.json                        |  4 +-
 extension/package.json                             |  2 +-
 extension/react-app/src/components/ComboBox.tsx    | 53 +++++++++++++---------
 .../react-app/src/components/StepContainer.tsx     |  2 +-
 extension/react-app/src/tabs/gui.tsx               | 11 ++++-
 5 files changed, 44 insertions(+), 28 deletions(-)

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

diff --git a/extension/package-lock.json b/extension/package-lock.json
index b322acb7..b34d1c61 100644
--- a/extension/package-lock.json
+++ b/extension/package-lock.json
@@ -1,12 +1,12 @@
 {
   "name": "continue",
-  "version": "0.0.113",
+  "version": "0.0.114",
   "lockfileVersion": 2,
   "requires": true,
   "packages": {
     "": {
       "name": "continue",
-      "version": "0.0.113",
+      "version": "0.0.114",
       "license": "Apache-2.0",
       "dependencies": {
         "@electron/rebuild": "^3.2.10",
diff --git a/extension/package.json b/extension/package.json
index 09703da4..4c972e86 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.113",
+  "version": "0.0.114",
   "publisher": "Continue",
   "engines": {
     "vscode": "^1.67.0"
diff --git a/extension/react-app/src/components/ComboBox.tsx b/extension/react-app/src/components/ComboBox.tsx
index 7ee5dc24..af673b42 100644
--- a/extension/react-app/src/components/ComboBox.tsx
+++ b/extension/react-app/src/components/ComboBox.tsx
@@ -79,7 +79,7 @@ const MainTextInput = styled.textarea`
   }
 `;
 
-const UlMaxHeight = 400;
+const UlMaxHeight = 300;
 const Ul = styled.ul<{
   hidden: boolean;
   showAbove: boolean;
@@ -94,13 +94,20 @@ const Ul = styled.ul<{
   background-color: ${secondaryDark};
   color: white;
   max-height: ${UlMaxHeight}px;
-  overflow: scroll;
+  overflow-y: scroll;
+  overflow-x: hidden;
   padding: 0;
   ${({ hidden }) => hidden && "display: none;"}
   border-radius: ${defaultBorderRadius};
-  overflow: hidden;
   border: 0.5px solid gray;
   z-index: 2;
+  // Get rid of scrollbar and its padding
+  scrollbar-width: none;
+  -ms-overflow-style: none;
+  &::-webkit-scrollbar {
+    width: 0px;
+    background: transparent; /* make scrollbar transparent */
+  }
 `;
 
 const Li = styled.li<{
@@ -108,7 +115,7 @@ const Li = styled.li<{
   selected: boolean;
   isLastItem: boolean;
 }>`
-  ${({ highlighted }) => highlighted && "background: #aa0000;"}
+  ${({ highlighted }) => highlighted && "background: #ff000066;"}
   ${({ selected }) => selected && "font-weight: bold;"}
     padding: 0.5rem 0.75rem;
   display: flex;
@@ -272,6 +279,12 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
                 event.key === "Enter" &&
                 (!isOpen || items.length === 0)
               ) {
+                setInputValue("");
+                const value = event.currentTarget.value;
+                if (value !== "") {
+                  setPositionInHistory(history.length + 1);
+                  setHistory([...history, value]);
+                }
                 // Prevent Downshift's default 'Enter' behavior.
                 (event.nativeEvent as any).preventDownshiftDefault = true;
 
@@ -280,33 +293,28 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
                   event.currentTarget.value = `/edit ${event.currentTarget.value}`;
                 }
                 if (props.onEnter) props.onEnter(event);
-                setInputValue("");
-                const value = event.currentTarget.value;
-                if (value !== "") {
-                  setPositionInHistory(history.length + 1);
-                  setHistory([...history, value]);
-                }
               } else if (event.key === "Tab" && items.length > 0) {
                 setInputValue(items[0].name);
                 event.preventDefault();
               } else if (
-                event.key === "ArrowUp" ||
-                (event.key === "ArrowDown" &&
-                  event.currentTarget.value.split("\n").length > 1)
-              ) {
-                (event.nativeEvent as any).preventDownshiftDefault = true;
-              } else if (
-                event.key === "ArrowUp" &&
+                (event.key === "ArrowUp" || event.key === "ArrowDown") &&
                 event.currentTarget.value.split("\n").length > 1
               ) {
+                (event.nativeEvent as any).preventDownshiftDefault = true;
+              } else if (event.key === "ArrowUp") {
+                console.log("OWJFOIJO");
                 if (positionInHistory == 0) return;
+                else if (
+                  positionInHistory == history.length &&
+                  (history.length === 0 ||
+                    history[history.length - 1] !== event.currentTarget.value)
+                ) {
+                  setHistory([...history, event.currentTarget.value]);
+                }
                 setInputValue(history[positionInHistory - 1]);
                 setPositionInHistory((prev) => prev - 1);
-              } else if (
-                event.key === "ArrowDown" &&
-                event.currentTarget.value.split("\n").length > 1
-              ) {
-                if (positionInHistory < history.length - 1) {
+              } else if (event.key === "ArrowDown") {
+                if (positionInHistory < history.length) {
                   setInputValue(history[positionInHistory + 1]);
                 }
                 setPositionInHistory((prev) =>
@@ -327,6 +335,7 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
           {isOpen &&
             items.map((item, index) => (
               <Li
+                style={{ borderTop: index === 0 ? "none" : undefined }}
                 key={`${item.name}${index}`}
                 {...getItemProps({ item, index })}
                 highlighted={highlightedIndex === index}
diff --git a/extension/react-app/src/components/StepContainer.tsx b/extension/react-app/src/components/StepContainer.tsx
index 91d7b8ef..590b1166 100644
--- a/extension/react-app/src/components/StepContainer.tsx
+++ b/extension/react-app/src/components/StepContainer.tsx
@@ -206,7 +206,7 @@ function StepContainer(props: StepContainerProps) {
                   e.stopPropagation();
                   props.onDelete();
                 }}
-                text={props.historyNode.active ? "Stop" : "Delete"}
+                text={props.historyNode.active ? "Stop (⌘⌫)" : "Delete"}
               >
                 {props.historyNode.active ? (
                   <StopCircle size="1.6em" onClick={props.onDelete} />
diff --git a/extension/react-app/src/tabs/gui.tsx b/extension/react-app/src/tabs/gui.tsx
index 3cce30de..ca369547 100644
--- a/extension/react-app/src/tabs/gui.tsx
+++ b/extension/react-app/src/tabs/gui.tsx
@@ -139,9 +139,16 @@ function GUI(props: GUIProps) {
 
   useEffect(() => {
     const listener = (e: any) => {
-      // Cmd + J to toggle fast model
+      // Cmd + i to toggle fast model
       if (e.key === "i" && e.metaKey && e.shiftKey) {
         setUsingFastModel((prev) => !prev);
+        // Cmd + backspace to stop currently running step
+      } else if (
+        e.key === "Backspace" &&
+        e.metaKey &&
+        typeof history?.current_index !== "undefined"
+      ) {
+        client?.deleteAtIndex(history.current_index);
       }
     };
     window.addEventListener("keydown", listener);
@@ -149,7 +156,7 @@ function GUI(props: GUIProps) {
     return () => {
       window.removeEventListener("keydown", listener);
     };
-  }, []);
+  }, [client, history]);
 
   useEffect(() => {
     client?.onStateUpdate((state: FullState) => {
-- 
cgit v1.2.3-70-g09d2


From 7207da47c790aab81f59e777b9d02769b46fb7f4 Mon Sep 17 00:00:00 2001
From: Nate Sesti <sestinj@gmail.com>
Date: Thu, 6 Jul 2023 12:39:17 -0700
Subject: details

---
 continuedev/src/continuedev/core/autopilot.py          | 18 +++++++++++++-----
 continuedev/src/continuedev/core/main.py               |  2 +-
 continuedev/src/continuedev/steps/chat.py              |  2 +-
 continuedev/src/continuedev/steps/core/core.py         |  2 +-
 continuedev/src/continuedev/steps/custom_command.py    |  7 ++++---
 extension/package-lock.json                            |  4 ++--
 extension/package.json                                 |  2 +-
 extension/react-app/src/components/ComboBox.tsx        | 10 ++++------
 extension/react-app/src/components/ContinueButton.tsx  | 12 ++----------
 extension/react-app/src/components/PillButton.tsx      |  4 +++-
 .../react-app/src/components/UserInputContainer.tsx    |  3 ++-
 extension/react-app/src/index.css                      |  1 -
 extension/react-app/src/tabs/gui.tsx                   | 10 +++++++++-
 extension/src/lang-server/codeLens.ts                  |  4 ++--
 14 files changed, 45 insertions(+), 36 deletions(-)

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

diff --git a/continuedev/src/continuedev/core/autopilot.py b/continuedev/src/continuedev/core/autopilot.py
index acdc1f0d..4466a01e 100644
--- a/continuedev/src/continuedev/core/autopilot.py
+++ b/continuedev/src/continuedev/core/autopilot.py
@@ -151,15 +151,23 @@ class Autopilot(ContinueBaseModel):
             self._highlighted_ranges[0].editing = True
 
     async def handle_highlighted_code(self, range_in_files: List[RangeInFileWithContents]):
-        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:
+        if len(self._highlighted_ranges) == 1 and len(range_in_files) <= 1 and (len(range_in_files) == 0 or range_in_files[0].range.start == range_in_files[0].range.end):
             self._highlighted_ranges = []
             await self.update_subscribers()
             return
 
+        # If not toggled to be adding context, only edit or add the first range
+        if not self._adding_highlighted_code and len(self._highlighted_ranges) > 0:
+            if len(range_in_files) == 0:
+                return
+            if range_in_files[0].range.overlaps_with(self._highlighted_ranges[0].range) and range_in_files[0].filepath == self._highlighted_ranges[0].range.filepath:
+                self._highlighted_ranges = [HighlightedRangeContext(
+                    range=range_in_files[0].range, editing=True, pinned=False)]
+                await self.update_subscribers()
+                return
+
         # Filter out rifs from ~/.continue/diffs folder
         range_in_files = [
             rif for rif in range_in_files if not os.path.dirname(rif.filepath) == os.path.expanduser("~/.continue/diffs")]
@@ -391,8 +399,8 @@ class Autopilot(ContinueBaseModel):
             return
 
         # Remove context unless pinned
-        self._highlighted_ranges = [
-            hr for hr in self._highlighted_ranges if hr.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
diff --git a/continuedev/src/continuedev/core/main.py b/continuedev/src/continuedev/core/main.py
index 62cc4936..d8bacb1f 100644
--- a/continuedev/src/continuedev/core/main.py
+++ b/continuedev/src/continuedev/core/main.py
@@ -259,7 +259,7 @@ class Step(ContinueBaseModel):
         if self.description is not None:
             d["description"] = self.description
         else:
-            d["description"] = "`Step in progress...`"
+            d["description"] = "Step in progress..."
         return d
 
     @validator("name", pre=True, always=True)
diff --git a/continuedev/src/continuedev/steps/chat.py b/continuedev/src/continuedev/steps/chat.py
index 8f88244c..d310a498 100644
--- a/continuedev/src/continuedev/steps/chat.py
+++ b/continuedev/src/continuedev/steps/chat.py
@@ -20,7 +20,7 @@ openai.api_key = OPENAI_API_KEY
 
 class SimpleChatStep(Step):
     user_input: str
-    name: str = "Chat"
+    name: str = "Generating Response..."
     manage_own_chat_context: bool = True
     description: str = ""
 
diff --git a/continuedev/src/continuedev/steps/core/core.py b/continuedev/src/continuedev/steps/core/core.py
index cbf0fe5e..5577c49a 100644
--- a/continuedev/src/continuedev/steps/core/core.py
+++ b/continuedev/src/continuedev/steps/core/core.py
@@ -302,7 +302,7 @@ class DefaultModelEditCodeStep(Step):
             completion = "\n".join(lines)
 
             full_prefix_lines = full_file_contents_lines[:rif.range.start.line]
-            full_suffix_lines = full_file_contents_lines[rif.range.end.line + 1:]
+            full_suffix_lines = full_file_contents_lines[rif.range.end.line:]
             new_file_contents = "\n".join(
                 full_prefix_lines) + "\n" + completion + "\n" + "\n".join(full_suffix_lines)
             await sdk.ide.showDiff(rif.filepath, new_file_contents)
diff --git a/continuedev/src/continuedev/steps/custom_command.py b/continuedev/src/continuedev/steps/custom_command.py
index b84e7b35..9d675091 100644
--- a/continuedev/src/continuedev/steps/custom_command.py
+++ b/continuedev/src/continuedev/steps/custom_command.py
@@ -1,16 +1,17 @@
 from ..core.main import Step
 from ..core.sdk import ContinueSDK
-from ..steps.chat import ChatWithFunctions
+from ..steps.chat import ChatWithFunctions, SimpleChatStep
 
 
 class CustomCommandStep(Step):
     name: str
     prompt: str
     user_input: str
-        
+    hide: bool = True
+
     async def describe(self):
         return self.prompt
 
     async def run(self, sdk: ContinueSDK):
         prompt_user_input = f"Task: {self.prompt}. Additional info: {self.user_input}"
-        await sdk.run_step(ChatWithFunctions(user_input=prompt_user_input))
\ No newline at end of file
+        await sdk.run_step(SimpleChatStep(user_input=prompt_user_input))
diff --git a/extension/package-lock.json b/extension/package-lock.json
index b34d1c61..cb11c5a8 100644
--- a/extension/package-lock.json
+++ b/extension/package-lock.json
@@ -1,12 +1,12 @@
 {
   "name": "continue",
-  "version": "0.0.114",
+  "version": "0.0.115",
   "lockfileVersion": 2,
   "requires": true,
   "packages": {
     "": {
       "name": "continue",
-      "version": "0.0.114",
+      "version": "0.0.115",
       "license": "Apache-2.0",
       "dependencies": {
         "@electron/rebuild": "^3.2.10",
diff --git a/extension/package.json b/extension/package.json
index 4c972e86..bbc83e4a 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.114",
+  "version": "0.0.115",
   "publisher": "Continue",
   "engines": {
     "vscode": "^1.67.0"
diff --git a/extension/react-app/src/components/ComboBox.tsx b/extension/react-app/src/components/ComboBox.tsx
index af673b42..b825dc2a 100644
--- a/extension/react-app/src/components/ComboBox.tsx
+++ b/extension/react-app/src/components/ComboBox.tsx
@@ -22,7 +22,7 @@ import {
 import { HighlightedRangeContext } from "../../../schema/FullState";
 
 // #region styled components
-const mainInputFontSize = 16;
+const mainInputFontSize = 13;
 
 const EmptyPillDiv = styled.div`
   padding: 8px;
@@ -64,7 +64,6 @@ const MainTextInput = styled.textarea`
   padding: 8px;
   font-size: ${mainInputFontSize}px;
   font-family: inherit;
-  border: 1px solid transparent;
   border-radius: ${defaultBorderRadius};
   margin: 8px auto;
   height: auto;
@@ -74,8 +73,7 @@ const MainTextInput = styled.textarea`
   z-index: 1;
 
   &:focus {
-    outline: 1px solid #ff000066;
-    border: 1px solid transparent;
+    outline: 1px solid ${lightGray};
   }
 `;
 
@@ -191,7 +189,7 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
   return (
     <>
       <div className="px-2 flex gap-2 items-center flex-wrap mt-2">
-        {highlightedCodeSections.length > 1 && (
+        {/* {highlightedCodeSections.length > 1 && (
           <>
             <HeaderButtonWithText
               text="Clear Context"
@@ -204,7 +202,7 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
               <Trash size="1.6em" />
             </HeaderButtonWithText>
           </>
-        )}
+        )} */}
         {highlightedCodeSections.map((section, idx) => (
           <PillButton
             editing={section.editing}
diff --git a/extension/react-app/src/components/ContinueButton.tsx b/extension/react-app/src/components/ContinueButton.tsx
index 462f2b46..72f6dcd2 100644
--- a/extension/react-app/src/components/ContinueButton.tsx
+++ b/extension/react-app/src/components/ContinueButton.tsx
@@ -10,20 +10,12 @@ let StyledButton = styled(Button)`
   display: grid;
   grid-template-columns: 30px 1fr;
   align-items: center;
-  background: linear-gradient(
-    95.23deg,
-    #be1a55 14.44%,
-    rgba(203, 27, 90, 0.4) 82.21%
-  );
+  background: #be1b55;
 
   &:hover {
     transition-delay: 0.5s;
     transition-property: "background";
-    background: linear-gradient(
-      45deg,
-      #be1a55 14.44%,
-      rgba(203, 27, 90, 0.4) 82.21%
-    );
+    opacity: 0.8;
   }
 `;
 
diff --git a/extension/react-app/src/components/PillButton.tsx b/extension/react-app/src/components/PillButton.tsx
index a384832e..31d98c0f 100644
--- a/extension/react-app/src/components/PillButton.tsx
+++ b/extension/react-app/src/components/PillButton.tsx
@@ -127,7 +127,9 @@ const PillButton = (props: PillButtonProps) => {
         {props.title}
       </Button>
       <StyledTooltip id={`edit-${props.index}`}>
-        {props.editing ? "Editing this range" : "Edit this range"}
+        {props.editing
+          ? "Editing this range (with rest of file as context)"
+          : "Edit this range"}
       </StyledTooltip>
       <StyledTooltip id={`delete-${props.index}`}>Delete</StyledTooltip>
     </>
diff --git a/extension/react-app/src/components/UserInputContainer.tsx b/extension/react-app/src/components/UserInputContainer.tsx
index f51f0cb5..0ff3e74f 100644
--- a/extension/react-app/src/components/UserInputContainer.tsx
+++ b/extension/react-app/src/components/UserInputContainer.tsx
@@ -1,7 +1,7 @@
 import React from "react";
 import ReactMarkdown from "react-markdown";
 import styled from "styled-components";
-import { buttonColor, secondaryDark } from ".";
+import { buttonColor, secondaryDark, vscBackground } from ".";
 import HeaderButtonWithText from "./HeaderButtonWithText";
 import { Play, XMark } from "@styled-icons/heroicons-outline";
 import { RootStore } from "../redux/store";
@@ -22,6 +22,7 @@ const StyledDiv = styled.div`
   font-size: 13px;
   display: flex;
   align-items: center;
+  border-bottom: 1px solid ${vscBackground};
 `;
 
 const UserInputContainer = (props: UserInputContainerProps) => {
diff --git a/extension/react-app/src/index.css b/extension/react-app/src/index.css
index 682551f8..6e33c89c 100644
--- a/extension/react-app/src/index.css
+++ b/extension/react-app/src/index.css
@@ -21,7 +21,6 @@ body,
 body {
   padding: 0;
   color: white;
-  font-family: "Mona Sans", "Arial", sans-serif;
   padding: 0px;
   margin: 0px;
   height: 100%;
diff --git a/extension/react-app/src/tabs/gui.tsx b/extension/react-app/src/tabs/gui.tsx
index ca369547..c8a42d9a 100644
--- a/extension/react-app/src/tabs/gui.tsx
+++ b/extension/react-app/src/tabs/gui.tsx
@@ -165,7 +165,15 @@ function GUI(props: GUIProps) {
       const shouldScrollToBottom =
         topGuiDivRef.current &&
         topGuiDivRef.current?.offsetHeight - window.scrollY < 100;
-      setWaitingForSteps(state.active);
+
+      const waitingForSteps =
+        state.active &&
+        state.history.current_index < state.history.timeline.length &&
+        state.history.timeline[
+          state.history.current_index
+        ].step.description?.trim() === "";
+
+      setWaitingForSteps(waitingForSteps);
       setHistory(state.history);
       setHighlightedRanges(state.highlighted_ranges);
       setUserInputQueue(state.user_input_queue);
diff --git a/extension/src/lang-server/codeLens.ts b/extension/src/lang-server/codeLens.ts
index 381a0084..79126eaa 100644
--- a/extension/src/lang-server/codeLens.ts
+++ b/extension/src/lang-server/codeLens.ts
@@ -72,12 +72,12 @@ class DiffViewerCodeLensProvider implements vscode.CodeLensProvider {
       const range = new vscode.Range(0, 0, 1, 0);
       codeLenses.push(
         new vscode.CodeLens(range, {
-          title: "Accept ✅",
+          title: "Accept ✅ (⌘⇧↩)",
           command: "continue.acceptDiff",
           arguments: [document.uri.fsPath],
         }),
         new vscode.CodeLens(range, {
-          title: "Reject ❌",
+          title: "Reject ❌ (⌘⇧⌫)",
           command: "continue.rejectDiff",
           arguments: [document.uri.fsPath],
         })
-- 
cgit v1.2.3-70-g09d2


From ee37fd0c5582bbe4b2163faa19846d980b5aa6ef Mon Sep 17 00:00:00 2001
From: Nate Sesti <sestinj@gmail.com>
Date: Thu, 6 Jul 2023 12:46:30 -0700
Subject: fix parroting bug

---
 continuedev/src/continuedev/steps/chat.py       | 9 +--------
 extension/react-app/src/components/ComboBox.tsx | 2 ++
 2 files changed, 3 insertions(+), 8 deletions(-)

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

diff --git a/continuedev/src/continuedev/steps/chat.py b/continuedev/src/continuedev/steps/chat.py
index d310a498..c26f8ff9 100644
--- a/continuedev/src/continuedev/steps/chat.py
+++ b/continuedev/src/continuedev/steps/chat.py
@@ -30,15 +30,8 @@ class SimpleChatStep(Step):
             self.description = ""
         await sdk.update_ui()
 
-        messages = await sdk.get_chat_context()
-        messages.append(ChatMessage(
-            role="user",
-            content=self.user_input,
-            summary=self.user_input
-        ))
-
         completion = ""
-        async for chunk in sdk.models.gpt4.stream_chat(messages):
+        async for chunk in sdk.models.gpt4.stream_chat(await sdk.get_chat_context()):
             if sdk.current_step_was_deleted():
                 return
 
diff --git a/extension/react-app/src/components/ComboBox.tsx b/extension/react-app/src/components/ComboBox.tsx
index b825dc2a..55496fb9 100644
--- a/extension/react-app/src/components/ComboBox.tsx
+++ b/extension/react-app/src/components/ComboBox.tsx
@@ -71,9 +71,11 @@ const MainTextInput = styled.textarea`
   background-color: ${secondaryDark};
   color: white;
   z-index: 1;
+  border: 1px solid transparent;
 
   &:focus {
     outline: 1px solid ${lightGray};
+    border: 1px solid transparent;
   }
 `;
 
-- 
cgit v1.2.3-70-g09d2


From 58317604298800ccea238dd34d5ac6537ede4529 Mon Sep 17 00:00:00 2001
From: Nate Sesti <sestinj@gmail.com>
Date: Thu, 6 Jul 2023 20:07:45 -0700
Subject: details

---
 continuedev/src/continuedev/core/autopilot.py      |  2 +-
 continuedev/src/continuedev/server/ide.py          |  7 +++
 continuedev/src/continuedev/steps/core/core.py     | 22 ++++----
 extension/package-lock.json                        |  4 +-
 extension/package.json                             |  2 +-
 extension/react-app/src/components/ComboBox.tsx    | 62 +++++++++++++---------
 .../react-app/src/components/ContinueButton.tsx    |  3 +-
 .../react-app/src/components/StepContainer.tsx     |  3 ++
 extension/react-app/src/tabs/gui.tsx               | 26 +--------
 extension/src/continueIdeClient.ts                 |  4 ++
 extension/src/diffs.ts                             |  3 ++
 11 files changed, 73 insertions(+), 65 deletions(-)

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

diff --git a/continuedev/src/continuedev/core/autopilot.py b/continuedev/src/continuedev/core/autopilot.py
index 6e4326f0..02fd61de 100644
--- a/continuedev/src/continuedev/core/autopilot.py
+++ b/continuedev/src/continuedev/core/autopilot.py
@@ -153,7 +153,7 @@ class Autopilot(ContinueBaseModel):
     async def handle_highlighted_code(self, range_in_files: List[RangeInFileWithContents]):
 
         # If un-highlighting, then remove the range
-        if len(self._highlighted_ranges) == 1 and len(range_in_files) <= 1 and (len(range_in_files) == 0 or range_in_files[0].range.start == range_in_files[0].range.end):
+        if len(self._highlighted_ranges) == 1 and len(range_in_files) <= 1 and (len(range_in_files) == 0 or range_in_files[0].range.start == range_in_files[0].range.end) and not self._adding_highlighted_code:
             self._highlighted_ranges = []
             await self.update_subscribers()
             return
diff --git a/continuedev/src/continuedev/server/ide.py b/continuedev/src/continuedev/server/ide.py
index ea355d3c..d16bd449 100644
--- a/continuedev/src/continuedev/server/ide.py
+++ b/continuedev/src/continuedev/server/ide.py
@@ -148,6 +148,8 @@ class IdeProtocolServer(AbstractIdeProtocolServer):
             self.onCommandOutput(output)
         elif message_type == "acceptRejectSuggestion":
             self.onAcceptRejectSuggestion(data["accepted"])
+        elif message_type == "acceptRejectDiff":
+            self.onAcceptRejectDiff(data["accepted"])
         elif message_type in ["highlightedCode", "openFiles", "readFile", "editFile", "workspaceDirectory", "getUserSecret", "runCommand", "uniqueId"]:
             self.sub_queue.post(message_type, data)
         else:
@@ -219,6 +221,11 @@ class IdeProtocolServer(AbstractIdeProtocolServer):
             "accepted": accepted
         })
 
+    def onAcceptRejectDiff(self, accepted: bool):
+        capture_event(self.unique_id, "accept_reject_diff", {
+            "accepted": accepted
+        })
+
     def onFileSystemUpdate(self, update: FileSystemEdit):
         # Access to Autopilot (so SessionManager)
         pass
diff --git a/continuedev/src/continuedev/steps/core/core.py b/continuedev/src/continuedev/steps/core/core.py
index 5577c49a..f22297ae 100644
--- a/continuedev/src/continuedev/steps/core/core.py
+++ b/continuedev/src/continuedev/steps/core/core.py
@@ -450,40 +450,40 @@ class DefaultModelEditCodeStep(Step):
                 chunk_lines.pop()  # because this will be an empty string
             else:
                 unfinished_line = chunk_lines.pop()
-            lines.extend(map(lambda l: common_whitespace + l, chunk_lines))
-
-            if True:
-                await sendDiffUpdate(lines + [common_whitespace + unfinished_line], sdk)
 
             # Deal with newly accumulated lines
-            for line in chunk_lines:
+            for i in range(len(chunk_lines)):
                 # Trailing whitespace doesn't matter
-                line = line.rstrip()
+                chunk_lines[i] = chunk_lines[i].rstrip()
+                chunk_lines[i] = common_whitespace + chunk_lines[i]
 
                 # Lines that should signify the end of generation
-                if self.is_end_line(line):
+                if self.is_end_line(chunk_lines[i]):
                     break
                 # Lines that should be ignored, like the <> tags
-                elif self.line_to_be_ignored(line, completion_lines_covered == 0):
+                elif self.line_to_be_ignored(chunk_lines[i], completion_lines_covered == 0):
                     continue
                 # Check if we are currently just copying the prefix
-                elif (lines_of_prefix_copied > 0 or completion_lines_covered == 0) and lines_of_prefix_copied < len(file_prefix.splitlines()) and line == full_file_contents_lines[lines_of_prefix_copied]:
+                elif (lines_of_prefix_copied > 0 or completion_lines_covered == 0) and lines_of_prefix_copied < len(file_prefix.splitlines()) and chunk_lines[i] == full_file_contents_lines[lines_of_prefix_copied]:
                     # This is a sketchy way of stopping it from repeating the file_prefix. Is a bug if output happens to have a matching line
                     lines_of_prefix_copied += 1
                     continue
                 # Because really short lines might be expected to be repeated, this is only a !heuristic!
                 # Stop when it starts copying the file_suffix
-                elif line.strip() == line_below_highlighted_range.strip() and len(line.strip()) > 4 and not (len(original_lines_below_previous_blocks) > 0 and line.strip() == original_lines_below_previous_blocks[0].strip()):
+                elif chunk_lines[i].strip() == line_below_highlighted_range.strip() and len(chunk_lines[i].strip()) > 4 and not (len(original_lines_below_previous_blocks) > 0 and chunk_lines[i].strip() == original_lines_below_previous_blocks[0].strip()):
                     repeating_file_suffix = True
                     break
 
                 # If none of the above, insert the line!
                 if False:
-                    await handle_generated_line(line)
+                    await handle_generated_line(chunk_lines[i])
 
+                lines.append(chunk_lines[i])
                 completion_lines_covered += 1
                 current_line_in_file += 1
 
+            await sendDiffUpdate(lines + [common_whitespace + unfinished_line], sdk)
+
         # Add the unfinished line
         if unfinished_line != "" and not self.line_to_be_ignored(unfinished_line, completion_lines_covered == 0) and not self.is_end_line(unfinished_line):
             unfinished_line = common_whitespace + unfinished_line
diff --git a/extension/package-lock.json b/extension/package-lock.json
index cb11c5a8..915c228e 100644
--- a/extension/package-lock.json
+++ b/extension/package-lock.json
@@ -1,12 +1,12 @@
 {
   "name": "continue",
-  "version": "0.0.115",
+  "version": "0.0.116",
   "lockfileVersion": 2,
   "requires": true,
   "packages": {
     "": {
       "name": "continue",
-      "version": "0.0.115",
+      "version": "0.0.116",
       "license": "Apache-2.0",
       "dependencies": {
         "@electron/rebuild": "^3.2.10",
diff --git a/extension/package.json b/extension/package.json
index bbc83e4a..30690397 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.115",
+  "version": "0.0.116",
   "publisher": "Continue",
   "engines": {
     "vscode": "^1.67.0"
diff --git a/extension/react-app/src/components/ComboBox.tsx b/extension/react-app/src/components/ComboBox.tsx
index 55496fb9..4dab8bcd 100644
--- a/extension/react-app/src/components/ComboBox.tsx
+++ b/extension/react-app/src/components/ComboBox.tsx
@@ -1,4 +1,9 @@
-import React, { useCallback, useEffect, useState } from "react";
+import React, {
+  useCallback,
+  useEffect,
+  useImperativeHandle,
+  useState,
+} from "react";
 import { useCombobox } from "downshift";
 import styled from "styled-components";
 import {
@@ -151,22 +156,13 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
   const [highlightedCodeSections, setHighlightedCodeSections] = React.useState(
     props.highlightedCodeSections || []
   );
+  const inputRef = React.useRef<HTMLInputElement>(null);
 
   useEffect(() => {
     setHighlightedCodeSections(props.highlightedCodeSections || []);
   }, [props.highlightedCodeSections]);
 
-  const {
-    isOpen,
-    getToggleButtonProps,
-    getLabelProps,
-    getMenuProps,
-    getInputProps,
-    highlightedIndex,
-    getItemProps,
-    selectedItem,
-    setInputValue,
-  } = useCombobox({
+  const { getInputProps, ...downshiftProps } = useCombobox({
     onInputValueChange({ inputValue }) {
       if (!inputValue) return;
       props.onInputValueChange(inputValue);
@@ -182,6 +178,24 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
     },
   });
 
+  useImperativeHandle(ref, () => downshiftProps, [downshiftProps]);
+
+  useEffect(() => {
+    if (!inputRef.current) {
+      return;
+    }
+    inputRef.current.focus();
+    const handler = (event: any) => {
+      if (event.data.type === "focusContinueInput") {
+        inputRef.current!.focus();
+      }
+    };
+    window.addEventListener("message", handler);
+    return () => {
+      window.removeEventListener("message", handler);
+    };
+  }, [inputRef.current]);
+
   const divRef = React.useRef<HTMLDivElement>(null);
   const ulRef = React.useRef<HTMLUListElement>(null);
   const showAbove = () => {
@@ -255,7 +269,7 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
             </HeaderButtonWithText>
           ))}
       </div>
-      <div className="flex px-2" ref={divRef} hidden={!isOpen}>
+      <div className="flex px-2" ref={divRef} hidden={!downshiftProps.isOpen}>
         <MainTextInput
           disabled={props.disabled}
           placeholder="Ask a question, give instructions, or type '/' to see slash commands"
@@ -277,9 +291,9 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
                 (event.nativeEvent as any).preventDownshiftDefault = true;
               } else if (
                 event.key === "Enter" &&
-                (!isOpen || items.length === 0)
+                (!downshiftProps.isOpen || items.length === 0)
               ) {
-                setInputValue("");
+                downshiftProps.setInputValue("");
                 const value = event.currentTarget.value;
                 if (value !== "") {
                   setPositionInHistory(history.length + 1);
@@ -294,7 +308,7 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
                 }
                 if (props.onEnter) props.onEnter(event);
               } else if (event.key === "Tab" && items.length > 0) {
-                setInputValue(items[0].name);
+                downshiftProps.setInputValue(items[0].name);
                 event.preventDefault();
               } else if (
                 (event.key === "ArrowUp" || event.key === "ArrowDown") &&
@@ -311,35 +325,35 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
                 ) {
                   setHistory([...history, event.currentTarget.value]);
                 }
-                setInputValue(history[positionInHistory - 1]);
+                downshiftProps.setInputValue(history[positionInHistory - 1]);
                 setPositionInHistory((prev) => prev - 1);
               } else if (event.key === "ArrowDown") {
                 if (positionInHistory < history.length) {
-                  setInputValue(history[positionInHistory + 1]);
+                  downshiftProps.setInputValue(history[positionInHistory + 1]);
                 }
                 setPositionInHistory((prev) =>
                   Math.min(prev + 1, history.length)
                 );
               }
             },
-            ref: ref as any,
+            ref: inputRef,
           })}
         />
         <Ul
-          {...getMenuProps({
+          {...downshiftProps.getMenuProps({
             ref: ulRef,
           })}
           showAbove={showAbove()}
           ulHeightPixels={ulRef.current?.getBoundingClientRect().height || 0}
         >
-          {isOpen &&
+          {downshiftProps.isOpen &&
             items.map((item, index) => (
               <Li
                 style={{ borderTop: index === 0 ? "none" : undefined }}
                 key={`${item.name}${index}`}
-                {...getItemProps({ item, index })}
-                highlighted={highlightedIndex === index}
-                selected={selectedItem === item}
+                {...downshiftProps.getItemProps({ item, index })}
+                highlighted={downshiftProps.highlightedIndex === index}
+                selected={downshiftProps.selectedItem === item}
               >
                 <span>
                   {item.name}: {item.description}
diff --git a/extension/react-app/src/components/ContinueButton.tsx b/extension/react-app/src/components/ContinueButton.tsx
index 72f6dcd2..d7739b20 100644
--- a/extension/react-app/src/components/ContinueButton.tsx
+++ b/extension/react-app/src/components/ContinueButton.tsx
@@ -13,9 +13,8 @@ let StyledButton = styled(Button)`
   background: #be1b55;
 
   &:hover {
-    transition-delay: 0.5s;
     transition-property: "background";
-    opacity: 0.8;
+    opacity: 0.7;
   }
 `;
 
diff --git a/extension/react-app/src/components/StepContainer.tsx b/extension/react-app/src/components/StepContainer.tsx
index 590b1166..d480c565 100644
--- a/extension/react-app/src/components/StepContainer.tsx
+++ b/extension/react-app/src/components/StepContainer.tsx
@@ -260,6 +260,9 @@ function StepContainer(props: StepContainerProps) {
                 code: ({ node, ...props }) => {
                   return <StyledCode children={props.children[0] as any} />;
                 },
+                ul: ({ node, ...props }) => {
+                  return <ul className="ml-0" {...props} />;
+                },
               }}
             >
               {props.historyNode.step.description as any}
diff --git a/extension/react-app/src/tabs/gui.tsx b/extension/react-app/src/tabs/gui.tsx
index c8a42d9a..1ea70dd2 100644
--- a/extension/react-app/src/tabs/gui.tsx
+++ b/extension/react-app/src/tabs/gui.tsx
@@ -217,25 +217,10 @@ function GUI(props: GUIProps) {
     [client]
   );
 
-  useEffect(() => {
-    if (mainTextInputRef.current) {
-      mainTextInputRef.current.focus();
-      let handler = (event: any) => {
-        if (event.data.type === "focusContinueInput") {
-          mainTextInputRef.current?.focus();
-        }
-      };
-      window.addEventListener("message", handler);
-      return () => {
-        window.removeEventListener("message", handler);
-      };
-    }
-  }, [mainTextInputRef]);
-
   const onMainTextInput = () => {
     if (mainTextInputRef.current) {
-      let input = mainTextInputRef.current.value;
-      mainTextInputRef.current.value = "";
+      const input = (mainTextInputRef.current as any).inputValue;
+      (mainTextInputRef.current as any).setInputValue("");
       if (!client) return;
 
       setWaitingForSteps(true);
@@ -266,13 +251,6 @@ function GUI(props: GUIProps) {
       setUserInputQueue((queue) => {
         return [...queue, input];
       });
-
-      // Delete all context items unless locked
-      if (!pinned) {
-        client?.deleteContextAtIndices(
-          highlightedRanges.map((_, index) => index)
-        );
-      }
     }
   };
 
diff --git a/extension/src/continueIdeClient.ts b/extension/src/continueIdeClient.ts
index e6966f41..3615ab92 100644
--- a/extension/src/continueIdeClient.ts
+++ b/extension/src/continueIdeClient.ts
@@ -423,6 +423,10 @@ class IdeProtocolClient {
   sendAcceptRejectSuggestion(accepted: boolean) {
     this.messenger?.send("acceptRejectSuggestion", { accepted });
   }
+
+  sendAcceptRejectDiff(accepted: boolean) {
+    this.messenger?.send("acceptRejectDiff", { accepted });
+  }
 }
 
 export default IdeProtocolClient;
diff --git a/extension/src/diffs.ts b/extension/src/diffs.ts
index 1b8888e8..4fce744c 100644
--- a/extension/src/diffs.ts
+++ b/extension/src/diffs.ts
@@ -2,6 +2,7 @@ import * as os from "os";
 import * as path from "path";
 import * as fs from "fs";
 import * as vscode from "vscode";
+import { ideProtocolClient } from "./activation/activate";
 
 interface DiffInfo {
   originalFilepath: string;
@@ -133,8 +134,10 @@ export const diffManager = new DiffManager();
 
 export async function acceptDiffCommand(newFilepath?: string) {
   diffManager.acceptDiff(newFilepath);
+  ideProtocolClient.sendAcceptRejectDiff(true);
 }
 
 export async function rejectDiffCommand(newFilepath?: string) {
   diffManager.rejectDiff(newFilepath);
+  ideProtocolClient.sendAcceptRejectDiff(false);
 }
-- 
cgit v1.2.3-70-g09d2


From 19b38863c21656526e0729776682430e0fa277da Mon Sep 17 00:00:00 2001
From: Nate Sesti <sestinj@gmail.com>
Date: Thu, 6 Jul 2023 23:10:18 -0700
Subject: fix: :bug: fix command enter, stop streaming on reject

---
 continuedev/src/continuedev/server/ide.py       |  2 +-
 extension/package-lock.json                     |  4 ++--
 extension/package.json                          |  2 +-
 extension/react-app/src/components/ComboBox.tsx |  7 +------
 extension/react-app/src/tabs/gui.tsx            | 10 +++++++---
 5 files changed, 12 insertions(+), 13 deletions(-)

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

diff --git a/continuedev/src/continuedev/server/ide.py b/continuedev/src/continuedev/server/ide.py
index 61e7ca78..e4a6266a 100644
--- a/continuedev/src/continuedev/server/ide.py
+++ b/continuedev/src/continuedev/server/ide.py
@@ -250,7 +250,7 @@ class IdeProtocolServer(AbstractIdeProtocolServer):
 
     def onDeleteAtIndex(self, index: int):
         for _, session in self.session_manager.sessions.items():
-            session.autopilot.delete_at_index(index)
+            asyncio.create_task(session.autopilot.delete_at_index(index))
 
     def onCommandOutput(self, output: str):
         # Send the output to ALL autopilots.
diff --git a/extension/package-lock.json b/extension/package-lock.json
index 71525620..9d560872 100644
--- a/extension/package-lock.json
+++ b/extension/package-lock.json
@@ -1,12 +1,12 @@
 {
   "name": "continue",
-  "version": "0.0.120",
+  "version": "0.0.121",
   "lockfileVersion": 2,
   "requires": true,
   "packages": {
     "": {
       "name": "continue",
-      "version": "0.0.120",
+      "version": "0.0.121",
       "license": "Apache-2.0",
       "dependencies": {
         "@electron/rebuild": "^3.2.10",
diff --git a/extension/package.json b/extension/package.json
index 7475a56d..cd5c1697 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.120",
+  "version": "0.0.121",
   "publisher": "Continue",
   "engines": {
     "vscode": "^1.67.0"
diff --git a/extension/react-app/src/components/ComboBox.tsx b/extension/react-app/src/components/ComboBox.tsx
index 4dab8bcd..e6632360 100644
--- a/extension/react-app/src/components/ComboBox.tsx
+++ b/extension/react-app/src/components/ComboBox.tsx
@@ -293,8 +293,7 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
                 event.key === "Enter" &&
                 (!downshiftProps.isOpen || items.length === 0)
               ) {
-                downshiftProps.setInputValue("");
-                const value = event.currentTarget.value;
+                const value = downshiftProps.inputValue;
                 if (value !== "") {
                   setPositionInHistory(history.length + 1);
                   setHistory([...history, value]);
@@ -302,10 +301,6 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
                 // Prevent Downshift's default 'Enter' behavior.
                 (event.nativeEvent as any).preventDownshiftDefault = true;
 
-                // cmd+enter to /edit
-                if (event.metaKey) {
-                  event.currentTarget.value = `/edit ${event.currentTarget.value}`;
-                }
                 if (props.onEnter) props.onEnter(event);
               } else if (event.key === "Tab" && items.length > 0) {
                 downshiftProps.setInputValue(items[0].name);
diff --git a/extension/react-app/src/tabs/gui.tsx b/extension/react-app/src/tabs/gui.tsx
index 1ea70dd2..e1ecec9e 100644
--- a/extension/react-app/src/tabs/gui.tsx
+++ b/extension/react-app/src/tabs/gui.tsx
@@ -217,9 +217,13 @@ function GUI(props: GUIProps) {
     [client]
   );
 
-  const onMainTextInput = () => {
+  const onMainTextInput = (event?: any) => {
     if (mainTextInputRef.current) {
-      const input = (mainTextInputRef.current as any).inputValue;
+      let input = (mainTextInputRef.current as any).inputValue;
+      // cmd+enter to /edit
+      if (event?.metaKey) {
+        input = `/edit ${input}`;
+      }
       (mainTextInputRef.current as any).setInputValue("");
       if (!client) return;
 
@@ -352,7 +356,7 @@ function GUI(props: GUIProps) {
           // }
           ref={mainTextInputRef}
           onEnter={(e) => {
-            onMainTextInput();
+            onMainTextInput(e);
             e.stopPropagation();
             e.preventDefault();
           }}
-- 
cgit v1.2.3-70-g09d2


From 5709c9ae003ededb520ee641cae8c8570d4c93af Mon Sep 17 00:00:00 2001
From: Nate Sesti <sestinj@gmail.com>
Date: Sun, 9 Jul 2023 14:12:36 -0700
Subject: sdk.get_code_context

---
 continuedev/src/continuedev/core/autopilot.py   |  6 ++--
 continuedev/src/continuedev/core/main.py        |  1 +
 continuedev/src/continuedev/core/sdk.py         |  7 ++++-
 continuedev/src/continuedev/steps/main.py       | 38 +++++++++++--------------
 extension/react-app/src/components/ComboBox.tsx |  6 ++--
 extension/schema/FullState.d.ts                 |  2 ++
 schema/json/FullState.json                      |  7 ++++-
 7 files changed, 36 insertions(+), 31 deletions(-)

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

diff --git a/continuedev/src/continuedev/core/autopilot.py b/continuedev/src/continuedev/core/autopilot.py
index b583d682..5c3baafd 100644
--- a/continuedev/src/continuedev/core/autopilot.py
+++ b/continuedev/src/continuedev/core/autopilot.py
@@ -157,8 +157,6 @@ class Autopilot(ContinueBaseModel):
 
         # Make sure all filepaths are relative to workspace
         workspace_path = self.continue_sdk.ide.workspace_directory
-        for rif in range_in_files:
-            rif.filepath = os.path.basename(rif.filepath)
 
         # If not adding highlighted code
         if not self._adding_highlighted_code:
@@ -170,7 +168,7 @@ class Autopilot(ContinueBaseModel):
                 # Otherwise, replace the current range with the new one
                 # This is the first range to be highlighted
                 self._highlighted_ranges = [HighlightedRangeContext(
-                    range=range_in_files[0], editing=True, pinned=False)]
+                    range=range_in_files[0], editing=True, pinned=False, display_name=os.path.basename(range_in_files[0].filepath))]
                 await self.update_subscribers()
             return
 
@@ -193,7 +191,7 @@ class Autopilot(ContinueBaseModel):
                 new_ranges.append(rif)
 
         self._highlighted_ranges = new_ranges + [HighlightedRangeContext(
-            range=rif, editing=False, pinned=False
+            range=rif, editing=False, pinned=False, display_name=os.path.basename(rif.filepath)
         ) for rif in range_in_files]
 
         self._make_sure_is_editing_range()
diff --git a/continuedev/src/continuedev/core/main.py b/continuedev/src/continuedev/core/main.py
index 4ea17f20..88690c83 100644
--- a/continuedev/src/continuedev/core/main.py
+++ b/continuedev/src/continuedev/core/main.py
@@ -205,6 +205,7 @@ class HighlightedRangeContext(ContinueBaseModel):
     range: RangeInFileWithContents
     editing: bool
     pinned: bool
+    display_name: str
 
 
 class FullState(ContinueBaseModel):
diff --git a/continuedev/src/continuedev/core/sdk.py b/continuedev/src/continuedev/core/sdk.py
index ed670799..8649cd58 100644
--- a/continuedev/src/continuedev/core/sdk.py
+++ b/continuedev/src/continuedev/core/sdk.py
@@ -13,7 +13,7 @@ from ..libs.llm.hf_inference_api import HuggingFaceInferenceAPI
 from ..libs.llm.openai import OpenAI
 from .observation import Observation
 from ..server.ide_protocol import AbstractIdeProtocolServer
-from .main import Context, ContinueCustomException, History, Step, ChatMessage, ChatMessageRole
+from .main import Context, ContinueCustomException, HighlightedRangeContext, History, Step, ChatMessage, ChatMessageRole
 from ..steps.core.core import *
 from ..libs.llm.proxy_server import ProxyServer
 
@@ -178,6 +178,11 @@ class ContinueSDK(AbstractContinueSDK):
         else:
             return load_global_config()
 
+    def get_code_context(self, only_editing: bool = False) -> List[RangeInFileWithContents]:
+        context = list(filter(lambda x: x.editing, self.__autopilot._highlighted_ranges)
+                       ) if only_editing else self.__autopilot._highlighted_ranges
+        return [c.range for c in context]
+
     def update_default_model(self, model: str):
         config = self.config
         config.default_model = model
diff --git a/continuedev/src/continuedev/steps/main.py b/continuedev/src/continuedev/steps/main.py
index 5ccffbfe..0a20ddd7 100644
--- a/continuedev/src/continuedev/steps/main.py
+++ b/continuedev/src/continuedev/steps/main.py
@@ -97,7 +97,7 @@ class FasterEditHighlightedCodeStep(Step):
         return "Editing highlighted code"
 
     async def run(self, sdk: ContinueSDK) -> Coroutine[Observation, None, None]:
-        range_in_files = await sdk.ide.getHighlightedCode()
+        range_in_files = await sdk.get_code_context(only_editing=True)
         if len(range_in_files) == 0:
             # Get the full contents of all open files
             files = await sdk.ide.getOpenFiles()
@@ -105,21 +105,16 @@ class FasterEditHighlightedCodeStep(Step):
             for file in files:
                 contents[file] = await sdk.ide.readFile(file)
 
-            range_in_files = [RangeInFile.from_entire_file(
+            range_in_files = [RangeInFileWithContents.from_entire_file(
                 filepath, content) for filepath, content in contents.items()]
 
-        rif_with_contents = []
-        for range_in_file in range_in_files:
-            file_contents = await sdk.ide.readRangeInFile(range_in_file)
-            rif_with_contents.append(
-                RangeInFileWithContents.from_range_in_file(range_in_file, file_contents))
-        enc_dec = MarkdownStyleEncoderDecoder(rif_with_contents)
+        enc_dec = MarkdownStyleEncoderDecoder(range_in_files)
         code_string = enc_dec.encode()
         prompt = self._prompt.format(
             code=code_string, user_input=self.user_input)
 
         rif_dict = {}
-        for rif in rif_with_contents:
+        for rif in range_in_files:
             rif_dict[rif.filepath] = rif.contents
 
         completion = await sdk.models.gpt35.complete(prompt)
@@ -193,7 +188,7 @@ class StarCoderEditHighlightedCodeStep(Step):
         return await models.gpt35.complete(f"{self._prompt_and_completion}\n\nPlease give brief a description of the changes made above using markdown bullet points:")
 
     async def run(self, sdk: ContinueSDK) -> Coroutine[Observation, None, None]:
-        range_in_files = await sdk.ide.getHighlightedCode()
+        range_in_files = await sdk.get_code_context(only_editing=True)
         found_highlighted_code = len(range_in_files) > 0
         if not found_highlighted_code:
             # Get the full contents of all open files
@@ -202,20 +197,14 @@ class StarCoderEditHighlightedCodeStep(Step):
             for file in files:
                 contents[file] = await sdk.ide.readFile(file)
 
-            range_in_files = [RangeInFile.from_entire_file(
+            range_in_files = [RangeInFileWithContents.from_entire_file(
                 filepath, content) for filepath, content in contents.items()]
 
-        rif_with_contents = []
-        for range_in_file in range_in_files:
-            file_contents = await sdk.ide.readRangeInFile(range_in_file)
-            rif_with_contents.append(
-                RangeInFileWithContents.from_range_in_file(range_in_file, file_contents))
-
         rif_dict = {}
-        for rif in rif_with_contents:
+        for rif in range_in_files:
             rif_dict[rif.filepath] = rif.contents
 
-        for rif in rif_with_contents:
+        for rif in range_in_files:
             prompt = self._prompt.format(
                 code=rif.contents, user_request=self.user_input)
 
@@ -255,7 +244,7 @@ class EditHighlightedCodeStep(Step):
         return "Editing code"
 
     async def run(self, sdk: ContinueSDK) -> Coroutine[Observation, None, None]:
-        range_in_files = await sdk.ide.getHighlightedCode()
+        range_in_files = sdk.get_code_context(only_editing=True)
         if len(range_in_files) == 0:
             # Get the full contents of all open files
             files = await sdk.ide.getOpenFiles()
@@ -263,7 +252,7 @@ class EditHighlightedCodeStep(Step):
             for file in files:
                 contents[file] = await sdk.ide.readFile(file)
 
-            range_in_files = [RangeInFile.from_entire_file(
+            range_in_files = [RangeInFileWithContents.from_entire_file(
                 filepath, content) for filepath, content in contents.items()]
 
         # If still no highlighted code, create a new file and edit there
@@ -271,7 +260,12 @@ class EditHighlightedCodeStep(Step):
             # Create a new file
             new_file_path = "new_file.txt"
             await sdk.add_file(new_file_path, "")
-            range_in_files = [RangeInFile.from_entire_file(new_file_path, "")]
+            range_in_files = [
+                RangeInFileWithContents.from_entire_file(new_file_path, "")]
+
+        range_in_files = list(map(lambda x: RangeInFile(
+            filepath=x.filepath, range=x.range
+        ), range_in_files))
 
         await sdk.run_step(DefaultModelEditCodeStep(user_input=self.user_input, range_in_files=range_in_files))
 
diff --git a/extension/react-app/src/components/ComboBox.tsx b/extension/react-app/src/components/ComboBox.tsx
index e6632360..801c3a03 100644
--- a/extension/react-app/src/components/ComboBox.tsx
+++ b/extension/react-app/src/components/ComboBox.tsx
@@ -224,8 +224,8 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
             editing={section.editing}
             pinned={section.pinned}
             index={idx}
-            key={`${section.filepath}${idx}`}
-            title={`${section.range.filepath} (${
+            key={`${section.display_name}${idx}`}
+            title={`${section.display_name} (${
               section.range.range.start.line + 1
             }-${section.range.range.end.line + 1})`}
             onDelete={() => {
@@ -372,7 +372,7 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
       >
         {highlightedCodeSections.map((section, idx) => (
           <>
-            <p>{section.range.filepath}</p>
+            <p>{section.display_name}</p>
             <CodeBlock showCopy={false} key={idx}>
               {section.range.contents}
             </CodeBlock>
diff --git a/extension/schema/FullState.d.ts b/extension/schema/FullState.d.ts
index 981e772e..abb0832d 100644
--- a/extension/schema/FullState.d.ts
+++ b/extension/schema/FullState.d.ts
@@ -32,6 +32,7 @@ export type Character = number;
 export type Contents = string;
 export type Editing = boolean;
 export type Pinned = boolean;
+export type DisplayName = string;
 export type HighlightedRanges = HighlightedRangeContext[];
 export type Name3 = string;
 export type Description1 = string;
@@ -102,6 +103,7 @@ export interface HighlightedRangeContext {
   range: RangeInFileWithContents;
   editing: Editing;
   pinned: Pinned;
+  display_name: DisplayName;
   [k: string]: unknown;
 }
 /**
diff --git a/schema/json/FullState.json b/schema/json/FullState.json
index af0f25e1..5a7e9d10 100644
--- a/schema/json/FullState.json
+++ b/schema/json/FullState.json
@@ -222,12 +222,17 @@
         "pinned": {
           "title": "Pinned",
           "type": "boolean"
+        },
+        "display_name": {
+          "title": "Display Name",
+          "type": "string"
         }
       },
       "required": [
         "range",
         "editing",
-        "pinned"
+        "pinned",
+        "display_name"
       ]
     },
     "SlashCommandDescription": {
-- 
cgit v1.2.3-70-g09d2


From b1a39567addc511ac0b477aaedaae4e10d7f5d31 Mon Sep 17 00:00:00 2001
From: Nate Sesti <sestinj@gmail.com>
Date: Tue, 11 Jul 2023 11:31:41 -0700
Subject: explain insert at cursor, better diff streaming

---
 continuedev/src/continuedev/steps/core/core.py  | 44 ++++++++++++++++++++++---
 extension/react-app/src/components/ComboBox.tsx | 32 +++++++++++++++---
 extension/src/diffs.ts                          |  7 +++-
 3 files changed, 72 insertions(+), 11 deletions(-)

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

diff --git a/continuedev/src/continuedev/steps/core/core.py b/continuedev/src/continuedev/steps/core/core.py
index b0d9d719..d4d067ba 100644
--- a/continuedev/src/continuedev/steps/core/core.py
+++ b/continuedev/src/continuedev/steps/core/core.py
@@ -265,6 +265,23 @@ class DefaultModelEditCodeStep(Step):
         return file_prefix, rif.contents, file_suffix, model_to_use, max_tokens
 
     def compile_prompt(self, file_prefix: str, contents: str, file_suffix: str, sdk: ContinueSDK) -> str:
+        if contents.strip() == "":
+            # Seperate prompt for insertion at the cursor, the other tends to cause it to repeat whole file
+            prompt = dedent(f"""\
+<file_prefix>
+{file_prefix}
+</file_prefix>
+<insertion_code_here>
+<file_suffix>
+{file_suffix}
+</file_suffix>
+<user_request>
+{self.user_input}
+</user_request>
+
+Please output the code to be inserted at the cursor in order to fulfill the user_request. Do NOT preface your answer or write anything other than code. You should not write any tags, just the code. Make sure to correctly indent the code:""")
+            return prompt
+
         prompt = self._prompt
         if file_prefix.strip() != "":
             prompt += dedent(f"""
@@ -306,15 +323,32 @@ class DefaultModelEditCodeStep(Step):
         prompt = self.compile_prompt(file_prefix, contents, file_suffix, sdk)
         full_file_contents_lines = full_file_contents.split("\n")
 
-        async def sendDiffUpdate(lines: List[str], sdk: ContinueSDK):
-            nonlocal full_file_contents_lines, rif
+        lines_to_display = []
+
+        async def sendDiffUpdate(lines: List[str], sdk: ContinueSDK, final: bool = False):
+            nonlocal full_file_contents_lines, rif, lines_to_display
 
             completion = "\n".join(lines)
 
             full_prefix_lines = full_file_contents_lines[:rif.range.start.line]
             full_suffix_lines = full_file_contents_lines[rif.range.end.line:]
+
+            # Don't do this at the very end, just show the inserted code
+            if final:
+                lines_to_display = []
+            # Only recalculate at every new-line, because this is sort of expensive
+            elif completion.endswith("\n"):
+                contents_lines = rif.contents.split("\n")
+                rewritten_lines = 0
+                for line in lines:
+                    for i in range(rewritten_lines, len(contents_lines)):
+                        if difflib.SequenceMatcher(None, line, contents_lines[i]).ratio() > 0.7 and contents_lines[i].strip() != "":
+                            rewritten_lines = i + 1
+                            break
+                lines_to_display = contents_lines[rewritten_lines:]
+
             new_file_contents = "\n".join(
-                full_prefix_lines) + "\n" + completion + "\n" + "\n".join(full_suffix_lines)
+                full_prefix_lines) + "\n" + completion + "\n" + "\n".join(lines_to_display) + "\n" + "\n".join(full_suffix_lines)
 
             step_index = sdk.history.current_index
 
@@ -495,7 +529,7 @@ class DefaultModelEditCodeStep(Step):
                 completion_lines_covered += 1
                 current_line_in_file += 1
 
-            await sendDiffUpdate(lines + [common_whitespace + unfinished_line], sdk)
+            await sendDiffUpdate(lines + [common_whitespace if unfinished_line.startswith("<") else (common_whitespace + unfinished_line)], sdk)
 
         # Add the unfinished line
         if unfinished_line != "" and not self.line_to_be_ignored(unfinished_line, completion_lines_covered == 0) and not self.is_end_line(unfinished_line):
@@ -505,7 +539,7 @@ class DefaultModelEditCodeStep(Step):
             completion_lines_covered += 1
             current_line_in_file += 1
 
-        await sendDiffUpdate(lines, sdk)
+        await sendDiffUpdate(lines, sdk, final=True)
 
         if False:
             # If the current block isn't empty, add that suggestion
diff --git a/extension/react-app/src/components/ComboBox.tsx b/extension/react-app/src/components/ComboBox.tsx
index 801c3a03..585a0584 100644
--- a/extension/react-app/src/components/ComboBox.tsx
+++ b/extension/react-app/src/components/ComboBox.tsx
@@ -180,6 +180,26 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
 
   useImperativeHandle(ref, () => downshiftProps, [downshiftProps]);
 
+  const [metaKeyPressed, setMetaKeyPressed] = useState(false);
+  useEffect(() => {
+    const handleKeyDown = (e: KeyboardEvent) => {
+      if (e.key === "Meta") {
+        setMetaKeyPressed(true);
+      }
+    };
+    const handleKeyUp = (e: KeyboardEvent) => {
+      if (e.key === "Meta") {
+        setMetaKeyPressed(false);
+      }
+    };
+    window.addEventListener("keydown", handleKeyDown);
+    window.addEventListener("keyup", handleKeyUp);
+    return () => {
+      window.removeEventListener("keydown", handleKeyDown);
+      window.removeEventListener("keyup", handleKeyUp);
+    };
+  });
+
   useEffect(() => {
     if (!inputRef.current) {
       return;
@@ -272,7 +292,7 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
       <div className="flex px-2" ref={divRef} hidden={!downshiftProps.isOpen}>
         <MainTextInput
           disabled={props.disabled}
-          placeholder="Ask a question, give instructions, or type '/' to see slash commands"
+          placeholder="Ask a question, give instructions, or type '/' to see slash commands. ⌘⏎ to edit."
           {...getInputProps({
             onChange: (e) => {
               const target = e.target as HTMLTextAreaElement;
@@ -357,10 +377,12 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
             ))}
         </Ul>
       </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> */}
+      {highlightedCodeSections.length === 0 &&
+        (downshiftProps.inputValue?.startsWith("/edit") || metaKeyPressed) && (
+          <div className="text-trueGray-400 pr-4 text-xs text-right">
+            Inserting at cursor
+          </div>
+        )}
       <ContextDropdown
         onMouseEnter={() => {
           setHoveringContextDropdown(true);
diff --git a/extension/src/diffs.ts b/extension/src/diffs.ts
index 1dc292e1..3ea6b4f8 100644
--- a/extension/src/diffs.ts
+++ b/extension/src/diffs.ts
@@ -164,7 +164,12 @@ class DiffManager {
     // Stop the step at step_index in case it is still streaming
     ideProtocolClient.deleteAtIndex(diffInfo.step_index);
 
-    this.cleanUpDiff(diffInfo);
+    vscode.workspace.textDocuments
+      .find((doc) => doc.uri.fsPath === newFilepath)
+      ?.save()
+      .then(() => {
+        this.cleanUpDiff(diffInfo);
+      });
   }
 }
 
-- 
cgit v1.2.3-70-g09d2


From 3fc16804fe74c38d4f94c25281025a84fd51771b Mon Sep 17 00:00:00 2001
From: Nate Sesti <sestinj@gmail.com>
Date: Tue, 11 Jul 2023 14:13:14 -0700
Subject: little ui stuff

---
 extension/react-app/src/components/ComboBox.tsx |  3 ++-
 extension/react-app/src/tabs/gui.tsx            | 11 +++--------
 2 files changed, 5 insertions(+), 9 deletions(-)

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

diff --git a/extension/react-app/src/components/ComboBox.tsx b/extension/react-app/src/components/ComboBox.tsx
index 585a0584..ac994b0a 100644
--- a/extension/react-app/src/components/ComboBox.tsx
+++ b/extension/react-app/src/components/ComboBox.tsx
@@ -378,7 +378,8 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
         </Ul>
       </div>
       {highlightedCodeSections.length === 0 &&
-        (downshiftProps.inputValue?.startsWith("/edit") || metaKeyPressed) && (
+        (downshiftProps.inputValue?.startsWith("/edit") ||
+          (metaKeyPressed && downshiftProps.inputValue?.length > 0)) && (
           <div className="text-trueGray-400 pr-4 text-xs text-right">
             Inserting at cursor
           </div>
diff --git a/extension/react-app/src/tabs/gui.tsx b/extension/react-app/src/tabs/gui.tsx
index 0e60e05c..619b91e1 100644
--- a/extension/react-app/src/tabs/gui.tsx
+++ b/extension/react-app/src/tabs/gui.tsx
@@ -170,6 +170,7 @@ function GUI(props: GUIProps) {
       const waitingForSteps =
         state.active &&
         state.history.current_index < state.history.timeline.length &&
+        state.history.timeline[state.history.current_index] &&
         state.history.timeline[
           state.history.current_index
         ].step.description?.trim() === "";
@@ -236,14 +237,14 @@ function GUI(props: GUIProps) {
         history.current_index < history.timeline.length
       ) {
         if (
-          history.timeline[history.current_index].step.name ===
+          history.timeline[history.current_index]?.step.name ===
           "Waiting for user input"
         ) {
           if (input.trim() === "") return;
           onStepUserInput(input, history!.current_index);
           return;
         } else if (
-          history.timeline[history.current_index].step.name ===
+          history.timeline[history.current_index]?.step.name ===
           "Waiting for user confirmation"
         ) {
           onStepUserInput("ok", history!.current_index);
@@ -350,12 +351,6 @@ function GUI(props: GUIProps) {
         </div>
 
         <ComboBox
-          // disabled={
-          //   history?.timeline.length
-          //     ? history.timeline[history.current_index].step.name ===
-          //       "Waiting for user confirmation"
-          //     : false
-          // }
           ref={mainTextInputRef}
           onEnter={(e) => {
             onMainTextInput(e);
-- 
cgit v1.2.3-70-g09d2


From 391764f1371dab06af30a29e10a826a516b69bb3 Mon Sep 17 00:00:00 2001
From: Nate Sesti <sestinj@gmail.com>
Date: Wed, 12 Jul 2023 21:53:06 -0700
Subject: persist state and reconnect automatically

---
 continuedev/src/continuedev/core/autopilot.py      |  17 +++-
 continuedev/src/continuedev/libs/constants/main.py |   6 ++
 continuedev/src/continuedev/libs/util/paths.py     |  17 ++++
 continuedev/src/continuedev/server/gui.py          |  10 +-
 continuedev/src/continuedev/server/ide.py          |  25 +++--
 continuedev/src/continuedev/server/ide_protocol.py |  10 +-
 continuedev/src/continuedev/server/main.py         |  16 ++-
 .../src/continuedev/server/session_manager.py      |  41 ++++++--
 docs/docs/concepts/ide.md                          |   4 +-
 extension/react-app/src/components/ComboBox.tsx    |   1 -
 extension/react-app/src/hooks/messenger.ts         |  10 --
 extension/react-app/src/pages/gui.tsx              |   1 -
 extension/src/activation/activate.ts               |   2 +-
 extension/src/continueIdeClient.ts                 |  62 ++++++++---
 extension/src/debugPanel.ts                        | 113 ++++-----------------
 extension/src/util/messenger.ts                    |  10 ++
 16 files changed, 192 insertions(+), 153 deletions(-)
 create mode 100644 continuedev/src/continuedev/libs/constants/main.py
 create mode 100644 continuedev/src/continuedev/libs/util/paths.py

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

diff --git a/continuedev/src/continuedev/core/autopilot.py b/continuedev/src/continuedev/core/autopilot.py
index 1b074435..e1c8a076 100644
--- a/continuedev/src/continuedev/core/autopilot.py
+++ b/continuedev/src/continuedev/core/autopilot.py
@@ -1,13 +1,13 @@
 from functools import cached_property
 import traceback
 import time
-from typing import Any, Callable, Coroutine, Dict, List
+from typing import Any, Callable, Coroutine, Dict, List, Union
 import os
 from aiohttp import ClientPayloadError
+from pydantic import root_validator
 
 from ..models.filesystem import RangeInFileWithContents
 from ..models.filesystem_edit import FileEditWithFullContents
-from ..libs.llm import LLM
 from .observation import Observation, InternalErrorObservation
 from ..server.ide_protocol import AbstractIdeProtocolServer
 from ..libs.util.queue import AsyncSubscriptionQueue
@@ -16,7 +16,6 @@ from .main import Context, ContinueCustomException, HighlightedRangeContext, Pol
 from ..steps.core.core import ReversibleStep, ManualEditStep, UserInputStep
 from ..libs.util.telemetry import capture_event
 from .sdk import ContinueSDK
-import asyncio
 from ..libs.util.step_name_to_steps import get_step_from_name
 from ..libs.util.traceback_parsers import get_python_traceback, get_javascript_traceback
 from openai import error as openai_errors
@@ -46,6 +45,7 @@ class Autopilot(ContinueBaseModel):
     ide: AbstractIdeProtocolServer
     history: History = History.from_empty()
     context: Context = Context()
+    full_state: Union[FullState, None] = None
     _on_update_callbacks: List[Callable[[FullState], None]] = []
 
     _active: bool = False
@@ -63,8 +63,15 @@ class Autopilot(ContinueBaseModel):
         arbitrary_types_allowed = True
         keep_untouched = (cached_property,)
 
+    @root_validator(pre=True)
+    def fill_in_values(cls, values):
+        full_state: FullState = values.get('full_state')
+        if full_state is not None:
+            values['history'] = full_state.history
+        return values
+
     def get_full_state(self) -> FullState:
-        return FullState(
+        full_state = FullState(
             history=self.history,
             active=self._active,
             user_input_queue=self._main_user_input_queue,
@@ -73,6 +80,8 @@ class Autopilot(ContinueBaseModel):
             slash_commands=self.get_available_slash_commands(),
             adding_highlighted_code=self._adding_highlighted_code,
         )
+        self.full_state = full_state
+        return full_state
 
     def get_available_slash_commands(self) -> List[Dict]:
         custom_commands = list(map(lambda x: {
diff --git a/continuedev/src/continuedev/libs/constants/main.py b/continuedev/src/continuedev/libs/constants/main.py
new file mode 100644
index 00000000..96eb6e69
--- /dev/null
+++ b/continuedev/src/continuedev/libs/constants/main.py
@@ -0,0 +1,6 @@
+## PATHS ##
+
+CONTINUE_GLOBAL_FOLDER = ".continue"
+CONTINUE_SESSIONS_FOLDER = "sessions"
+CONTINUE_SERVER_FOLDER = "server"
+
diff --git a/continuedev/src/continuedev/libs/util/paths.py b/continuedev/src/continuedev/libs/util/paths.py
new file mode 100644
index 00000000..fddef887
--- /dev/null
+++ b/continuedev/src/continuedev/libs/util/paths.py
@@ -0,0 +1,17 @@
+import os
+
+from ..constants.main import CONTINUE_SESSIONS_FOLDER, CONTINUE_GLOBAL_FOLDER, CONTINUE_SERVER_FOLDER
+
+def getGlobalFolderPath():
+    return os.path.join(os.path.expanduser("~"), CONTINUE_GLOBAL_FOLDER)
+
+
+
+def getSessionsFolderPath():
+    return os.path.join(getGlobalFolderPath(), CONTINUE_SESSIONS_FOLDER)
+
+def getServerFolderPath():
+    return os.path.join(getGlobalFolderPath(), CONTINUE_SERVER_FOLDER)
+
+def getSessionFilePath(session_id: str):
+    return os.path.join(getSessionsFolderPath(), f"{session_id}.json")
\ No newline at end of file
diff --git a/continuedev/src/continuedev/server/gui.py b/continuedev/src/continuedev/server/gui.py
index 21089f30..8f6f68f6 100644
--- a/continuedev/src/continuedev/server/gui.py
+++ b/continuedev/src/continuedev/server/gui.py
@@ -31,12 +31,12 @@ class AppStatus:
 Server.handle_exit = AppStatus.handle_exit
 
 
-def session(x_continue_session_id: str = Header("anonymous")) -> Session:
-    return session_manager.get_session(x_continue_session_id)
+async def session(x_continue_session_id: str = Header("anonymous")) -> Session:
+    return await session_manager.get_session(x_continue_session_id)
 
 
-def websocket_session(session_id: str) -> Session:
-    return session_manager.get_session(session_id)
+async def websocket_session(session_id: str) -> Session:
+    return await session_manager.get_session(session_id)
 
 
 T = TypeVar("T", bound=BaseModel)
@@ -199,4 +199,6 @@ async def websocket_endpoint(websocket: WebSocket, session: Session = Depends(we
         print("Closing gui websocket")
         if websocket.client_state != WebSocketState.DISCONNECTED:
             await websocket.close()
+
+        session_manager.persist_session(session.session_id)
         session_manager.remove_session(session.session_id)
diff --git a/continuedev/src/continuedev/server/ide.py b/continuedev/src/continuedev/server/ide.py
index 4645b49e..12a21f19 100644
--- a/continuedev/src/continuedev/server/ide.py
+++ b/continuedev/src/continuedev/server/ide.py
@@ -52,9 +52,11 @@ class FileEditsUpdate(BaseModel):
 class OpenFilesResponse(BaseModel):
     openFiles: List[str]
 
+
 class VisibleFilesResponse(BaseModel):
     visibleFiles: List[str]
 
+
 class HighlightedCodeResponse(BaseModel):
     highlightedCode: List[RangeInFile]
 
@@ -115,6 +117,7 @@ class IdeProtocolServer(AbstractIdeProtocolServer):
     websocket: WebSocket
     session_manager: SessionManager
     sub_queue: AsyncSubscriptionQueue = AsyncSubscriptionQueue()
+    session_id: Union[str, None] = None
 
     def __init__(self, session_manager: SessionManager, websocket: WebSocket):
         self.websocket = websocket
@@ -132,8 +135,6 @@ class IdeProtocolServer(AbstractIdeProtocolServer):
                 continue
             message_type = message["messageType"]
             data = message["data"]
-            # if message_type == "openGUI":
-            #     await self.openGUI()
             if message_type == "workspaceDirectory":
                 self.workspace_directory = data["workspaceDirectory"]
                 break
@@ -158,8 +159,8 @@ class IdeProtocolServer(AbstractIdeProtocolServer):
         return resp_model.parse_obj(resp)
 
     async def handle_json(self, message_type: str, data: Any):
-        if message_type == "openGUI":
-            await self.openGUI()
+        if message_type == "getSessionId":
+            await self.getSessionId()
         elif message_type == "setFileOpen":
             await self.setFileOpen(data["filepath"], data["open"])
         elif message_type == "setSuggestionsLocked":
@@ -217,9 +218,10 @@ class IdeProtocolServer(AbstractIdeProtocolServer):
             "locked": locked
         })
 
-    async def openGUI(self):
-        session_id = self.session_manager.new_session(self)
-        await self._send_json("openGUI", {
+    async def getSessionId(self):
+        session_id = self.session_manager.new_session(
+            self, self.session_id).session_id
+        await self._send_json("getSessionId", {
             "sessionId": session_id
         })
 
@@ -304,7 +306,7 @@ class IdeProtocolServer(AbstractIdeProtocolServer):
     async def getOpenFiles(self) -> List[str]:
         resp = await self._send_and_receive_json({}, OpenFilesResponse, "openFiles")
         return resp.openFiles
-    
+
     async def getVisibleFiles(self) -> List[str]:
         resp = await self._send_and_receive_json({}, VisibleFilesResponse, "visibleFiles")
         return resp.visibleFiles
@@ -416,7 +418,7 @@ class IdeProtocolServer(AbstractIdeProtocolServer):
 
 
 @router.websocket("/ws")
-async def websocket_endpoint(websocket: WebSocket):
+async def websocket_endpoint(websocket: WebSocket, session_id: str = None):
     try:
         await websocket.accept()
         print("Accepted websocket connection from, ", websocket.client)
@@ -434,6 +436,9 @@ async def websocket_endpoint(websocket: WebSocket):
                 ideProtocolServer.handle_json(message_type, data))
 
         ideProtocolServer = IdeProtocolServer(session_manager, websocket)
+        ideProtocolServer.session_id = session_id
+        if session_id is not None:
+            session_manager.registered_ides[session_id] = ideProtocolServer
         other_msgs = await ideProtocolServer.initialize()
 
         for other_msg in other_msgs:
@@ -454,3 +459,5 @@ async def websocket_endpoint(websocket: WebSocket):
     finally:
         if websocket.client_state != WebSocketState.DISCONNECTED:
             await websocket.close()
+
+        session_manager.registered_ides.pop(ideProtocolServer.session_id)
diff --git a/continuedev/src/continuedev/server/ide_protocol.py b/continuedev/src/continuedev/server/ide_protocol.py
index 2783dc61..2f78cf0e 100644
--- a/continuedev/src/continuedev/server/ide_protocol.py
+++ b/continuedev/src/continuedev/server/ide_protocol.py
@@ -1,5 +1,6 @@
-from typing import Any, List
+from typing import Any, List, Union
 from abc import ABC, abstractmethod, abstractproperty
+from fastapi import WebSocket
 
 from ..models.main import Traceback
 from ..models.filesystem_edit import FileEdit, FileSystemEdit, EditDiff
@@ -7,6 +8,9 @@ from ..models.filesystem import RangeInFile, RangeInFileWithContents
 
 
 class AbstractIdeProtocolServer(ABC):
+    websocket: WebSocket
+    session_id: Union[str, None]
+
     @abstractmethod
     async def handle_json(self, data: Any):
         """Handle a json message"""
@@ -24,8 +28,8 @@ class AbstractIdeProtocolServer(ABC):
         """Set whether suggestions are locked"""
 
     @abstractmethod
-    async def openGUI(self):
-        """Open a GUI"""
+    async def getSessionId(self):
+        """Get a new session ID"""
 
     @abstractmethod
     async def showSuggestionsAndWait(self, suggestions: List[FileEdit]) -> bool:
diff --git a/continuedev/src/continuedev/server/main.py b/continuedev/src/continuedev/server/main.py
index f4d82903..aa093853 100644
--- a/continuedev/src/continuedev/server/main.py
+++ b/continuedev/src/continuedev/server/main.py
@@ -4,7 +4,8 @@ from fastapi import FastAPI
 from fastapi.middleware.cors import CORSMiddleware
 from .ide import router as ide_router
 from .gui import router as gui_router
-import logging
+from .session_manager import session_manager
+import atexit
 import uvicorn
 import argparse
 
@@ -44,5 +45,16 @@ def run_server():
     uvicorn.run(app, host="0.0.0.0", port=args.port)
 
 
+def cleanup():
+    print("Cleaning up sessions")
+    for session_id in session_manager.sessions:
+        session_manager.persist_session(session_id)
+
+
+atexit.register(cleanup)
 if __name__ == "__main__":
-    run_server()
+    try:
+        run_server()
+    except Exception as e:
+        cleanup()
+        raise e
diff --git a/continuedev/src/continuedev/server/session_manager.py b/continuedev/src/continuedev/server/session_manager.py
index 7147dcfa..fb8ac386 100644
--- a/continuedev/src/continuedev/server/session_manager.py
+++ b/continuedev/src/continuedev/server/session_manager.py
@@ -1,9 +1,12 @@
-from asyncio import BaseEventLoop
+import os
 from fastapi import WebSocket
 from typing import Any, Dict, List, Union
 from uuid import uuid4
+import json
 
+from ..libs.util.paths import getSessionFilePath, getSessionsFolderPath
 from ..models.filesystem_edit import FileEditWithFullContents
+from ..libs.constants.main import CONTINUE_SESSIONS_FOLDER
 from ..core.policy import DemoPolicy
 from ..core.main import FullState
 from ..core.autopilot import Autopilot
@@ -39,17 +42,35 @@ class DemoAutopilot(Autopilot):
 
 class SessionManager:
     sessions: Dict[str, Session] = {}
+    # Mapping of session_id to IDE, where the IDE is still alive
+    registered_ides: Dict[str, AbstractIdeProtocolServer] = {}
 
-    def get_session(self, session_id: str) -> Session:
+    async def get_session(self, session_id: str) -> Session:
         if session_id not in self.sessions:
+            # Check then whether it is persisted by listing all files in the sessions folder
+            # And only if the IDE is still alive
+            sessions_folder = getSessionsFolderPath()
+            session_files = os.listdir(sessions_folder)
+            if f"{session_id}.json" in session_files and session_id in self.registered_ides:
+                if self.registered_ides[session_id].session_id is not None:
+                    return self.new_session(self.registered_ides[session_id], session_id=session_id)
+
             raise KeyError("Session ID not recognized", session_id)
         return self.sessions[session_id]
 
-    def new_session(self, ide: AbstractIdeProtocolServer) -> str:
-        autopilot = DemoAutopilot(policy=DemoPolicy(), ide=ide)
-        session_id = str(uuid4())
+    def new_session(self, ide: AbstractIdeProtocolServer, session_id: Union[str, None] = None) -> Session:
+        full_state = None
+        if session_id is not None and os.path.exists(getSessionFilePath(session_id)):
+            with open(getSessionFilePath(session_id), "r") as f:
+                full_state = FullState(**json.load(f))
+
+        autopilot = DemoAutopilot(
+            policy=DemoPolicy(), ide=ide, full_state=full_state)
+        session_id = session_id or str(uuid4())
+        ide.session_id = session_id
         session = Session(session_id=session_id, autopilot=autopilot)
         self.sessions[session_id] = session
+        self.registered_ides[session_id] = ide
 
         async def on_update(state: FullState):
             await session_manager.send_ws_data(session_id, "state_update", {
@@ -58,11 +79,19 @@ class SessionManager:
 
         autopilot.on_update(on_update)
         create_async_task(autopilot.run_policy())
-        return session_id
+        return session
 
     def remove_session(self, session_id: str):
         del self.sessions[session_id]
 
+    def persist_session(self, session_id: str):
+        """Save the session's FullState as a json file"""
+        full_state = self.sessions[session_id].autopilot.get_full_state()
+        if not os.path.exists(getSessionsFolderPath()):
+            os.mkdir(getSessionsFolderPath())
+        with open(getSessionFilePath(session_id), "w") as f:
+            json.dump(full_state.dict(), f)
+
     def register_websocket(self, session_id: str, ws: WebSocket):
         self.sessions[session_id].ws = ws
         print("Registered websocket for session", session_id)
diff --git a/docs/docs/concepts/ide.md b/docs/docs/concepts/ide.md
index dc7b9e23..bd31481b 100644
--- a/docs/docs/concepts/ide.md
+++ b/docs/docs/concepts/ide.md
@@ -41,9 +41,9 @@ Get the workspace directory
 
 Set whether a file is open
 
-### openGUI
+### getSessionId
 
-Open a gui
+Get a new session ID
 
 ### showSuggestionsAndWait
 
diff --git a/extension/react-app/src/components/ComboBox.tsx b/extension/react-app/src/components/ComboBox.tsx
index ac994b0a..7d6541c7 100644
--- a/extension/react-app/src/components/ComboBox.tsx
+++ b/extension/react-app/src/components/ComboBox.tsx
@@ -331,7 +331,6 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
               ) {
                 (event.nativeEvent as any).preventDownshiftDefault = true;
               } else if (event.key === "ArrowUp") {
-                console.log("OWJFOIJO");
                 if (positionInHistory == 0) return;
                 else if (
                   positionInHistory == history.length &&
diff --git a/extension/react-app/src/hooks/messenger.ts b/extension/react-app/src/hooks/messenger.ts
index e2a0bab8..00ce1fbb 100644
--- a/extension/react-app/src/hooks/messenger.ts
+++ b/extension/react-app/src/hooks/messenger.ts
@@ -1,6 +1,3 @@
-// console.log("Websocket import");
-// const WebSocket = require("ws");
-
 export abstract class Messenger {
   abstract send(messageType: string, data: object): void;
 
@@ -28,13 +25,6 @@ export class WebsocketMessenger extends Messenger {
   private serverUrl: string;
 
   _newWebsocket(): WebSocket {
-    // // Dynamic import, because WebSocket is builtin with browser, but not with node. And can't use require in browser.
-    // if (typeof process === "object") {
-    //   console.log("Using node");
-    //   // process is only available in Node
-    //   var WebSocket = require("ws");
-    // }
-
     const newWebsocket = new WebSocket(this.serverUrl);
     for (const listener of this.onOpenListeners) {
       this.onOpen(listener);
diff --git a/extension/react-app/src/pages/gui.tsx b/extension/react-app/src/pages/gui.tsx
index b9382bd1..4ff260fa 100644
--- a/extension/react-app/src/pages/gui.tsx
+++ b/extension/react-app/src/pages/gui.tsx
@@ -262,7 +262,6 @@ function GUI(props: GUIProps) {
 
   const onStepUserInput = (input: string, index: number) => {
     if (!client) return;
-    console.log("Sending step user input", input, index);
     client.sendStepUserInput(input, index);
   };
 
diff --git a/extension/src/activation/activate.ts b/extension/src/activation/activate.ts
index 559caf44..cd885b12 100644
--- a/extension/src/activation/activate.ts
+++ b/extension/src/activation/activate.ts
@@ -56,7 +56,7 @@ export async function activateExtension(context: vscode.ExtensionContext) {
   registerAllCodeLensProviders(context);
   registerAllCommands(context);
 
-  // Initialize IDE Protocol Client, then call "openGUI"
+  // Initialize IDE Protocol Client
   const serverUrl = getContinueServerUrl();
   ideProtocolClient = new IdeProtocolClient(
     `${serverUrl.replace("http", "ws")}/ide/ws`,
diff --git a/extension/src/continueIdeClient.ts b/extension/src/continueIdeClient.ts
index b728833f..4c1fdf1e 100644
--- a/extension/src/continueIdeClient.ts
+++ b/extension/src/continueIdeClient.ts
@@ -1,10 +1,9 @@
-// import { ShowSuggestionRequest } from "../schema/ShowSuggestionRequest";
 import {
   editorSuggestionsLocked,
   showSuggestion as showSuggestionInEditor,
   SuggestionRanges,
 } from "./suggestions";
-import { openEditorAndRevealRange, getRightViewColumn } from "./util/vscode";
+import { openEditorAndRevealRange } from "./util/vscode";
 import { FileEdit } from "../schema/FileEdit";
 import { RangeInFile } from "../schema/RangeInFile";
 import * as vscode from "vscode";
@@ -15,8 +14,6 @@ import {
 import { FileEditWithFullContents } from "../schema/FileEditWithFullContents";
 import fs = require("fs");
 import { WebsocketMessenger } from "./util/messenger";
-import * as path from "path";
-import * as os from "os";
 import { diffManager } from "./diffs";
 
 class IdeProtocolClient {
@@ -27,17 +24,54 @@ class IdeProtocolClient {
 
   private _highlightDebounce: NodeJS.Timeout | null = null;
 
-  constructor(serverUrl: string, context: vscode.ExtensionContext) {
-    this.context = context;
+  private _lastReloadTime: number = 16;
+  private _reconnectionTimeouts: NodeJS.Timeout[] = [];
+
+  private _sessionId: string | null = null;
+  private _serverUrl: string;
 
-    let messenger = new WebsocketMessenger(serverUrl);
+  private _newWebsocketMessenger() {
+    const requestUrl =
+      this._serverUrl +
+      (this._sessionId ? `?session_id=${this._sessionId}` : "");
+    const messenger = new WebsocketMessenger(requestUrl);
     this.messenger = messenger;
-    messenger.onClose(() => {
+
+    const reconnect = () => {
+      console.log("Trying to reconnect IDE protocol websocket...");
       this.messenger = null;
+
+      // Exponential backoff to reconnect
+      this._reconnectionTimeouts.forEach((to) => clearTimeout(to));
+
+      const timeout = setTimeout(() => {
+        if (this.messenger?.websocket?.readyState === 1) {
+          return;
+        }
+        this._newWebsocketMessenger();
+      }, this._lastReloadTime);
+
+      this._reconnectionTimeouts.push(timeout);
+      this._lastReloadTime = Math.min(2 * this._lastReloadTime, 5000);
+    };
+    messenger.onOpen(() => {
+      this._reconnectionTimeouts.forEach((to) => clearTimeout(to));
+    });
+    messenger.onClose(() => {
+      reconnect();
+    });
+    messenger.onError(() => {
+      reconnect();
     });
     messenger.onMessage((messageType, data, messenger) => {
       this.handleMessage(messageType, data, messenger);
     });
+  }
+
+  constructor(serverUrl: string, context: vscode.ExtensionContext) {
+    this.context = context;
+    this._serverUrl = serverUrl;
+    this._newWebsocketMessenger();
 
     // Setup listeners for any file changes in open editors
     // vscode.workspace.onDidChangeTextDocument((event) => {
@@ -171,7 +205,7 @@ class IdeProtocolClient {
       case "showDiff":
         this.showDiff(data.filepath, data.replacement, data.step_index);
         break;
-      case "openGUI":
+      case "getSessionId":
       case "connected":
         break;
       default:
@@ -284,10 +318,6 @@ class IdeProtocolClient {
   // ------------------------------------ //
   // Initiate Request
 
-  async openGUI(asRightWebviewPanel: boolean = false) {
-    // Open the webview panel
-  }
-
   async getSessionId(): Promise<string> {
     await new Promise((resolve, reject) => {
       // Repeatedly try to connect to the server
@@ -303,10 +333,10 @@ class IdeProtocolClient {
         }
       }, 1000);
     });
-    const resp = await this.messenger?.sendAndReceive("openGUI", {});
-    const sessionId = resp.sessionId;
+    const resp = await this.messenger?.sendAndReceive("getSessionId", {});
     // console.log("New Continue session with ID: ", sessionId);
-    return sessionId;
+    this._sessionId = resp.sessionId;
+    return resp.sessionId;
   }
 
   acceptRejectSuggestion(accept: boolean, key: SuggestionRanges) {
diff --git a/extension/src/debugPanel.ts b/extension/src/debugPanel.ts
index 487bbedf..5e1689d1 100644
--- a/extension/src/debugPanel.ts
+++ b/extension/src/debugPanel.ts
@@ -8,76 +8,6 @@ import {
 import { RangeInFile } from "./client";
 const WebSocket = require("ws");
 
-class StreamManager {
-  private _fullText: string = "";
-  private _insertionPoint: vscode.Position | undefined;
-
-  private _addToEditor(update: string) {
-    let editor =
-      vscode.window.activeTextEditor || vscode.window.visibleTextEditors[0];
-
-    if (typeof this._insertionPoint === "undefined") {
-      if (editor?.selection.isEmpty) {
-        this._insertionPoint = editor?.selection.active;
-      } else {
-        this._insertionPoint = editor?.selection.end;
-      }
-    }
-    editor?.edit((editBuilder) => {
-      if (this._insertionPoint) {
-        editBuilder.insert(this._insertionPoint, update);
-        this._insertionPoint = this._insertionPoint.translate(
-          Array.from(update.matchAll(/\n/g)).length,
-          update.length
-        );
-      }
-    });
-  }
-
-  public closeStream() {
-    this._fullText = "";
-    this._insertionPoint = undefined;
-    this._codeBlockStatus = "closed";
-    this._pendingBackticks = 0;
-  }
-
-  private _codeBlockStatus: "open" | "closed" | "language-descriptor" =
-    "closed";
-  private _pendingBackticks: number = 0;
-  public onStreamUpdate(update: string) {
-    let textToInsert = "";
-    for (let i = 0; i < update.length; i++) {
-      switch (this._codeBlockStatus) {
-        case "closed":
-          if (update[i] === "`" && this._fullText.endsWith("``")) {
-            this._codeBlockStatus = "language-descriptor";
-          }
-          break;
-        case "language-descriptor":
-          if (update[i] === " " || update[i] === "\n") {
-            this._codeBlockStatus = "open";
-          }
-          break;
-        case "open":
-          if (update[i] === "`") {
-            if (this._fullText.endsWith("``")) {
-              this._codeBlockStatus = "closed";
-              this._pendingBackticks = 0;
-            } else {
-              this._pendingBackticks += 1;
-            }
-          } else {
-            textToInsert += "`".repeat(this._pendingBackticks) + update[i];
-            this._pendingBackticks = 0;
-          }
-          break;
-      }
-      this._fullText += update[i];
-    }
-    this._addToEditor(textToInsert);
-  }
-}
-
 let websocketConnections: { [url: string]: WebsocketConnection | undefined } =
   {};
 
@@ -127,8 +57,6 @@ class WebsocketConnection {
   }
 }
 
-let streamManager = new StreamManager();
-
 export let debugPanelWebview: vscode.Webview | undefined;
 export function setupDebugPanel(
   panel: vscode.WebviewPanel | vscode.WebviewView,
@@ -147,10 +75,7 @@ export function setupDebugPanel(
     .toString();
 
   const isProduction = true; // context?.extensionMode === vscode.ExtensionMode.Development;
-  if (!isProduction) {
-    scriptUri = "http://localhost:5173/src/main.tsx";
-    styleMainUri = "http://localhost:5173/src/main.css";
-  } else {
+  if (isProduction) {
     scriptUri = debugPanelWebview
       .asWebviewUri(
         vscode.Uri.joinPath(extensionUri, "react-app/dist/assets/index.js")
@@ -161,6 +86,9 @@ export function setupDebugPanel(
         vscode.Uri.joinPath(extensionUri, "react-app/dist/assets/index.css")
       )
       .toString();
+  } else {
+    scriptUri = "http://localhost:5173/src/main.tsx";
+    styleMainUri = "http://localhost:5173/src/main.css";
   }
 
   panel.webview.options = {
@@ -175,11 +103,11 @@ export function setupDebugPanel(
       return;
     }
 
-    let rangeInFile: RangeInFile = {
+    const rangeInFile: RangeInFile = {
       range: e.selections[0],
       filepath: e.textEditor.document.fileName,
     };
-    let filesystem = {
+    const filesystem = {
       [rangeInFile.filepath]: e.textEditor.document.getText(),
     };
     panel.webview.postMessage({
@@ -217,13 +145,19 @@ export function setupDebugPanel(
           url,
         });
       };
-      const connection = new WebsocketConnection(
-        url,
-        onMessage,
-        onOpen,
-        onClose
-      );
-      websocketConnections[url] = connection;
+      try {
+        const connection = new WebsocketConnection(
+          url,
+          onMessage,
+          onOpen,
+          onClose
+        );
+        websocketConnections[url] = connection;
+        resolve(null);
+      } catch (e) {
+        console.log("Caught it!: ", e);
+        reject(e);
+      }
     });
   }
 
@@ -292,15 +226,6 @@ export function setupDebugPanel(
         openEditorAndRevealRange(data.path, undefined, vscode.ViewColumn.One);
         break;
       }
-      case "streamUpdate": {
-        // Write code at the position of the cursor
-        streamManager.onStreamUpdate(data.update);
-        break;
-      }
-      case "closeStream": {
-        streamManager.closeStream();
-        break;
-      }
       case "withProgress": {
         // This message allows withProgress to be used in the webview
         if (data.done) {
diff --git a/extension/src/util/messenger.ts b/extension/src/util/messenger.ts
index b1df161b..7fd71ddd 100644
--- a/extension/src/util/messenger.ts
+++ b/extension/src/util/messenger.ts
@@ -15,6 +15,8 @@ export abstract class Messenger {
   abstract onOpen(callback: () => void): void;
 
   abstract onClose(callback: () => void): void;
+  
+  abstract onError(callback: () => void): void;
 
   abstract sendAndReceive(messageType: string, data: any): Promise<any>;
 }
@@ -26,6 +28,7 @@ export class WebsocketMessenger extends Messenger {
   } = {};
   private onOpenListeners: (() => void)[] = [];
   private onCloseListeners: (() => void)[] = [];
+  private onErrorListeners: (() => void)[] = [];
   private serverUrl: string;
 
   _newWebsocket(): WebSocket {
@@ -43,6 +46,9 @@ export class WebsocketMessenger extends Messenger {
     for (const listener of this.onCloseListeners) {
       this.onClose(listener);
     }
+    for (const listener of this.onErrorListeners) {
+      this.onError(listener);
+    }
     for (const messageType in this.onMessageListeners) {
       for (const listener of this.onMessageListeners[messageType]) {
         this.onMessageType(messageType, listener);
@@ -151,4 +157,8 @@ export class WebsocketMessenger extends Messenger {
   onClose(callback: () => void): void {
     this.websocket.addEventListener("close", callback);
   }
+
+  onError(callback: () => void): void {
+    this.websocket.addEventListener("error", callback);
+  }
 }
-- 
cgit v1.2.3-70-g09d2


From 5c6d2f1be8474d26124506e0c2a640fa68efe52d Mon Sep 17 00:00:00 2001
From: Nate Sesti <sestinj@gmail.com>
Date: Fri, 14 Jul 2023 02:30:45 -0700
Subject: fixed unique_id being asyncio.run property

---
 continuedev/src/continuedev/server/ide.py          | 22 +++++++++++-----------
 continuedev/src/continuedev/server/ide_protocol.py |  5 +----
 continuedev/src/continuedev/steps/help.py          |  8 +++++---
 extension/package-lock.json                        |  4 ++--
 extension/package.json                             |  2 +-
 extension/react-app/src/components/ComboBox.tsx    | 17 ++---------------
 extension/react-app/src/components/Onboarding.tsx  |  1 +
 7 files changed, 23 insertions(+), 36 deletions(-)

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

diff --git a/continuedev/src/continuedev/server/ide.py b/continuedev/src/continuedev/server/ide.py
index 12a21f19..73cce201 100644
--- a/continuedev/src/continuedev/server/ide.py
+++ b/continuedev/src/continuedev/server/ide.py
@@ -123,10 +123,12 @@ class IdeProtocolServer(AbstractIdeProtocolServer):
         self.websocket = websocket
         self.session_manager = session_manager
 
-    workspace_directory: str
+    workspace_directory: str = None
+    unique_id: str = None
 
     async def initialize(self) -> List[str]:
         await self._send_json("workspaceDirectory", {})
+        await self._send_json("uniqueId", {})
         other_msgs = []
         while True:
             msg_string = await self.websocket.receive_text()
@@ -137,9 +139,13 @@ class IdeProtocolServer(AbstractIdeProtocolServer):
             data = message["data"]
             if message_type == "workspaceDirectory":
                 self.workspace_directory = data["workspaceDirectory"]
-                break
+            elif message_type == "uniqueId":
+                self.unique_id = data["uniqueId"]
             else:
                 other_msgs.append(msg_string)
+
+            if self.workspace_directory is not None and self.unique_id is not None:
+                break
         return other_msgs
 
     async def _send_json(self, message_type: str, data: Any):
@@ -183,10 +189,12 @@ class IdeProtocolServer(AbstractIdeProtocolServer):
             self.onMainUserInput(data["input"])
         elif message_type == "deleteAtIndex":
             self.onDeleteAtIndex(data["index"])
-        elif message_type in ["highlightedCode", "openFiles", "visibleFiles", "readFile", "editFile", "getUserSecret", "runCommand", "uniqueId"]:
+        elif message_type in ["highlightedCode", "openFiles", "visibleFiles", "readFile", "editFile", "getUserSecret", "runCommand"]:
             self.sub_queue.post(message_type, data)
         elif message_type == "workspaceDirectory":
             self.workspace_directory = data["workspaceDirectory"]
+        elif message_type == "uniqueId":
+            self.unique_id = data["uniqueId"]
         else:
             raise ValueError("Unknown message type", message_type)
 
@@ -311,14 +319,6 @@ class IdeProtocolServer(AbstractIdeProtocolServer):
         resp = await self._send_and_receive_json({}, VisibleFilesResponse, "visibleFiles")
         return resp.visibleFiles
 
-    async def get_unique_id(self) -> str:
-        resp = await self._send_and_receive_json({}, UniqueIdResponse, "uniqueId")
-        return resp.uniqueId
-
-    @cached_property_no_none
-    def unique_id(self) -> str:
-        return asyncio.run(self.get_unique_id())
-
     async def getHighlightedCode(self) -> List[RangeInFile]:
         resp = await self._send_and_receive_json({}, HighlightedCodeResponse, "highlightedCode")
         return resp.highlightedCode
diff --git a/continuedev/src/continuedev/server/ide_protocol.py b/continuedev/src/continuedev/server/ide_protocol.py
index 2f78cf0e..d0fb0bf8 100644
--- a/continuedev/src/continuedev/server/ide_protocol.py
+++ b/continuedev/src/continuedev/server/ide_protocol.py
@@ -108,7 +108,4 @@ class AbstractIdeProtocolServer(ABC):
         """Show a diff"""
 
     workspace_directory: str
-
-    @abstractproperty
-    def unique_id(self) -> str:
-        """Get a unique ID for this IDE"""
+    unique_id: str
diff --git a/continuedev/src/continuedev/steps/help.py b/continuedev/src/continuedev/steps/help.py
index fdfb986f..2dc3647c 100644
--- a/continuedev/src/continuedev/steps/help.py
+++ b/continuedev/src/continuedev/steps/help.py
@@ -6,7 +6,7 @@ from ..libs.util.telemetry import capture_event
 help = dedent("""\
         Continue is an open-source coding autopilot. It is a VS Code extension that brings the power of ChatGPT to your IDE.
               
-        It gathers context for you and stores your interactions automatically, so that you can avoid copy/paste now and benefit from a customized LLM later.
+        It gathers context for you and stores your interactions automatically, so that you can avoid copy/paste now and benefit from a customized Large Language Model (LLM) later.
 
         Continue can be used to...
         1. Edit chunks of code with specific instructions (e.g. "/edit migrate this digital ocean terraform file into one that works for GCP")
@@ -25,6 +25,7 @@ help = dedent("""\
 
         If you have feedback, please use /feedback to let us know how you would like to use Continue. We are excited to hear from you!""")
 
+
 class HelpStep(Step):
 
     name: str = "Help"
@@ -41,7 +42,7 @@ class HelpStep(Step):
                     Information:
 
                     {help}""")
-        
+
         self.chat_context.append(ChatMessage(
             role="user",
             content=prompt,
@@ -54,4 +55,5 @@ class HelpStep(Step):
                 self.description += chunk["content"]
                 await sdk.update_ui()
 
-        capture_event(sdk.ide.unique_id, "help", {"question": question, "answer": self.description})
\ No newline at end of file
+        capture_event(sdk.ide.unique_id, "help", {
+                      "question": question, "answer": self.description})
diff --git a/extension/package-lock.json b/extension/package-lock.json
index 65fdab12..9d5c73e1 100644
--- a/extension/package-lock.json
+++ b/extension/package-lock.json
@@ -1,12 +1,12 @@
 {
   "name": "continue",
-  "version": "0.0.162",
+  "version": "0.0.163",
   "lockfileVersion": 2,
   "requires": true,
   "packages": {
     "": {
       "name": "continue",
-      "version": "0.0.162",
+      "version": "0.0.163",
       "license": "Apache-2.0",
       "dependencies": {
         "@electron/rebuild": "^3.2.10",
diff --git a/extension/package.json b/extension/package.json
index ef39582b..2b0f6b94 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.162",
+  "version": "0.0.163",
   "publisher": "Continue",
   "engines": {
     "vscode": "^1.67.0"
diff --git a/extension/react-app/src/components/ComboBox.tsx b/extension/react-app/src/components/ComboBox.tsx
index 7d6541c7..73db33ca 100644
--- a/extension/react-app/src/components/ComboBox.tsx
+++ b/extension/react-app/src/components/ComboBox.tsx
@@ -1,29 +1,16 @@
-import React, {
-  useCallback,
-  useEffect,
-  useImperativeHandle,
-  useState,
-} from "react";
+import React, { useEffect, useImperativeHandle, useState } from "react";
 import { useCombobox } from "downshift";
 import styled from "styled-components";
 import {
-  buttonColor,
   defaultBorderRadius,
   lightGray,
   secondaryDark,
   vscBackground,
 } from ".";
 import CodeBlock from "./CodeBlock";
-import { RangeInFile } from "../../../src/client";
 import PillButton from "./PillButton";
 import HeaderButtonWithText from "./HeaderButtonWithText";
-import {
-  Trash,
-  LockClosed,
-  LockOpen,
-  Plus,
-  DocumentPlus,
-} from "@styled-icons/heroicons-outline";
+import { DocumentPlus } from "@styled-icons/heroicons-outline";
 import { HighlightedRangeContext } from "../../../schema/FullState";
 
 // #region styled components
diff --git a/extension/react-app/src/components/Onboarding.tsx b/extension/react-app/src/components/Onboarding.tsx
index e2dd6f57..6bfb0ccd 100644
--- a/extension/react-app/src/components/Onboarding.tsx
+++ b/extension/react-app/src/components/Onboarding.tsx
@@ -22,6 +22,7 @@ const StyledSpan = styled.span`
   &:hover {
     background-color: #ffffff33;
   }
+  white-space: nowrap;
 `;
 
 const Onboarding = () => {
-- 
cgit v1.2.3-70-g09d2


From 39cd2ef27d6ed439b00a9edec4a487343ff1c2c9 Mon Sep 17 00:00:00 2001
From: Nate Sesti <sestinj@gmail.com>
Date: Fri, 14 Jul 2023 03:24:46 -0700
Subject: warn of large highlighted ranges, cmd+k->m

---
 continuedev/src/continuedev/core/policy.py        |   2 +-
 continuedev/src/continuedev/steps/help.py         |   2 +-
 extension/package-lock.json                       |   4 +-
 extension/package.json                            |   6 +-
 extension/react-app/src/components/ComboBox.tsx   |   5 +
 extension/react-app/src/components/Onboarding.tsx |   1 +
 extension/react-app/src/components/PillButton.tsx | 167 +++++++++++++---------
 extension/react-app/src/pages/gui.tsx             |  27 ++--
 extension/src/commands.ts                         |  17 ++-
 extension/src/lang-server/codeLens.ts             |   4 +-
 10 files changed, 141 insertions(+), 94 deletions(-)

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

diff --git a/continuedev/src/continuedev/core/policy.py b/continuedev/src/continuedev/core/policy.py
index 59ea78b1..bc897357 100644
--- a/continuedev/src/continuedev/core/policy.py
+++ b/continuedev/src/continuedev/core/policy.py
@@ -59,7 +59,7 @@ class DemoPolicy(Policy):
             return (
                 MessageStep(name="Welcome to Continue", message=dedent("""\
                     - Highlight code and ask a question or give instructions
-                    - Use `cmd+k` (Mac) / `ctrl+k` (Windows) to open Continue
+                    - Use `cmd+m` (Mac) / `ctrl+m` (Windows) to open Continue
                     - Use `/help` to ask questions about how to use Continue""")) >>
                 WelcomeStep() >>
                 # SetupContinueWorkspaceStep() >>
diff --git a/continuedev/src/continuedev/steps/help.py b/continuedev/src/continuedev/steps/help.py
index 2dc3647c..ba1e6087 100644
--- a/continuedev/src/continuedev/steps/help.py
+++ b/continuedev/src/continuedev/steps/help.py
@@ -19,7 +19,7 @@ help = dedent("""\
 
         Continue passes all of the sections of code you highlight, the code above and below the to-be edited highlighted code section, and all previous steps above input box as context to the LLM.
 
-        You can use cmd+k (Mac) / ctrl+k (Windows) to open Continue. You can use cmd+shift+e / ctrl+shift+e to open file Explorer. You can add your own OpenAI API key to VS Code Settings with `cmd+,`
+        You can use cmd+m (Mac) / ctrl+m (Windows) to open Continue. You can use cmd+shift+e / ctrl+shift+e to open file Explorer. You can add your own OpenAI API key to VS Code Settings with `cmd+,`
 
         If Continue is stuck loading, try using `cmd+shift+p` to open the command palette, search "Reload Window", and then select it. This will reload VS Code and Continue and often fixes issues.
 
diff --git a/extension/package-lock.json b/extension/package-lock.json
index 9d5c73e1..a79dd6b4 100644
--- a/extension/package-lock.json
+++ b/extension/package-lock.json
@@ -1,12 +1,12 @@
 {
   "name": "continue",
-  "version": "0.0.163",
+  "version": "0.0.164",
   "lockfileVersion": 2,
   "requires": true,
   "packages": {
     "": {
       "name": "continue",
-      "version": "0.0.163",
+      "version": "0.0.164",
       "license": "Apache-2.0",
       "dependencies": {
         "@electron/rebuild": "^3.2.10",
diff --git a/extension/package.json b/extension/package.json
index 2b0f6b94..de1f395d 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.163",
+  "version": "0.0.164",
   "publisher": "Continue",
   "engines": {
     "vscode": "^1.67.0"
@@ -111,8 +111,8 @@
     "keybindings": [
       {
         "command": "continue.focusContinueInput",
-        "mac": "cmd+k",
-        "key": "ctrl+k"
+        "mac": "cmd+m",
+        "key": "ctrl+m"
       },
       {
         "command": "continue.suggestionDown",
diff --git a/extension/react-app/src/components/ComboBox.tsx b/extension/react-app/src/components/ComboBox.tsx
index 73db33ca..bd0d59b5 100644
--- a/extension/react-app/src/components/ComboBox.tsx
+++ b/extension/react-app/src/components/ComboBox.tsx
@@ -228,6 +228,11 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
         )} */}
         {highlightedCodeSections.map((section, idx) => (
           <PillButton
+            warning={
+              section.range.contents.length > 4000 && section.editing
+                ? "Editing such a large range may be slow"
+                : undefined
+            }
             editing={section.editing}
             pinned={section.pinned}
             index={idx}
diff --git a/extension/react-app/src/components/Onboarding.tsx b/extension/react-app/src/components/Onboarding.tsx
index 6bfb0ccd..231c1e93 100644
--- a/extension/react-app/src/components/Onboarding.tsx
+++ b/extension/react-app/src/components/Onboarding.tsx
@@ -109,6 +109,7 @@ const Onboarding = () => {
             paddingBottom: "50px",
             textAlign: "center",
             cursor: "pointer",
+            whiteSpace: "nowrap",
           }}
         >
           <StyledSpan
diff --git a/extension/react-app/src/components/PillButton.tsx b/extension/react-app/src/components/PillButton.tsx
index 31d98c0f..d9d779d1 100644
--- a/extension/react-app/src/components/PillButton.tsx
+++ b/extension/react-app/src/components/PillButton.tsx
@@ -1,12 +1,11 @@
 import { useContext, useState } from "react";
 import styled from "styled-components";
+import { StyledTooltip, defaultBorderRadius, secondaryDark } from ".";
 import {
-  StyledTooltip,
-  defaultBorderRadius,
-  lightGray,
-  secondaryDark,
-} from ".";
-import { Trash, PaintBrush, MapPin } from "@styled-icons/heroicons-outline";
+  Trash,
+  PaintBrush,
+  ExclamationTriangle,
+} from "@styled-icons/heroicons-outline";
 import { GUIClientContext } from "../App";
 
 const Button = styled.button`
@@ -31,7 +30,6 @@ const GridDiv = styled.div`
   grid-template-columns: 1fr 1fr;
   align-items: center;
   border-radius: ${defaultBorderRadius};
-  overflow: hidden;
 
   background-color: ${secondaryDark};
 `;
@@ -48,6 +46,21 @@ const ButtonDiv = styled.div<{ backgroundColor: string }>`
   }
 `;
 
+const CircleDiv = styled.div`
+  position: absolute;
+  top: -10px;
+  right: -10px;
+  width: 20px;
+  height: 20px;
+  border-radius: 50%;
+  background-color: red;
+  color: white;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  padding: 2px;
+`;
+
 interface PillButtonProps {
   onHover?: (arg0: boolean) => void;
   onDelete?: () => void;
@@ -55,6 +68,7 @@ interface PillButtonProps {
   index: number;
   editing: boolean;
   pinned: boolean;
+  warning?: string;
 }
 
 const PillButton = (props: PillButtonProps) => {
@@ -63,75 +77,96 @@ const PillButton = (props: PillButtonProps) => {
 
   return (
     <>
-      <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>
+      <div style={{ position: "relative" }}>
+        <Button
+          style={{
+            position: "relative",
+            borderColor: props.warning
+              ? "red"
+              : 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
+              {/* <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 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 (with rest of file as context)"
+            : "Edit this range"}
+        </StyledTooltip>
+        <StyledTooltip id={`delete-${props.index}`}>Delete</StyledTooltip>
+        {props.warning && (
+          <>
+            <CircleDiv data-tooltip-id={`circle-div-${props.title}`}>
+              <ExclamationTriangle
+                style={{ margin: "auto" }}
+                width="1.0em"
+                strokeWidth={2}
+              />
+            </CircleDiv>
+            <StyledTooltip id={`circle-div-${props.title}`}>
+              {props.warning}
             </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 (with rest of file as context)"
-          : "Edit this range"}
-      </StyledTooltip>
-      <StyledTooltip id={`delete-${props.index}`}>Delete</StyledTooltip>
+      </div>
     </>
   );
 };
diff --git a/extension/react-app/src/pages/gui.tsx b/extension/react-app/src/pages/gui.tsx
index 4ff260fa..57cebac3 100644
--- a/extension/react-app/src/pages/gui.tsx
+++ b/extension/react-app/src/pages/gui.tsx
@@ -95,11 +95,8 @@ function GUI(props: GUIProps) {
           name: "Welcome to Continue",
           hide: false,
           description: `- Highlight code and ask a question or give instructions
-- Use \`cmd+k\` (Mac) / \`ctrl+k\` (Windows) to open Continue
-- Use \`cmd+shift+e\` / \`ctrl+shift+e\` to open file Explorer
-- Add your own OpenAI API key to VS Code Settings with \`cmd+,\`
-- Use slash commands when you want fine-grained control
-- Past steps are included as part of the context by default`,
+          - Use \`cmd+m\` (Mac) / \`ctrl+m\` (Windows) to open Continue
+          - Use \`/help\` to ask questions about how to use Continue`,
           system_message: null,
           chat_context: [],
           manage_own_chat_context: false,
@@ -269,15 +266,17 @@ function GUI(props: GUIProps) {
   return (
     <>
       <Onboarding />
-      <TextDialog showDialog={showFeedbackDialog}
-      onEnter={(text) => {
-        client?.sendMainInput(`/feedback ${text}`);
-        setShowFeedbackDialog(false);
-      }}
-      onClose={() => {
-        setShowFeedbackDialog(false);
-      }}
-      message={feedbackDialogMessage} />
+      <TextDialog
+        showDialog={showFeedbackDialog}
+        onEnter={(text) => {
+          client?.sendMainInput(`/feedback ${text}`);
+          setShowFeedbackDialog(false);
+        }}
+        onClose={() => {
+          setShowFeedbackDialog(false);
+        }}
+        message={feedbackDialogMessage}
+      />
 
       <TopGUIDiv
         ref={topGuiDivRef}
diff --git a/extension/src/commands.ts b/extension/src/commands.ts
index 0b002549..0025340a 100644
--- a/extension/src/commands.ts
+++ b/extension/src/commands.ts
@@ -19,6 +19,8 @@ import { debugPanelWebview } from "./debugPanel";
 import { sendTelemetryEvent, TelemetryEvent } from "./telemetry";
 import { ideProtocolClient } from "./activation/activate";
 
+let focusedOnContinueInput = false;
+
 // Copy everything over from extension.ts
 const commandsMap: { [command: string]: (...args: any) => any } = {
   "continue.suggestionDown": suggestionDownCommand,
@@ -30,10 +32,15 @@ const commandsMap: { [command: string]: (...args: any) => any } = {
   "continue.acceptAllSuggestions": acceptAllSuggestionsCommand,
   "continue.rejectAllSuggestions": rejectAllSuggestionsCommand,
   "continue.focusContinueInput": async () => {
-    vscode.commands.executeCommand("continue.continueGUIView.focus");
-    debugPanelWebview?.postMessage({
-      type: "focusContinueInput",
-    });
+    if (focusedOnContinueInput) {
+      vscode.commands.executeCommand("workbench.action.focusActiveEditorGroup");
+    } else {
+      vscode.commands.executeCommand("continue.continueGUIView.focus");
+      debugPanelWebview?.postMessage({
+        type: "focusContinueInput",
+      });
+    }
+    focusedOnContinueInput = !focusedOnContinueInput;
   },
   "continue.quickTextEntry": async () => {
     const text = await vscode.window.showInputBox({
@@ -53,4 +60,4 @@ export function registerAllCommands(context: vscode.ExtensionContext) {
       vscode.commands.registerCommand(command, callback)
     );
   }
-}
\ No newline at end of file
+}
diff --git a/extension/src/lang-server/codeLens.ts b/extension/src/lang-server/codeLens.ts
index 5800a00e..1cfef5d5 100644
--- a/extension/src/lang-server/codeLens.ts
+++ b/extension/src/lang-server/codeLens.ts
@@ -60,12 +60,12 @@ class DiffViewerCodeLensProvider implements vscode.CodeLensProvider {
       }
       codeLenses.push(
         new vscode.CodeLens(range, {
-          title: "Accept ✅ (⌘⇧↩)",
+          title: "Accept All ✅ (⌘⇧↩)",
           command: "continue.acceptDiff",
           arguments: [document.uri.fsPath],
         }),
         new vscode.CodeLens(range, {
-          title: "Reject ❌ (⌘⇧⌫)",
+          title: "Reject All ❌ (⌘⇧⌫)",
           command: "continue.rejectDiff",
           arguments: [document.uri.fsPath],
         })
-- 
cgit v1.2.3-70-g09d2


From b19076ddb6d11acb5ffd54046d9e5cad549c00c1 Mon Sep 17 00:00:00 2001
From: Nate Sesti <sestinj@gmail.com>
Date: Fri, 14 Jul 2023 11:01:06 -0700
Subject: command m reliable toggle

---
 extension/package-lock.json                     |  4 ++--
 extension/package.json                          |  2 +-
 extension/react-app/src/components/ComboBox.tsx |  4 ++++
 extension/src/commands.ts                       |  5 ++++-
 extension/src/debugPanel.ts                     |  5 +++++
 extension/src/diffs.ts                          | 21 ++++++++++++---------
 6 files changed, 28 insertions(+), 13 deletions(-)

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

diff --git a/extension/package-lock.json b/extension/package-lock.json
index a79dd6b4..12aa27c9 100644
--- a/extension/package-lock.json
+++ b/extension/package-lock.json
@@ -1,12 +1,12 @@
 {
   "name": "continue",
-  "version": "0.0.164",
+  "version": "0.0.165",
   "lockfileVersion": 2,
   "requires": true,
   "packages": {
     "": {
       "name": "continue",
-      "version": "0.0.164",
+      "version": "0.0.165",
       "license": "Apache-2.0",
       "dependencies": {
         "@electron/rebuild": "^3.2.10",
diff --git a/extension/package.json b/extension/package.json
index de1f395d..05bd4d84 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.164",
+  "version": "0.0.165",
   "publisher": "Continue",
   "engines": {
     "vscode": "^1.67.0"
diff --git a/extension/react-app/src/components/ComboBox.tsx b/extension/react-app/src/components/ComboBox.tsx
index bd0d59b5..5d9b5109 100644
--- a/extension/react-app/src/components/ComboBox.tsx
+++ b/extension/react-app/src/components/ComboBox.tsx
@@ -12,6 +12,7 @@ import PillButton from "./PillButton";
 import HeaderButtonWithText from "./HeaderButtonWithText";
 import { DocumentPlus } from "@styled-icons/heroicons-outline";
 import { HighlightedRangeContext } from "../../../schema/FullState";
+import { postVscMessage } from "../vscode";
 
 // #region styled components
 const mainInputFontSize = 13;
@@ -297,6 +298,9 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
 
               // setShowContextDropdown(target.value.endsWith("@"));
             },
+            onBlur: (e) => {
+              postVscMessage("blurContinueInput", {});
+            },
             onKeyDown: (event) => {
               if (event.key === "Enter" && event.shiftKey) {
                 // Prevent Downshift's default 'Enter' behavior.
diff --git a/extension/src/commands.ts b/extension/src/commands.ts
index 0025340a..888f01ed 100644
--- a/extension/src/commands.ts
+++ b/extension/src/commands.ts
@@ -16,11 +16,14 @@ import {
 import { acceptDiffCommand, rejectDiffCommand } from "./diffs";
 import * as bridge from "./bridge";
 import { debugPanelWebview } from "./debugPanel";
-import { sendTelemetryEvent, TelemetryEvent } from "./telemetry";
 import { ideProtocolClient } from "./activation/activate";
 
 let focusedOnContinueInput = false;
 
+export const setFocusedOnContinueInput = (value: boolean) => {
+  focusedOnContinueInput = value;
+};
+
 // Copy everything over from extension.ts
 const commandsMap: { [command: string]: (...args: any) => any } = {
   "continue.suggestionDown": suggestionDownCommand,
diff --git a/extension/src/debugPanel.ts b/extension/src/debugPanel.ts
index 5e1689d1..dd24a8d8 100644
--- a/extension/src/debugPanel.ts
+++ b/extension/src/debugPanel.ts
@@ -6,6 +6,7 @@ import {
   openEditorAndRevealRange,
 } from "./util/vscode";
 import { RangeInFile } from "./client";
+import { setFocusedOnContinueInput } from "./commands";
 const WebSocket = require("ws");
 
 let websocketConnections: { [url: string]: WebsocketConnection | undefined } =
@@ -226,6 +227,10 @@ export function setupDebugPanel(
         openEditorAndRevealRange(data.path, undefined, vscode.ViewColumn.One);
         break;
       }
+      case "blurContinueInput": {
+        setFocusedOnContinueInput(false);
+        break;
+      }
       case "withProgress": {
         // This message allows withProgress to be used in the webview
         if (data.done) {
diff --git a/extension/src/diffs.ts b/extension/src/diffs.ts
index 910c30f2..37943de4 100644
--- a/extension/src/diffs.ts
+++ b/extension/src/diffs.ts
@@ -104,6 +104,17 @@ class DiffManager {
     return editor;
   }
 
+  private _findFirstDifferentLine(contentA: string, contentB: string): number {
+    const linesA = contentA.split("\n");
+    const linesB = contentB.split("\n");
+    for (let i = 0; i < linesA.length && i < linesB.length; i++) {
+      if (linesA[i] !== linesB[i]) {
+        return i;
+      }
+    }
+    return 0;
+  }
+
   writeDiff(
     originalFilepath: string,
     newContent: string,
@@ -119,15 +130,7 @@ class DiffManager {
     if (!this.diffs.has(newFilepath)) {
       // Figure out the first line that is different
       const oldContent = fs.readFileSync(originalFilepath).toString("utf-8");
-      let line = 0;
-      const newLines = newContent.split("\n");
-      const oldLines = oldContent.split("\n");
-      for (let i = 0; i < newLines.length && i < oldLines.length; i++) {
-        if (newLines[i] !== oldLines[i]) {
-          line = i;
-          break;
-        }
-      }
+      const line = this._findFirstDifferentLine(oldContent, newContent);
 
       const diffInfo: DiffInfo = {
         originalFilepath,
-- 
cgit v1.2.3-70-g09d2


From c5102b0997baa81ce544514d6b5b4d5a2eae804f Mon Sep 17 00:00:00 2001
From: Nate Sesti <sestinj@gmail.com>
Date: Fri, 14 Jul 2023 13:45:10 -0700
Subject: insidious client_state vs application_state err

---
 continuedev/src/continuedev/core/autopilot.py        | 2 ++
 continuedev/src/continuedev/server/gui.py            | 2 +-
 continuedev/src/continuedev/server/ide.py            | 2 +-
 continuedev/src/continuedev/steps/core/core.py       | 9 ++++++++-
 extension/react-app/src/components/ComboBox.tsx      | 9 ++++++++-
 extension/react-app/src/components/StepContainer.tsx | 9 ++++++---
 extension/src/continueIdeClient.ts                   | 8 ++++++--
 extension/src/diffs.ts                               | 2 +-
 extension/src/util/messenger.ts                      | 2 +-
 9 files changed, 34 insertions(+), 11 deletions(-)

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

diff --git a/continuedev/src/continuedev/core/autopilot.py b/continuedev/src/continuedev/core/autopilot.py
index e1c8a076..82439f49 100644
--- a/continuedev/src/continuedev/core/autopilot.py
+++ b/continuedev/src/continuedev/core/autopilot.py
@@ -37,6 +37,8 @@ def get_error_title(e: Exception) -> str:
         return "The request failed. Please check your internet connection and try again. If this issue persists, you can use our API key for free by going to VS Code settings and changing the value of continue.OPENAI_API_KEY to \"\""
     elif isinstance(e, openai_errors.InvalidRequestError):
         return 'Your API key does not have access to GPT-4. You can use ours for free by going to VS Code settings and changing the value of continue.OPENAI_API_KEY to ""'
+    elif e.__str__().startswith("Cannot connect to host"):
+        return "The request failed. Please check your internet connection and try again."
     return e.__str__() or e.__repr__()
 
 
diff --git a/continuedev/src/continuedev/server/gui.py b/continuedev/src/continuedev/server/gui.py
index 238273b2..9a411fbe 100644
--- a/continuedev/src/continuedev/server/gui.py
+++ b/continuedev/src/continuedev/server/gui.py
@@ -53,7 +53,7 @@ class GUIProtocolServer(AbstractGUIProtocolServer):
         self.session = session
 
     async def _send_json(self, message_type: str, data: Any):
-        if self.websocket.client_state == WebSocketState.DISCONNECTED:
+        if self.websocket.application_state == WebSocketState.DISCONNECTED:
             return
         await self.websocket.send_json({
             "messageType": message_type,
diff --git a/continuedev/src/continuedev/server/ide.py b/continuedev/src/continuedev/server/ide.py
index 73cce201..7875c94d 100644
--- a/continuedev/src/continuedev/server/ide.py
+++ b/continuedev/src/continuedev/server/ide.py
@@ -149,7 +149,7 @@ class IdeProtocolServer(AbstractIdeProtocolServer):
         return other_msgs
 
     async def _send_json(self, message_type: str, data: Any):
-        if self.websocket.client_state == WebSocketState.DISCONNECTED:
+        if self.websocket.application_state == WebSocketState.DISCONNECTED:
             return
         await self.websocket.send_json({
             "messageType": message_type,
diff --git a/continuedev/src/continuedev/steps/core/core.py b/continuedev/src/continuedev/steps/core/core.py
index 787da316..75f8e460 100644
--- a/continuedev/src/continuedev/steps/core/core.py
+++ b/continuedev/src/continuedev/steps/core/core.py
@@ -9,7 +9,7 @@ from ...libs.llm.prompt_utils import MarkdownStyleEncoderDecoder
 from ...models.filesystem_edit import EditDiff, FileEdit, FileEditWithFullContents, FileSystemEdit
 from ...models.filesystem import FileSystem, RangeInFile, RangeInFileWithContents
 from ...core.observation import Observation, TextObservation, TracebackObservation, UserInputObservation
-from ...core.main import ChatMessage, Step, SequentialStep
+from ...core.main import ChatMessage, ContinueCustomException, Step, SequentialStep
 from ...libs.util.count_tokens import MAX_TOKENS_FOR_MODEL, DEFAULT_MAX_TOKENS
 from ...libs.util.dedent import dedent_and_get_common_whitespace
 import difflib
@@ -608,6 +608,13 @@ Please output the code to be inserted at the cursor in order to fulfill the user
             rif_dict[rif.filepath] = rif.contents
 
         for rif in rif_with_contents:
+            # If the file doesn't exist, ask them to save it first
+            if not os.path.exists(rif.filepath):
+                message = f"The file {rif.filepath} does not exist. Please save it first."
+                raise ContinueCustomException(
+                    title=message, message=message
+                )
+
             await sdk.ide.setFileOpen(rif.filepath)
             await sdk.ide.setSuggestionsLocked(rif.filepath, True)
             await self.stream_rif(rif, sdk)
diff --git a/extension/react-app/src/components/ComboBox.tsx b/extension/react-app/src/components/ComboBox.tsx
index 5d9b5109..754c9445 100644
--- a/extension/react-app/src/components/ComboBox.tsx
+++ b/extension/react-app/src/components/ComboBox.tsx
@@ -169,6 +169,7 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
   useImperativeHandle(ref, () => downshiftProps, [downshiftProps]);
 
   const [metaKeyPressed, setMetaKeyPressed] = useState(false);
+  const [focused, setFocused] = useState(false);
   useEffect(() => {
     const handleKeyDown = (e: KeyboardEvent) => {
       if (e.key === "Meta") {
@@ -298,7 +299,11 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
 
               // setShowContextDropdown(target.value.endsWith("@"));
             },
+            onFocus: (e) => {
+              setFocused(true);
+            },
             onBlur: (e) => {
+              setFocused(false);
               postVscMessage("blurContinueInput", {});
             },
             onKeyDown: (event) => {
@@ -374,7 +379,9 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
       </div>
       {highlightedCodeSections.length === 0 &&
         (downshiftProps.inputValue?.startsWith("/edit") ||
-          (metaKeyPressed && downshiftProps.inputValue?.length > 0)) && (
+          (focused &&
+            metaKeyPressed &&
+            downshiftProps.inputValue?.length > 0)) && (
           <div className="text-trueGray-400 pr-4 text-xs text-right">
             Inserting at cursor
           </div>
diff --git a/extension/react-app/src/components/StepContainer.tsx b/extension/react-app/src/components/StepContainer.tsx
index 6fa4ba13..14e9b854 100644
--- a/extension/react-app/src/components/StepContainer.tsx
+++ b/extension/react-app/src/components/StepContainer.tsx
@@ -253,9 +253,12 @@ function StepContainer(props: StepContainerProps) {
           )}
 
           {props.historyNode.observation?.error ? (
-            <pre className="overflow-x-scroll">
-              {props.historyNode.observation.error as string}
-            </pre>
+            <details>
+              <summary>View Traceback</summary>
+              <pre className="overflow-x-scroll">
+                {props.historyNode.observation.error as string}
+              </pre>
+            </details>
           ) : (
             <StyledMarkdownPreview
               source={props.historyNode.step.description || ""}
diff --git a/extension/src/continueIdeClient.ts b/extension/src/continueIdeClient.ts
index 4c1fdf1e..6dd117d3 100644
--- a/extension/src/continueIdeClient.ts
+++ b/extension/src/continueIdeClient.ts
@@ -386,8 +386,12 @@ class IdeProtocolClient {
         contents = editor.document.getText();
       }
     });
-    if (!contents) {
-      contents = fs.readFileSync(filepath, "utf-8");
+    if (typeof contents === "undefined") {
+      if (fs.existsSync(filepath)) {
+        contents = fs.readFileSync(filepath, "utf-8");
+      } else {
+        contents = "";
+      }
     }
     return contents;
   }
diff --git a/extension/src/diffs.ts b/extension/src/diffs.ts
index 37943de4..d04f9bdb 100644
--- a/extension/src/diffs.ts
+++ b/extension/src/diffs.ts
@@ -129,7 +129,7 @@ class DiffManager {
     // Open the diff editor if this is a new diff
     if (!this.diffs.has(newFilepath)) {
       // Figure out the first line that is different
-      const oldContent = fs.readFileSync(originalFilepath).toString("utf-8");
+      const oldContent = ideProtocolClient.readFile(originalFilepath);
       const line = this._findFirstDifferentLine(oldContent, newContent);
 
       const diffInfo: DiffInfo = {
diff --git a/extension/src/util/messenger.ts b/extension/src/util/messenger.ts
index 7fd71ddd..3044898e 100644
--- a/extension/src/util/messenger.ts
+++ b/extension/src/util/messenger.ts
@@ -15,7 +15,7 @@ export abstract class Messenger {
   abstract onOpen(callback: () => void): void;
 
   abstract onClose(callback: () => void): void;
-  
+
   abstract onError(callback: () => void): void;
 
   abstract sendAndReceive(messageType: string, data: any): Promise<any>;
-- 
cgit v1.2.3-70-g09d2


From 45ee33f7fd84c0bc49d35d9d1a7a3a8e9f6addd7 Mon Sep 17 00:00:00 2001
From: Nate Sesti <sestinj@gmail.com>
Date: Sat, 15 Jul 2023 15:06:32 -0700
Subject: use correct label for meta key

---
 extension/react-app/src/components/ComboBox.tsx    |  3 ++-
 .../react-app/src/components/StepContainer.tsx     |  7 +++++-
 extension/react-app/src/util/index.ts              | 17 +++++++++++--
 extension/src/diffs.ts                             |  3 ++-
 extension/src/lang-server/codeLens.ts              |  7 +++---
 extension/src/util/util.ts                         | 29 ++++++++++++++++++++++
 6 files changed, 58 insertions(+), 8 deletions(-)

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

diff --git a/extension/react-app/src/components/ComboBox.tsx b/extension/react-app/src/components/ComboBox.tsx
index 754c9445..f11e07af 100644
--- a/extension/react-app/src/components/ComboBox.tsx
+++ b/extension/react-app/src/components/ComboBox.tsx
@@ -13,6 +13,7 @@ import HeaderButtonWithText from "./HeaderButtonWithText";
 import { DocumentPlus } from "@styled-icons/heroicons-outline";
 import { HighlightedRangeContext } from "../../../schema/FullState";
 import { postVscMessage } from "../vscode";
+import { getMetaKeyLabel } from "../util";
 
 // #region styled components
 const mainInputFontSize = 13;
@@ -286,7 +287,7 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
       <div className="flex px-2" ref={divRef} hidden={!downshiftProps.isOpen}>
         <MainTextInput
           disabled={props.disabled}
-          placeholder="Ask a question, give instructions, or type '/' to see slash commands. ⌘⏎ to edit."
+          placeholder={`Ask a question, give instructions, or type '/' to see slash commands. ${getMetaKeyLabel()}⏎ to edit.`}
           {...getInputProps({
             onChange: (e) => {
               const target = e.target as HTMLTextAreaElement;
diff --git a/extension/react-app/src/components/StepContainer.tsx b/extension/react-app/src/components/StepContainer.tsx
index 7f23e333..93bdbc89 100644
--- a/extension/react-app/src/components/StepContainer.tsx
+++ b/extension/react-app/src/components/StepContainer.tsx
@@ -17,6 +17,7 @@ import { StopCircle } from "@styled-icons/heroicons-solid";
 import { HistoryNode } from "../../../schema/HistoryNode";
 import HeaderButtonWithText from "./HeaderButtonWithText";
 import MarkdownPreview from "@uiw/react-markdown-preview";
+import { getMetaKeyLabel, isMetaEquivalentKeyPressed } from "../util";
 
 interface StepContainerProps {
   historyNode: HistoryNode;
@@ -217,7 +218,11 @@ function StepContainer(props: StepContainerProps) {
                   e.stopPropagation();
                   props.onDelete();
                 }}
-                text={props.historyNode.active ? "Stop (⌘⌫)" : "Delete"}
+                text={
+                  props.historyNode.active
+                    ? `Stop (${getMetaKeyLabel()}⌫)`
+                    : "Delete"
+                }
               >
                 {props.historyNode.active ? (
                   <StopCircle size="1.6em" onClick={props.onDelete} />
diff --git a/extension/react-app/src/util/index.ts b/extension/react-app/src/util/index.ts
index ad711321..c4168e13 100644
--- a/extension/react-app/src/util/index.ts
+++ b/extension/react-app/src/util/index.ts
@@ -1,6 +1,6 @@
 type Platform = "mac" | "linux" | "windows" | "unknown";
 
-function getPlatform(): Platform {
+export function getPlatform(): Platform {
   const platform = window.navigator.platform.toUpperCase();
   if (platform.indexOf("MAC") >= 0) {
     return "mac";
@@ -13,7 +13,7 @@ function getPlatform(): Platform {
   }
 }
 
-function isMetaEquivalentKeyPressed(event: {
+export function isMetaEquivalentKeyPressed(event: {
   metaKey: boolean;
   ctrlKey: boolean;
 }): boolean {
@@ -28,3 +28,16 @@ function isMetaEquivalentKeyPressed(event: {
       return event.metaKey;
   }
 }
+
+export function getMetaKeyLabel(): string {
+  const platform = getPlatform();
+  switch (platform) {
+    case "mac":
+      return "⌘";
+    case "linux":
+    case "windows":
+      return "^";
+    default:
+      return "⌘";
+  }
+}
diff --git a/extension/src/diffs.ts b/extension/src/diffs.ts
index d04f9bdb..9d0c9fe7 100644
--- a/extension/src/diffs.ts
+++ b/extension/src/diffs.ts
@@ -3,6 +3,7 @@ import * as path from "path";
 import * as fs from "fs";
 import * as vscode from "vscode";
 import { extensionContext, ideProtocolClient } from "./activation/activate";
+import { getMetaKeyLabel } from "./util/util";
 
 interface DiffInfo {
   originalFilepath: string;
@@ -86,7 +87,7 @@ class DiffManager {
     ) {
       vscode.window
         .showInformationMessage(
-          "Accept (⌘⇧↩) or reject (⌘⇧⌫) at the top of the file.",
+          `Accept (${getMetaKeyLabel()}⇧↩) or reject (${getMetaKeyLabel()}⇧⌫) at the top of the file.`,
           "Got it",
           "Don't show again"
         )
diff --git a/extension/src/lang-server/codeLens.ts b/extension/src/lang-server/codeLens.ts
index 1cfef5d5..ba80e557 100644
--- a/extension/src/lang-server/codeLens.ts
+++ b/extension/src/lang-server/codeLens.ts
@@ -3,6 +3,7 @@ import { editorToSuggestions, editorSuggestionsLocked } from "../suggestions";
 import * as path from "path";
 import * as os from "os";
 import { DIFF_DIRECTORY, diffManager } from "../diffs";
+import { getMetaKeyLabel } from "../util/util";
 class SuggestionsCodeLensProvider implements vscode.CodeLensProvider {
   public provideCodeLenses(
     document: vscode.TextDocument,
@@ -35,7 +36,7 @@ class SuggestionsCodeLensProvider implements vscode.CodeLensProvider {
       if (codeLenses.length === 2) {
         codeLenses.push(
           new vscode.CodeLens(range, {
-            title: "(⌘⇧↩/⌘⇧⌫ to accept/reject all)",
+            title: `(${getMetaKeyLabel()}⇧↩/${getMetaKeyLabel()}⇧⌫ to accept/reject all)`,
             command: "",
           })
         );
@@ -60,12 +61,12 @@ class DiffViewerCodeLensProvider implements vscode.CodeLensProvider {
       }
       codeLenses.push(
         new vscode.CodeLens(range, {
-          title: "Accept All ✅ (⌘⇧↩)",
+          title: `Accept All ✅ (${getMetaKeyLabel()}⇧↩)`,
           command: "continue.acceptDiff",
           arguments: [document.uri.fsPath],
         }),
         new vscode.CodeLens(range, {
-          title: "Reject All ❌ (⌘⇧⌫)",
+          title: `Reject All ❌ (${getMetaKeyLabel()}⇧⌫)`,
           command: "continue.rejectDiff",
           arguments: [document.uri.fsPath],
         })
diff --git a/extension/src/util/util.ts b/extension/src/util/util.ts
index d33593e1..dfc10c90 100644
--- a/extension/src/util/util.ts
+++ b/extension/src/util/util.ts
@@ -1,5 +1,6 @@
 import { RangeInFile, SerializedDebugContext } from "../client";
 import * as fs from "fs";
+const os = require("os");
 
 function charIsEscapedAtIndex(index: number, str: string): boolean {
   if (index === 0) return false;
@@ -113,3 +114,31 @@ export function debounced(delay: number, fn: Function) {
     }, delay);
   };
 }
+
+type Platform = "mac" | "linux" | "windows" | "unknown";
+
+function getPlatform(): Platform {
+  const platform = os.platform();
+  if (platform === "darwin") {
+    return "mac";
+  } else if (platform === "linux") {
+    return "linux";
+  } else if (platform === "win32") {
+    return "windows";
+  } else {
+    return "unknown";
+  }
+}
+
+export function getMetaKeyLabel() {
+  const platform = getPlatform();
+  switch (platform) {
+    case "mac":
+      return "⌘";
+    case "linux":
+    case "windows":
+      return "^";
+    default:
+      return "⌘";
+  }
+}
-- 
cgit v1.2.3-70-g09d2


From c3a5010c7e2b49022c08f8fec113d4fdf21e0438 Mon Sep 17 00:00:00 2001
From: Nate Sesti <sestinj@gmail.com>
Date: Sun, 16 Jul 2023 23:48:57 -0700
Subject: fix alignment of dropdown

---
 extension/react-app/src/components/ComboBox.tsx | 49 +------------------------
 1 file changed, 2 insertions(+), 47 deletions(-)

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

diff --git a/extension/react-app/src/components/ComboBox.tsx b/extension/react-app/src/components/ComboBox.tsx
index f11e07af..773fcf72 100644
--- a/extension/react-app/src/components/ComboBox.tsx
+++ b/extension/react-app/src/components/ComboBox.tsx
@@ -37,21 +37,6 @@ const EmptyPillDiv = styled.div`
   }
 `;
 
-const ContextDropdown = styled.div`
-  position: absolute;
-  padding: 4px;
-  width: calc(100% - 16px - 8px);
-  background-color: ${secondaryDark};
-  color: white;
-  border-bottom-right-radius: ${defaultBorderRadius};
-  border-bottom-left-radius: ${defaultBorderRadius};
-  /* border: 1px solid white; */
-  border-top: none;
-  margin: 8px;
-  outline: 1px solid orange;
-  z-index: 5;
-`;
-
 const MainTextInput = styled.textarea`
   resize: none;
 
@@ -88,12 +73,13 @@ const Ul = styled.ul<{
   background-color: ${secondaryDark};
   color: white;
   max-height: ${UlMaxHeight}px;
+  width: calc(100% - 16px);
   overflow-y: scroll;
   overflow-x: hidden;
   padding: 0;
   ${({ hidden }) => hidden && "display: none;"}
   border-radius: ${defaultBorderRadius};
-  border: 0.5px solid gray;
+  outline: 0.5px solid gray;
   z-index: 2;
   // Get rid of scrollbar and its padding
   scrollbar-width: none;
@@ -138,10 +124,6 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
   // The position of the current command you are typing now, so the one that will be appended to history once you press enter
   const [positionInHistory, setPositionInHistory] = React.useState<number>(0);
   const [items, setItems] = React.useState(props.items);
-  const [hoveringButton, setHoveringButton] = React.useState(false);
-  const [hoveringContextDropdown, setHoveringContextDropdown] =
-    React.useState(false);
-  const [pinned, setPinned] = useState(false);
   const [highlightedCodeSections, setHighlightedCodeSections] = React.useState(
     props.highlightedCodeSections || []
   );
@@ -253,15 +235,6 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
                 return newSections;
               });
             }}
-            onHover={(val: boolean) => {
-              if (val) {
-                setHoveringButton(val);
-              } else {
-                setTimeout(() => {
-                  setHoveringButton(val);
-                }, 100);
-              }
-            }}
           />
         ))}
         {props.highlightedCodeSections.length > 0 &&
@@ -387,24 +360,6 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
             Inserting at cursor
           </div>
         )}
-      <ContextDropdown
-        onMouseEnter={() => {
-          setHoveringContextDropdown(true);
-        }}
-        onMouseLeave={() => {
-          setHoveringContextDropdown(false);
-        }}
-        hidden={true || (!hoveringContextDropdown && !hoveringButton)}
-      >
-        {highlightedCodeSections.map((section, idx) => (
-          <>
-            <p>{section.display_name}</p>
-            <CodeBlock showCopy={false} key={idx}>
-              {section.range.contents}
-            </CodeBlock>
-          </>
-        ))}
-      </ContextDropdown>
     </>
   );
 });
-- 
cgit v1.2.3-70-g09d2


From 88c1f16c597e0a55271e622a5283562ccb7a80a1 Mon Sep 17 00:00:00 2001
From: Nate Sesti <sestinj@gmail.com>
Date: Mon, 17 Jul 2023 00:00:31 -0700
Subject: only show delete when only one range selected

---
 extension/react-app/src/components/ComboBox.tsx   |  2 ++
 extension/react-app/src/components/PillButton.tsx | 34 +++++++++++++----------
 2 files changed, 22 insertions(+), 14 deletions(-)

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

diff --git a/extension/react-app/src/components/ComboBox.tsx b/extension/react-app/src/components/ComboBox.tsx
index 773fcf72..dbebd534 100644
--- a/extension/react-app/src/components/ComboBox.tsx
+++ b/extension/react-app/src/components/ComboBox.tsx
@@ -218,6 +218,7 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
                 ? "Editing such a large range may be slow"
                 : undefined
             }
+            onlyShowDelete={highlightedCodeSections.length <= 1}
             editing={section.editing}
             pinned={section.pinned}
             index={idx}
@@ -334,6 +335,7 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
           })}
           showAbove={showAbove()}
           ulHeightPixels={ulRef.current?.getBoundingClientRect().height || 0}
+          hidden={!downshiftProps.isOpen || items.length === 0}
         >
           {downshiftProps.isOpen &&
             items.map((item, index) => (
diff --git a/extension/react-app/src/components/PillButton.tsx b/extension/react-app/src/components/PillButton.tsx
index d9d779d1..5a16516e 100644
--- a/extension/react-app/src/components/PillButton.tsx
+++ b/extension/react-app/src/components/PillButton.tsx
@@ -27,7 +27,6 @@ const GridDiv = styled.div`
   height: 100%;
   display: grid;
   grid-gap: 0;
-  grid-template-columns: 1fr 1fr;
   align-items: center;
   border-radius: ${defaultBorderRadius};
 
@@ -69,6 +68,7 @@ interface PillButtonProps {
   editing: boolean;
   pinned: boolean;
   warning?: string;
+  onlyShowDelete?: boolean;
 }
 
 const PillButton = (props: PillButtonProps) => {
@@ -105,19 +105,25 @@ const PillButton = (props: PillButtonProps) => {
           }}
         >
           {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>
+            <GridDiv
+              style={{
+                gridTemplateColumns: props.onlyShowDelete ? "1fr" : "1fr 1fr",
+              }}
+            >
+              {props.onlyShowDelete || (
+                <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}`}
-- 
cgit v1.2.3-70-g09d2


From e5b15e38982300dd555006c010bf3e887bf4bd7a Mon Sep 17 00:00:00 2001
From: Ty Dunn <ty@tydunn.com>
Date: Mon, 17 Jul 2023 11:36:21 -0500
Subject: align on `code section`

---
 continuedev/src/continuedev/core/policy.py        | 2 +-
 extension/react-app/src/components/ComboBox.tsx   | 6 +++---
 extension/react-app/src/components/PillButton.tsx | 4 ++--
 3 files changed, 6 insertions(+), 6 deletions(-)

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

diff --git a/continuedev/src/continuedev/core/policy.py b/continuedev/src/continuedev/core/policy.py
index bc897357..d007c92b 100644
--- a/continuedev/src/continuedev/core/policy.py
+++ b/continuedev/src/continuedev/core/policy.py
@@ -58,7 +58,7 @@ class DemoPolicy(Policy):
         if history.get_current() is None:
             return (
                 MessageStep(name="Welcome to Continue", message=dedent("""\
-                    - Highlight code and ask a question or give instructions
+                    - Highlight code section and ask a question or give instructions
                     - Use `cmd+m` (Mac) / `ctrl+m` (Windows) to open Continue
                     - Use `/help` to ask questions about how to use Continue""")) >>
                 WelcomeStep() >>
diff --git a/extension/react-app/src/components/ComboBox.tsx b/extension/react-app/src/components/ComboBox.tsx
index dbebd534..8136399a 100644
--- a/extension/react-app/src/components/ComboBox.tsx
+++ b/extension/react-app/src/components/ComboBox.tsx
@@ -245,11 +245,11 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
                 props.onToggleAddContext();
               }}
             >
-              Highlight to Add Context
+              Highlight code section
             </EmptyPillDiv>
           ) : (
             <HeaderButtonWithText
-              text="Add to Context"
+              text="Add more code to context"
               onClick={() => {
                 props.onToggleAddContext();
               }}
@@ -261,7 +261,7 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
       <div className="flex px-2" ref={divRef} hidden={!downshiftProps.isOpen}>
         <MainTextInput
           disabled={props.disabled}
-          placeholder={`Ask a question, give instructions, or type '/' to see slash commands. ${getMetaKeyLabel()}⏎ to edit.`}
+          placeholder={`Ask a question, give instructions, or type '/' to see slash commands`}
           {...getInputProps({
             onChange: (e) => {
               const target = e.target as HTMLTextAreaElement;
diff --git a/extension/react-app/src/components/PillButton.tsx b/extension/react-app/src/components/PillButton.tsx
index 5a16516e..6bfe6369 100644
--- a/extension/react-app/src/components/PillButton.tsx
+++ b/extension/react-app/src/components/PillButton.tsx
@@ -154,8 +154,8 @@ const PillButton = (props: PillButtonProps) => {
         </Button>
         <StyledTooltip id={`edit-${props.index}`}>
           {props.editing
-            ? "Editing this range (with rest of file as context)"
-            : "Edit this range"}
+            ? "Editing this section (with entire file as context)"
+            : "Edit this section"}
         </StyledTooltip>
         <StyledTooltip id={`delete-${props.index}`}>Delete</StyledTooltip>
         {props.warning && (
-- 
cgit v1.2.3-70-g09d2


From 08221a0879b4a163eab6860524f255dbcb4743ae Mon Sep 17 00:00:00 2001
From: Nate Sesti <sestinj@gmail.com>
Date: Mon, 17 Jul 2023 12:05:03 -0700
Subject: match vscode color theme

---
 continuedev/src/continuedev/libs/util/dedent.py    | 25 -----------
 continuedev/src/continuedev/libs/util/strings.py   | 49 ++++++++++++++++++++++
 continuedev/src/continuedev/steps/chat.py          |  8 ++--
 continuedev/src/continuedev/steps/core/core.py     | 17 ++------
 extension/package-lock.json                        |  4 +-
 extension/package.json                             |  2 +-
 extension/react-app/src/components/ComboBox.tsx    | 10 +++--
 .../react-app/src/components/InputAndButton.tsx    | 10 ++---
 extension/react-app/src/components/PillButton.tsx  |  9 +++-
 .../react-app/src/components/StepContainer.tsx     | 12 ++++--
 extension/react-app/src/components/TextDialog.tsx  | 14 ++++---
 extension/react-app/src/components/index.ts        | 23 ++++++----
 extension/react-app/src/index.css                  |  4 +-
 extension/react-app/src/pages/gui.tsx              | 11 +++--
 14 files changed, 119 insertions(+), 79 deletions(-)
 delete mode 100644 continuedev/src/continuedev/libs/util/dedent.py
 create mode 100644 continuedev/src/continuedev/libs/util/strings.py

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

diff --git a/continuedev/src/continuedev/libs/util/dedent.py b/continuedev/src/continuedev/libs/util/dedent.py
deleted file mode 100644
index e59c2e97..00000000
--- a/continuedev/src/continuedev/libs/util/dedent.py
+++ /dev/null
@@ -1,25 +0,0 @@
-from typing import Tuple
-
-
-def dedent_and_get_common_whitespace(s: str) -> Tuple[str, str]:
-    lines = s.splitlines()
-    if len(lines) == 0:
-        return "", ""
-
-    # Longest common whitespace prefix
-    lcp = lines[0].split(lines[0].strip())[0]
-    # Iterate through the lines
-    for i in range(1, len(lines)):
-        # Empty lines are wildcards
-        if lines[i].strip() == "":
-            continue
-        # Iterate through the leading whitespace characters of the current line
-        for j in range(0, len(lcp)):
-            # If it doesn't have the same whitespace as lcp, then update lcp
-            if j >= len(lines[i]) or lcp[j] != lines[i][j]:
-                lcp = lcp[:j]
-                if lcp == "":
-                    return s, ""
-                break
-
-    return "\n".join(map(lambda x: x.lstrip(lcp), lines)), lcp
diff --git a/continuedev/src/continuedev/libs/util/strings.py b/continuedev/src/continuedev/libs/util/strings.py
new file mode 100644
index 00000000..f1fb8d0b
--- /dev/null
+++ b/continuedev/src/continuedev/libs/util/strings.py
@@ -0,0 +1,49 @@
+from typing import Tuple
+
+
+def dedent_and_get_common_whitespace(s: str) -> Tuple[str, str]:
+    lines = s.splitlines()
+    if len(lines) == 0:
+        return "", ""
+
+    # Longest common whitespace prefix
+    lcp = lines[0].split(lines[0].strip())[0]
+    # Iterate through the lines
+    for i in range(1, len(lines)):
+        # Empty lines are wildcards
+        if lines[i].strip() == "":
+            continue
+        # Iterate through the leading whitespace characters of the current line
+        for j in range(0, len(lcp)):
+            # If it doesn't have the same whitespace as lcp, then update lcp
+            if j >= len(lines[i]) or lcp[j] != lines[i][j]:
+                lcp = lcp[:j]
+                if lcp == "":
+                    return s, ""
+                break
+
+    return "\n".join(map(lambda x: x.lstrip(lcp), lines)), lcp
+
+
+def remove_quotes_and_escapes(output: str) -> str:
+    """
+    Clean up the output of the completion API, removing unnecessary escapes and quotes
+    """
+    output = output.strip()
+
+    # Replace smart quotes
+    output = output.replace("“", '"')
+    output = output.replace("”", '"')
+    output = output.replace("‘", "'")
+    output = output.replace("’", "'")
+
+    # Remove escapes
+    output = output.replace('\\"', '"')
+    output = output.replace("\\'", "'")
+    output = output.replace("\\n", "\n")
+    output = output.replace("\\t", "\t")
+    output = output.replace("\\\\", "\\")
+    if (output.startswith('"') and output.endswith('"')) or (output.startswith("'") and output.endswith("'")):
+        output = output[1:-1]
+
+    return output
diff --git a/continuedev/src/continuedev/steps/chat.py b/continuedev/src/continuedev/steps/chat.py
index 3751dec2..7c6b42db 100644
--- a/continuedev/src/continuedev/steps/chat.py
+++ b/continuedev/src/continuedev/steps/chat.py
@@ -3,6 +3,7 @@ from typing import Any, Coroutine, List
 
 from pydantic import Field
 
+from ..libs.util.strings import remove_quotes_and_escapes
 from .main import EditHighlightedCodeStep
 from .core.core import MessageStep
 from ..core.main import FunctionCall, Models
@@ -43,11 +44,8 @@ class SimpleChatStep(Step):
         finally:
             await generator.aclose()
 
-        self.name = (await sdk.models.gpt35.complete(
-            f"Write a short title for the following chat message: {self.description}")).strip()
-
-        if self.name.startswith('"') and self.name.endswith('"'):
-            self.name = self.name[1:-1]
+        self.name = remove_quotes_and_escapes(await sdk.models.gpt35.complete(
+            f"Write a short title for the following chat message: {self.description}"))
 
         self.chat_context.append(ChatMessage(
             role="assistant",
diff --git a/continuedev/src/continuedev/steps/core/core.py b/continuedev/src/continuedev/steps/core/core.py
index d5a7cd9a..5b9b9fd5 100644
--- a/continuedev/src/continuedev/steps/core/core.py
+++ b/continuedev/src/continuedev/steps/core/core.py
@@ -12,7 +12,7 @@ from ...models.filesystem import FileSystem, RangeInFile, RangeInFileWithContent
 from ...core.observation import Observation, TextObservation, TracebackObservation, UserInputObservation
 from ...core.main import ChatMessage, ContinueCustomException, Step, SequentialStep
 from ...libs.util.count_tokens import MAX_TOKENS_FOR_MODEL, DEFAULT_MAX_TOKENS
-from ...libs.util.dedent import dedent_and_get_common_whitespace
+from ...libs.util.strings import dedent_and_get_common_whitespace, remove_quotes_and_escapes
 import difflib
 
 
@@ -157,17 +157,6 @@ class DefaultModelEditCodeStep(Step):
     _new_contents: str = ""
     _prompt_and_completion: str = ""
 
-    def _cleanup_output(self, output: str) -> str:
-        output = output.replace('\\"', '"')
-        output = output.replace("\\'", "'")
-        output = output.replace("\\n", "\n")
-        output = output.replace("\\t", "\t")
-        output = output.replace("\\\\", "\\")
-        if output.startswith('"') and output.endswith('"'):
-            output = output[1:-1]
-
-        return output
-
     async def describe(self, models: Models) -> Coroutine[str, None, None]:
         if self._previous_contents.strip() == self._new_contents.strip():
             description = "No edits were made"
@@ -183,9 +172,9 @@ class DefaultModelEditCodeStep(Step):
 
                 Please give brief a description of the changes made above using markdown bullet points. Be concise:"""))
         name = await models.gpt3516k.complete(f"Write a very short title to describe this requested change (no quotes): '{self.user_input}'. This is the title:")
-        self.name = self._cleanup_output(name)
+        self.name = remove_quotes_and_escapes(name)
 
-        return f"{self._cleanup_output(description)}"
+        return f"{remove_quotes_and_escapes(description)}"
 
     async def get_prompt_parts(self, rif: RangeInFileWithContents, sdk: ContinueSDK, full_file_contents: str):
         # We don't know here all of the functions being passed in.
diff --git a/extension/package-lock.json b/extension/package-lock.json
index 33f81dec..0e0125b0 100644
--- a/extension/package-lock.json
+++ b/extension/package-lock.json
@@ -1,12 +1,12 @@
 {
   "name": "continue",
-  "version": "0.0.176",
+  "version": "0.0.177",
   "lockfileVersion": 2,
   "requires": true,
   "packages": {
     "": {
       "name": "continue",
-      "version": "0.0.176",
+      "version": "0.0.177",
       "license": "Apache-2.0",
       "dependencies": {
         "@electron/rebuild": "^3.2.10",
diff --git a/extension/package.json b/extension/package.json
index e515ed36..8462bf68 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.176",
+  "version": "0.0.177",
   "publisher": "Continue",
   "engines": {
     "vscode": "^1.67.0"
diff --git a/extension/react-app/src/components/ComboBox.tsx b/extension/react-app/src/components/ComboBox.tsx
index dbebd534..0ea8a3e1 100644
--- a/extension/react-app/src/components/ComboBox.tsx
+++ b/extension/react-app/src/components/ComboBox.tsx
@@ -6,6 +6,7 @@ import {
   lightGray,
   secondaryDark,
   vscBackground,
+  vscForeground,
 } from ".";
 import CodeBlock from "./CodeBlock";
 import PillButton from "./PillButton";
@@ -48,7 +49,7 @@ const MainTextInput = styled.textarea`
   height: auto;
   width: 100%;
   background-color: ${secondaryDark};
-  color: white;
+  color: ${vscForeground};
   z-index: 1;
   border: 1px solid transparent;
 
@@ -71,7 +72,7 @@ const Ul = styled.ul<{
   position: absolute;
   background: ${vscBackground};
   background-color: ${secondaryDark};
-  color: white;
+  color: ${vscForeground};
   max-height: ${UlMaxHeight}px;
   width: calc(100% - 16px);
   overflow-y: scroll;
@@ -95,6 +96,7 @@ const Li = styled.li<{
   selected: boolean;
   isLastItem: boolean;
 }>`
+  background-color: ${secondaryDark};
   ${({ highlighted }) => highlighted && "background: #ff000066;"}
   ${({ selected }) => selected && "font-weight: bold;"}
     padding: 0.5rem 0.75rem;
@@ -218,7 +220,9 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
                 ? "Editing such a large range may be slow"
                 : undefined
             }
-            onlyShowDelete={highlightedCodeSections.length <= 1}
+            onlyShowDelete={
+              highlightedCodeSections.length <= 1 || section.editing
+            }
             editing={section.editing}
             pinned={section.pinned}
             index={idx}
diff --git a/extension/react-app/src/components/InputAndButton.tsx b/extension/react-app/src/components/InputAndButton.tsx
index 0a8592f2..8019d014 100644
--- a/extension/react-app/src/components/InputAndButton.tsx
+++ b/extension/react-app/src/components/InputAndButton.tsx
@@ -1,6 +1,6 @@
 import React, { useRef } from "react";
 import styled from "styled-components";
-import { vscBackground } from ".";
+import { vscBackground, vscForeground } from ".";
 
 interface InputAndButtonProps {
   onUserInput: (input: string) => void;
@@ -16,7 +16,7 @@ const Input = styled.input`
   padding: 0.5rem;
   border: 1px solid white;
   background-color: ${vscBackground};
-  color: white;
+  color: ${vscForeground};
   border-radius: 4px;
   border-top-right-radius: 0;
   border-bottom-right-radius: 0;
@@ -27,7 +27,7 @@ const Button = styled.button`
   padding: 0.5rem;
   border: 1px solid white;
   background-color: ${vscBackground};
-  color: white;
+  color: ${vscForeground};
   border-radius: 4px;
   border-top-left-radius: 0;
   border-bottom-left-radius: 0;
@@ -35,8 +35,8 @@ const Button = styled.button`
   cursor: pointer;
 
   &:hover {
-    background-color: white;
-    color: black;
+    background-color: ${vscForeground};
+    color: ${vscBackground};
   }
 `;
 
diff --git a/extension/react-app/src/components/PillButton.tsx b/extension/react-app/src/components/PillButton.tsx
index 5a16516e..eba5cf8f 100644
--- a/extension/react-app/src/components/PillButton.tsx
+++ b/extension/react-app/src/components/PillButton.tsx
@@ -1,6 +1,11 @@
 import { useContext, useState } from "react";
 import styled from "styled-components";
-import { StyledTooltip, defaultBorderRadius, secondaryDark } from ".";
+import {
+  StyledTooltip,
+  defaultBorderRadius,
+  secondaryDark,
+  vscForeground,
+} from ".";
 import {
   Trash,
   PaintBrush,
@@ -10,7 +15,7 @@ import { GUIClientContext } from "../App";
 
 const Button = styled.button`
   border: none;
-  color: white;
+  color: ${vscForeground};
   background-color: ${secondaryDark};
   border-radius: ${defaultBorderRadius};
   padding: 8px;
diff --git a/extension/react-app/src/components/StepContainer.tsx b/extension/react-app/src/components/StepContainer.tsx
index 93bdbc89..26bc8e33 100644
--- a/extension/react-app/src/components/StepContainer.tsx
+++ b/extension/react-app/src/components/StepContainer.tsx
@@ -6,6 +6,7 @@ import {
   secondaryDark,
   vscBackground,
   vscBackgroundTransparent,
+  vscForeground,
 } from ".";
 import {
   ChevronDown,
@@ -120,20 +121,22 @@ const StyledMarkdownPreview = styled(MarkdownPreview)`
   }
 
   code {
-    color: #f69292;
+    color: #f78383;
     word-wrap: break-word;
+    border-radius: ${defaultBorderRadius};
+    background-color: ${secondaryDark};
   }
 
   pre > code {
     background-color: ${secondaryDark};
-    color: white;
+    color: ${vscForeground};
   }
 
   background-color: ${vscBackground};
   font-family: "Lexend", sans-serif;
   font-size: 13px;
   padding: 8px;
-  color: white;
+  color: ${vscForeground};
 `;
 
 // #endregion
@@ -267,6 +270,9 @@ function StepContainer(props: StepContainerProps) {
           ) : (
             <StyledMarkdownPreview
               source={props.historyNode.step.description || ""}
+              wrapperElement={{
+                "data-color-mode": "dark",
+              }}
             />
           )}
         </ContentDiv>
diff --git a/extension/react-app/src/components/TextDialog.tsx b/extension/react-app/src/components/TextDialog.tsx
index 646d6846..cba3852d 100644
--- a/extension/react-app/src/components/TextDialog.tsx
+++ b/extension/react-app/src/components/TextDialog.tsx
@@ -1,7 +1,7 @@
 // Write a component that displays a dialog box with a text field and a button.
 import React, { useEffect, useState } from "react";
 import styled from "styled-components";
-import { Button, buttonColor, secondaryDark, vscBackground } from ".";
+import { Button, secondaryDark, vscBackground, vscForeground } from ".";
 import { isMetaEquivalentKeyPressed } from "../util";
 
 const ScreenCover = styled.div`
@@ -21,13 +21,13 @@ const DialogContainer = styled.div`
 `;
 
 const Dialog = styled.div`
-  background-color: white;
+  color: ${vscForeground};
+  background-color: ${vscBackground};
   border-radius: 8px;
   padding: 8px;
   display: flex;
   flex-direction: column;
-  /* box-shadow: 0 0 10px 0 rgba(255, 255, 255, 0.5); */
-  border: 2px solid ${buttonColor};
+  box-shadow: 0 0 10px 0 ${vscForeground};
   width: fit-content;
   margin: auto;
 `;
@@ -38,14 +38,16 @@ const TextArea = styled.textarea`
   padding: 8px;
   outline: 1px solid black;
   resize: none;
+  background-color: ${secondaryDark};
+  color: ${vscForeground};
 
   &:focus {
-    outline: 1px solid ${buttonColor};
+    outline: 1px solid ${vscForeground};
   }
 `;
 
 const P = styled.p`
-  color: black;
+  color: ${vscForeground};
   margin: 8px auto;
 `;
 
diff --git a/extension/react-app/src/components/index.ts b/extension/react-app/src/components/index.ts
index 9ae0f097..cb5e7915 100644
--- a/extension/react-app/src/components/index.ts
+++ b/extension/react-app/src/components/index.ts
@@ -3,12 +3,16 @@ import styled, { keyframes } from "styled-components";
 
 export const defaultBorderRadius = "5px";
 export const lightGray = "rgb(100 100 100)";
-export const secondaryDark = "rgb(45 45 45)";
-export const vscBackground = "rgb(30 30 30)";
+// 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)";
 export const buttonColorHover = "rgb(113 28 59 0.67)";
 
+export const secondaryDark = "var(--vscode-textBlockQuote-background)";
+export const vscBackground = "var(--vscode-editor-background)";
+export const vscForeground = "var(--vscode-editor-foreground)";
+
 export const Button = styled.button`
   padding: 10px 12px;
   margin: 8px 0;
@@ -46,8 +50,8 @@ export const TextArea = styled.textarea`
   resize: vertical;
 
   padding: 4px;
-  caret-color: white;
-  color: white;
+  caret-color: ${vscForeground};
+  color: #{vscForeground};
 
   &:focus {
     outline: 1px solid ${buttonColor};
@@ -120,7 +124,7 @@ export const MainTextInput = styled.textarea`
   border: 1px solid #ccc;
   margin: 8px 8px;
   background-color: ${vscBackground};
-  color: white;
+  color: ${vscForeground};
   outline: 1px solid orange;
   resize: none;
 `;
@@ -137,8 +141,9 @@ export const appear = keyframes`
 `;
 
 export const HeaderButton = styled.button<{ inverted: boolean | undefined }>`
-  background-color: ${({ inverted }) => (inverted ? "white" : "transparent")};
-  color: ${({ inverted }) => (inverted ? "black" : "white")};
+  background-color: ${({ inverted }) =>
+    inverted ? vscForeground : "transparent"};
+  color: ${({ inverted }) => (inverted ? vscBackground : vscForeground)};
 
   border: none;
   border-radius: ${defaultBorderRadius};
@@ -146,7 +151,9 @@ export const HeaderButton = styled.button<{ inverted: boolean | undefined }>`
 
   &:hover {
     background-color: ${({ inverted }) =>
-      typeof inverted === "undefined" || inverted ? lightGray : "transparent"};
+      typeof inverted === "undefined" || inverted
+        ? secondaryDark
+        : "transparent"};
   }
   display: flex;
   align-items: center;
diff --git a/extension/react-app/src/index.css b/extension/react-app/src/index.css
index 6e33c89c..bac7fe97 100644
--- a/extension/react-app/src/index.css
+++ b/extension/react-app/src/index.css
@@ -14,13 +14,13 @@ html,
 body,
 #root {
   height: 100%;
-  background-color: var(--vsc-background);
+  background-color: var(--vscode-editor-background);
   font-family: "Lexend", sans-serif;
 }
 
 body {
   padding: 0;
-  color: white;
+  color: var(--vscode-editor-foreground);
   padding: 0px;
   margin: 0px;
   height: 100%;
diff --git a/extension/react-app/src/pages/gui.tsx b/extension/react-app/src/pages/gui.tsx
index 64207487..c35cf21b 100644
--- a/extension/react-app/src/pages/gui.tsx
+++ b/extension/react-app/src/pages/gui.tsx
@@ -1,5 +1,9 @@
 import styled from "styled-components";
-import { defaultBorderRadius } from "../components";
+import {
+  defaultBorderRadius,
+  vscBackground,
+  vscForeground,
+} from "../components";
 import Loader from "../components/Loader";
 import ContinueButton from "../components/ContinueButton";
 import { FullState, HighlightedRangeContext } from "../../../schema/FullState";
@@ -371,12 +375,13 @@ function GUI(props: GUIProps) {
         style={{
           position: "fixed",
           bottom: "50px",
-          backgroundColor: "white",
-          color: "black",
+          backgroundColor: vscBackground,
+          color: vscForeground,
           borderRadius: defaultBorderRadius,
           padding: "16px",
           margin: "16px",
           zIndex: 100,
+          boxShadow: `0px 0px 10px 0px ${vscForeground}`,
         }}
         hidden={!showDataSharingInfo}
       >
-- 
cgit v1.2.3-70-g09d2


From 4d7e72970f770eb49627589fb142c93dfb6fd73b Mon Sep 17 00:00:00 2001
From: Nate Sesti <sestinj@gmail.com>
Date: Sat, 22 Jul 2023 22:37:13 -0700
Subject: @ feature (very large commit)

---
 continuedev/poetry.lock                            | 340 ++++++++++++++++++++-
 continuedev/pyproject.toml                         |   2 +
 continuedev/src/continuedev/core/autopilot.py      | 138 ++-------
 continuedev/src/continuedev/core/config.py         |   3 +
 continuedev/src/continuedev/core/context.py        | 205 +++++++++++++
 .../src/continuedev/core/context_manager.py        | 119 --------
 continuedev/src/continuedev/core/main.py           |  59 +++-
 continuedev/src/continuedev/core/sdk.py            |  31 +-
 .../highlighted_code_context_provider.py           | 191 ++++++++++++
 continuedev/src/continuedev/libs/util/paths.py     |  20 +-
 .../src/continuedev/models/generate_json_schema.py |   3 +
 continuedev/src/continuedev/server/gui.py          |  37 +--
 continuedev/src/continuedev/server/gui_protocol.py |  10 +-
 continuedev/src/continuedev/server/main.py         |  28 +-
 .../src/continuedev/server/meilisearch_server.py   |  56 ++++
 .../src/continuedev/server/session_manager.py      |   6 +-
 extension/react-app/package-lock.json              |  98 ++++++
 extension/react-app/package.json                   |   1 +
 extension/react-app/src/components/ComboBox.tsx    | 174 ++++++-----
 extension/react-app/src/components/PillButton.tsx  |  87 ++++--
 .../react-app/src/components/StepContainer.tsx     |  29 +-
 .../src/components/StyledMarkdownPreview.tsx       |  37 +++
 extension/react-app/src/components/TextDialog.tsx  |   2 +-
 .../src/hooks/AbstractContinueGUIClientProtocol.ts |   8 +-
 .../src/hooks/ContinueGUIClientProtocol.ts         |  15 +-
 extension/react-app/src/pages/gui.tsx              |  81 ++---
 .../src/redux/selectors/uiStateSelectors.ts        |   5 +
 .../react-app/src/redux/slices/uiStateSlice.ts     |  24 ++
 extension/react-app/src/redux/store.ts             |   6 +
 extension/schema/ContextItem.d.ts                  |  45 +++
 extension/schema/FullState.d.ts                    |  65 ++--
 schema/json/ContextItem.json                       |  76 +++++
 schema/json/FullState.json                         | 132 ++++----
 33 files changed, 1554 insertions(+), 579 deletions(-)
 create mode 100644 continuedev/src/continuedev/core/context.py
 delete mode 100644 continuedev/src/continuedev/core/context_manager.py
 create mode 100644 continuedev/src/continuedev/libs/context_providers/highlighted_code_context_provider.py
 create mode 100644 continuedev/src/continuedev/server/meilisearch_server.py
 create mode 100644 extension/react-app/src/components/StyledMarkdownPreview.tsx
 create mode 100644 extension/react-app/src/redux/selectors/uiStateSelectors.ts
 create mode 100644 extension/react-app/src/redux/slices/uiStateSlice.ts
 create mode 100644 extension/schema/ContextItem.d.ts
 create mode 100644 schema/json/ContextItem.json

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

diff --git a/continuedev/poetry.lock b/continuedev/poetry.lock
index 1cd4a591..b67128fd 100644
--- a/continuedev/poetry.lock
+++ b/continuedev/poetry.lock
@@ -220,6 +220,24 @@ files = [
     {file = "boltons-23.0.0.tar.gz", hash = "sha256:8c50a71829525835ca3c849c7ed2511610c972b4dddfcd41a4a5447222beb4b0"},
 ]
 
+[[package]]
+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 = [
+    {file = "camel_converter-3.0.2-py3-none-any.whl", hash = "sha256:88e5d91be5b2dff9c0748ba515774c3421088922d9e77c39f8742eb41cb7db88"},
+    {file = "camel_converter-3.0.2.tar.gz", hash = "sha256:3b3d076e824ae979b271b4d497c90514c2b218811f76b0c368fb69da2556fe07"},
+]
+
+[package.dependencies]
+pydantic = {version = ">=1.8.2", optional = true, markers = "extra == \"pydantic\""}
+
+[package.extras]
+pydantic = ["pydantic (>=1.8.2)"]
+
 [[package]]
 name = "certifi"
 version = "2022.12.7"
@@ -232,6 +250,83 @@ files = [
     {file = "certifi-2022.12.7.tar.gz", hash = "sha256:35824b4c3a97115964b408844d64aa14db1cc518f6562e8d7261699d1350a9e3"},
 ]
 
+[[package]]
+name = "cffi"
+version = "1.15.1"
+description = "Foreign Function Interface for Python calling C code."
+category = "main"
+optional = false
+python-versions = "*"
+files = [
+    {file = "cffi-1.15.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:a66d3508133af6e8548451b25058d5812812ec3798c886bf38ed24a98216fab2"},
+    {file = "cffi-1.15.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:470c103ae716238bbe698d67ad020e1db9d9dba34fa5a899b5e21577e6d52ed2"},
+    {file = "cffi-1.15.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:9ad5db27f9cabae298d151c85cf2bad1d359a1b9c686a275df03385758e2f914"},
+    {file = "cffi-1.15.1-cp27-cp27m-win32.whl", hash = "sha256:b3bbeb01c2b273cca1e1e0c5df57f12dce9a4dd331b4fa1635b8bec26350bde3"},
+    {file = "cffi-1.15.1-cp27-cp27m-win_amd64.whl", hash = "sha256:e00b098126fd45523dd056d2efba6c5a63b71ffe9f2bbe1a4fe1716e1d0c331e"},
+    {file = "cffi-1.15.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:d61f4695e6c866a23a21acab0509af1cdfd2c013cf256bbf5b6b5e2695827162"},
+    {file = "cffi-1.15.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:ed9cb427ba5504c1dc15ede7d516b84757c3e3d7868ccc85121d9310d27eed0b"},
+    {file = "cffi-1.15.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:39d39875251ca8f612b6f33e6b1195af86d1b3e60086068be9cc053aa4376e21"},
+    {file = "cffi-1.15.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:285d29981935eb726a4399badae8f0ffdff4f5050eaa6d0cfc3f64b857b77185"},
+    {file = "cffi-1.15.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3eb6971dcff08619f8d91607cfc726518b6fa2a9eba42856be181c6d0d9515fd"},
+    {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:21157295583fe8943475029ed5abdcf71eb3911894724e360acff1d61c1d54bc"},
+    {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5635bd9cb9731e6d4a1132a498dd34f764034a8ce60cef4f5319c0541159392f"},
+    {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2012c72d854c2d03e45d06ae57f40d78e5770d252f195b93f581acf3ba44496e"},
+    {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd86c085fae2efd48ac91dd7ccffcfc0571387fe1193d33b6394db7ef31fe2a4"},
+    {file = "cffi-1.15.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:fa6693661a4c91757f4412306191b6dc88c1703f780c8234035eac011922bc01"},
+    {file = "cffi-1.15.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:59c0b02d0a6c384d453fece7566d1c7e6b7bae4fc5874ef2ef46d56776d61c9e"},
+    {file = "cffi-1.15.1-cp310-cp310-win32.whl", hash = "sha256:cba9d6b9a7d64d4bd46167096fc9d2f835e25d7e4c121fb2ddfc6528fb0413b2"},
+    {file = "cffi-1.15.1-cp310-cp310-win_amd64.whl", hash = "sha256:ce4bcc037df4fc5e3d184794f27bdaab018943698f4ca31630bc7f84a7b69c6d"},
+    {file = "cffi-1.15.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3d08afd128ddaa624a48cf2b859afef385b720bb4b43df214f85616922e6a5ac"},
+    {file = "cffi-1.15.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3799aecf2e17cf585d977b780ce79ff0dc9b78d799fc694221ce814c2c19db83"},
+    {file = "cffi-1.15.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a591fe9e525846e4d154205572a029f653ada1a78b93697f3b5a8f1f2bc055b9"},
+    {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3548db281cd7d2561c9ad9984681c95f7b0e38881201e157833a2342c30d5e8c"},
+    {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:91fc98adde3d7881af9b59ed0294046f3806221863722ba7d8d120c575314325"},
+    {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94411f22c3985acaec6f83c6df553f2dbe17b698cc7f8ae751ff2237d96b9e3c"},
+    {file = "cffi-1.15.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:03425bdae262c76aad70202debd780501fabeaca237cdfddc008987c0e0f59ef"},
+    {file = "cffi-1.15.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:cc4d65aeeaa04136a12677d3dd0b1c0c94dc43abac5860ab33cceb42b801c1e8"},
+    {file = "cffi-1.15.1-cp311-cp311-win32.whl", hash = "sha256:a0f100c8912c114ff53e1202d0078b425bee3649ae34d7b070e9697f93c5d52d"},
+    {file = "cffi-1.15.1-cp311-cp311-win_amd64.whl", hash = "sha256:04ed324bda3cda42b9b695d51bb7d54b680b9719cfab04227cdd1e04e5de3104"},
+    {file = "cffi-1.15.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50a74364d85fd319352182ef59c5c790484a336f6db772c1a9231f1c3ed0cbd7"},
+    {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e263d77ee3dd201c3a142934a086a4450861778baaeeb45db4591ef65550b0a6"},
+    {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cec7d9412a9102bdc577382c3929b337320c4c4c4849f2c5cdd14d7368c5562d"},
+    {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4289fc34b2f5316fbb762d75362931e351941fa95fa18789191b33fc4cf9504a"},
+    {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:173379135477dc8cac4bc58f45db08ab45d228b3363adb7af79436135d028405"},
+    {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6975a3fac6bc83c4a65c9f9fcab9e47019a11d3d2cf7f3c0d03431bf145a941e"},
+    {file = "cffi-1.15.1-cp36-cp36m-win32.whl", hash = "sha256:2470043b93ff09bf8fb1d46d1cb756ce6132c54826661a32d4e4d132e1977adf"},
+    {file = "cffi-1.15.1-cp36-cp36m-win_amd64.whl", hash = "sha256:30d78fbc8ebf9c92c9b7823ee18eb92f2e6ef79b45ac84db507f52fbe3ec4497"},
+    {file = "cffi-1.15.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:198caafb44239b60e252492445da556afafc7d1e3ab7a1fb3f0584ef6d742375"},
+    {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5ef34d190326c3b1f822a5b7a45f6c4535e2f47ed06fec77d3d799c450b2651e"},
+    {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8102eaf27e1e448db915d08afa8b41d6c7ca7a04b7d73af6514df10a3e74bd82"},
+    {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5df2768244d19ab7f60546d0c7c63ce1581f7af8b5de3eb3004b9b6fc8a9f84b"},
+    {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8c4917bd7ad33e8eb21e9a5bbba979b49d9a97acb3a803092cbc1133e20343c"},
+    {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2642fe3142e4cc4af0799748233ad6da94c62a8bec3a6648bf8ee68b1c7426"},
+    {file = "cffi-1.15.1-cp37-cp37m-win32.whl", hash = "sha256:e229a521186c75c8ad9490854fd8bbdd9a0c9aa3a524326b55be83b54d4e0ad9"},
+    {file = "cffi-1.15.1-cp37-cp37m-win_amd64.whl", hash = "sha256:a0b71b1b8fbf2b96e41c4d990244165e2c9be83d54962a9a1d118fd8657d2045"},
+    {file = "cffi-1.15.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:320dab6e7cb2eacdf0e658569d2575c4dad258c0fcc794f46215e1e39f90f2c3"},
+    {file = "cffi-1.15.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e74c6b51a9ed6589199c787bf5f9875612ca4a8a0785fb2d4a84429badaf22a"},
+    {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5c84c68147988265e60416b57fc83425a78058853509c1b0629c180094904a5"},
+    {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b926aa83d1edb5aa5b427b4053dc420ec295a08e40911296b9eb1b6170f6cca"},
+    {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:87c450779d0914f2861b8526e035c5e6da0a3199d8f1add1a665e1cbc6fc6d02"},
+    {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f2c9f67e9821cad2e5f480bc8d83b8742896f1242dba247911072d4fa94c192"},
+    {file = "cffi-1.15.1-cp38-cp38-win32.whl", hash = "sha256:8b7ee99e510d7b66cdb6c593f21c043c248537a32e0bedf02e01e9553a172314"},
+    {file = "cffi-1.15.1-cp38-cp38-win_amd64.whl", hash = "sha256:00a9ed42e88df81ffae7a8ab6d9356b371399b91dbdf0c3cb1e84c03a13aceb5"},
+    {file = "cffi-1.15.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:54a2db7b78338edd780e7ef7f9f6c442500fb0d41a5a4ea24fff1c929d5af585"},
+    {file = "cffi-1.15.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:fcd131dd944808b5bdb38e6f5b53013c5aa4f334c5cad0c72742f6eba4b73db0"},
+    {file = "cffi-1.15.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7473e861101c9e72452f9bf8acb984947aa1661a7704553a9f6e4baa5ba64415"},
+    {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c9a799e985904922a4d207a94eae35c78ebae90e128f0c4e521ce339396be9d"},
+    {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3bcde07039e586f91b45c88f8583ea7cf7a0770df3a1649627bf598332cb6984"},
+    {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:33ab79603146aace82c2427da5ca6e58f2b3f2fb5da893ceac0c42218a40be35"},
+    {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d598b938678ebf3c67377cdd45e09d431369c3b1a5b331058c338e201f12b27"},
+    {file = "cffi-1.15.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:db0fbb9c62743ce59a9ff687eb5f4afbe77e5e8403d6697f7446e5f609976f76"},
+    {file = "cffi-1.15.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:98d85c6a2bef81588d9227dde12db8a7f47f639f4a17c9ae08e773aa9c697bf3"},
+    {file = "cffi-1.15.1-cp39-cp39-win32.whl", hash = "sha256:40f4774f5a9d4f5e344f31a32b5096977b5d48560c5592e2f3d2c4374bd543ee"},
+    {file = "cffi-1.15.1-cp39-cp39-win_amd64.whl", hash = "sha256:70df4e3b545a17496c9b3f41f5115e69a4f2e77e94e1d2a8e1070bc0c38c8a3c"},
+    {file = "cffi-1.15.1.tar.gz", hash = "sha256:d400bfb9a37b1351253cb402671cea7e89bdecc294e8016a707f6d1d8ac934f9"},
+]
+
+[package.dependencies]
+pycparser = "*"
+
 [[package]]
 name = "charset-normalizer"
 version = "3.1.0"
@@ -356,6 +451,52 @@ files = [
     {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
 ]
 
+[[package]]
+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 = [
+    {file = "cryptography-41.0.2-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:01f1d9e537f9a15b037d5d9ee442b8c22e3ae11ce65ea1f3316a41c78756b711"},
+    {file = "cryptography-41.0.2-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:079347de771f9282fbfe0e0236c716686950c19dee1b76240ab09ce1624d76d7"},
+    {file = "cryptography-41.0.2-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:439c3cc4c0d42fa999b83ded80a9a1fb54d53c58d6e59234cfe97f241e6c781d"},
+    {file = "cryptography-41.0.2-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f14ad275364c8b4e525d018f6716537ae7b6d369c094805cae45300847e0894f"},
+    {file = "cryptography-41.0.2-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:84609ade00a6ec59a89729e87a503c6e36af98ddcd566d5f3be52e29ba993182"},
+    {file = "cryptography-41.0.2-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:49c3222bb8f8e800aead2e376cbef687bc9e3cb9b58b29a261210456a7783d83"},
+    {file = "cryptography-41.0.2-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:d73f419a56d74fef257955f51b18d046f3506270a5fd2ac5febbfa259d6c0fa5"},
+    {file = "cryptography-41.0.2-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:2a034bf7d9ca894720f2ec1d8b7b5832d7e363571828037f9e0c4f18c1b58a58"},
+    {file = "cryptography-41.0.2-cp37-abi3-win32.whl", hash = "sha256:d124682c7a23c9764e54ca9ab5b308b14b18eba02722b8659fb238546de83a76"},
+    {file = "cryptography-41.0.2-cp37-abi3-win_amd64.whl", hash = "sha256:9c3fe6534d59d071ee82081ca3d71eed3210f76ebd0361798c74abc2bcf347d4"},
+    {file = "cryptography-41.0.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:a719399b99377b218dac6cf547b6ec54e6ef20207b6165126a280b0ce97e0d2a"},
+    {file = "cryptography-41.0.2-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:182be4171f9332b6741ee818ec27daff9fb00349f706629f5cbf417bd50e66fd"},
+    {file = "cryptography-41.0.2-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:7a9a3bced53b7f09da251685224d6a260c3cb291768f54954e28f03ef14e3766"},
+    {file = "cryptography-41.0.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:f0dc40e6f7aa37af01aba07277d3d64d5a03dc66d682097541ec4da03cc140ee"},
+    {file = "cryptography-41.0.2-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:674b669d5daa64206c38e507808aae49904c988fa0a71c935e7006a3e1e83831"},
+    {file = "cryptography-41.0.2-pp38-pypy38_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:7af244b012711a26196450d34f483357e42aeddb04128885d95a69bd8b14b69b"},
+    {file = "cryptography-41.0.2-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:9b6d717393dbae53d4e52684ef4f022444fc1cce3c48c38cb74fca29e1f08eaa"},
+    {file = "cryptography-41.0.2-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:192255f539d7a89f2102d07d7375b1e0a81f7478925b3bc2e0549ebf739dae0e"},
+    {file = "cryptography-41.0.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:f772610fe364372de33d76edcd313636a25684edb94cee53fd790195f5989d14"},
+    {file = "cryptography-41.0.2-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:b332cba64d99a70c1e0836902720887fb4529ea49ea7f5462cf6640e095e11d2"},
+    {file = "cryptography-41.0.2-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:9a6673c1828db6270b76b22cc696f40cde9043eb90373da5c2f8f2158957f42f"},
+    {file = "cryptography-41.0.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:342f3767e25876751e14f8459ad85e77e660537ca0a066e10e75df9c9e9099f0"},
+    {file = "cryptography-41.0.2.tar.gz", hash = "sha256:7d230bf856164de164ecb615ccc14c7fc6de6906ddd5b491f3af90d3514c925c"},
+]
+
+[package.dependencies]
+cffi = ">=1.12"
+
+[package.extras]
+docs = ["sphinx (>=5.3.0)", "sphinx-rtd-theme (>=1.1.1)"]
+docstest = ["pyenchant (>=1.6.11)", "sphinxcontrib-spelling (>=4.0.1)", "twine (>=1.12.0)"]
+nox = ["nox"]
+pep8test = ["black", "check-sdist", "mypy", "ruff"]
+sdist = ["build"]
+ssh = ["bcrypt (>=3.1.5)"]
+test = ["pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"]
+test-randomorder = ["pytest-randomly"]
+
 [[package]]
 name = "dataclasses-json"
 version = "0.5.7"
@@ -376,6 +517,24 @@ typing-inspect = ">=0.4.0"
 [package.extras]
 dev = ["flake8", "hypothesis", "ipython", "mypy (>=0.710)", "portray", "pytest (>=6.2.3)", "simplejson", "types-dataclasses"]
 
+[[package]]
+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 = [
+    {file = "Deprecated-1.2.14-py2.py3-none-any.whl", hash = "sha256:6fac8b097794a90302bdbb17b9b815e732d3c4720583ff1b198499d78470466c"},
+    {file = "Deprecated-1.2.14.tar.gz", hash = "sha256:e5323eb936458dccc2582dc6f9c322c852a775a27065ff2b0c4970b9d53d01b3"},
+]
+
+[package.dependencies]
+wrapt = ">=1.10,<2"
+
+[package.extras]
+dev = ["PyTest", "PyTest-Cov", "bump2version (<1)", "sphinx (<2)", "tox"]
+
 [[package]]
 name = "diff-match-patch"
 version = "20230430"
@@ -816,6 +975,22 @@ files = [
 [package.dependencies]
 marshmallow = ">=2.0.0"
 
+[[package]]
+name = "meilisearch"
+version = "0.28.1"
+description = "The python client for Meilisearch API."
+category = "main"
+optional = false
+python-versions = ">=3.8"
+files = [
+    {file = "meilisearch-0.28.1-py3-none-any.whl", hash = "sha256:b4cfaf140fc323c429a4e174b801bcc6dddef88bf901560ebf2fc5c0014099b5"},
+    {file = "meilisearch-0.28.1.tar.gz", hash = "sha256:4e8627abe1394f04125c99e60f9f4356ba200effe5735ce9b8a44b09e3c6403c"},
+]
+
+[package.dependencies]
+camel-converter = {version = "*", extras = ["pydantic"]}
+requests = "*"
+
 [[package]]
 name = "monotonic"
 version = "1.6"
@@ -1198,6 +1373,18 @@ files = [
 [package.extras]
 test = ["enum34", "ipaddress", "mock", "pywin32", "wmi"]
 
+[[package]]
+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 = [
+    {file = "pycparser-2.21-py2.py3-none-any.whl", hash = "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9"},
+    {file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"},
+]
+
 [[package]]
 name = "pydantic"
 version = "1.10.7"
@@ -1251,6 +1438,72 @@ typing-extensions = ">=4.2.0"
 dotenv = ["python-dotenv (>=0.10.4)"]
 email = ["email-validator (>=1.0.3)"]
 
+[[package]]
+name = "pygithub"
+version = "1.59.0"
+description = "Use the full Github API v3"
+category = "main"
+optional = false
+python-versions = ">=3.7"
+files = [
+    {file = "PyGithub-1.59.0-py3-none-any.whl", hash = "sha256:126bdbae72087d8d038b113aab6b059b4553cb59348e3024bb1a1cae406ace9e"},
+    {file = "PyGithub-1.59.0.tar.gz", hash = "sha256:6e05ff49bac3caa7d1d6177a10c6e55a3e20c85b92424cc198571fd0cf786690"},
+]
+
+[package.dependencies]
+deprecated = "*"
+pyjwt = {version = ">=2.4.0", extras = ["crypto"]}
+pynacl = ">=1.4.0"
+requests = ">=2.14.0"
+
+[[package]]
+name = "pyjwt"
+version = "2.8.0"
+description = "JSON Web Token implementation in Python"
+category = "main"
+optional = false
+python-versions = ">=3.7"
+files = [
+    {file = "PyJWT-2.8.0-py3-none-any.whl", hash = "sha256:59127c392cc44c2da5bb3192169a91f429924e17aff6534d70fdc02ab3e04320"},
+    {file = "PyJWT-2.8.0.tar.gz", hash = "sha256:57e28d156e3d5c10088e0c68abb90bfac3df82b40a71bd0daa20c65ccd5c23de"},
+]
+
+[package.dependencies]
+cryptography = {version = ">=3.4.0", optional = true, markers = "extra == \"crypto\""}
+
+[package.extras]
+crypto = ["cryptography (>=3.4.0)"]
+dev = ["coverage[toml] (==5.0.4)", "cryptography (>=3.4.0)", "pre-commit", "pytest (>=6.0.0,<7.0.0)", "sphinx (>=4.5.0,<5.0.0)", "sphinx-rtd-theme", "zope.interface"]
+docs = ["sphinx (>=4.5.0,<5.0.0)", "sphinx-rtd-theme", "zope.interface"]
+tests = ["coverage[toml] (==5.0.4)", "pytest (>=6.0.0,<7.0.0)"]
+
+[[package]]
+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 = [
+    {file = "PyNaCl-1.5.0-cp36-abi3-macosx_10_10_universal2.whl", hash = "sha256:401002a4aaa07c9414132aaed7f6836ff98f59277a234704ff66878c2ee4a0d1"},
+    {file = "PyNaCl-1.5.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:52cb72a79269189d4e0dc537556f4740f7f0a9ec41c1322598799b0bdad4ef92"},
+    {file = "PyNaCl-1.5.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a36d4a9dda1f19ce6e03c9a784a2921a4b726b02e1c736600ca9c22029474394"},
+    {file = "PyNaCl-1.5.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:0c84947a22519e013607c9be43706dd42513f9e6ae5d39d3613ca1e142fba44d"},
+    {file = "PyNaCl-1.5.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:06b8f6fa7f5de8d5d2f7573fe8c863c051225a27b61e6860fd047b1775807858"},
+    {file = "PyNaCl-1.5.0-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:a422368fc821589c228f4c49438a368831cb5bbc0eab5ebe1d7fac9dded6567b"},
+    {file = "PyNaCl-1.5.0-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:61f642bf2378713e2c2e1de73444a3778e5f0a38be6fee0fe532fe30060282ff"},
+    {file = "PyNaCl-1.5.0-cp36-abi3-win32.whl", hash = "sha256:e46dae94e34b085175f8abb3b0aaa7da40767865ac82c928eeb9e57e1ea8a543"},
+    {file = "PyNaCl-1.5.0-cp36-abi3-win_amd64.whl", hash = "sha256:20f42270d27e1b6a29f54032090b972d97f0a1b0948cc52392041ef7831fee93"},
+    {file = "PyNaCl-1.5.0.tar.gz", hash = "sha256:8ac7448f09ab85811607bdd21ec2464495ac8b7c66d146bf545b0f08fb9220ba"},
+]
+
+[package.dependencies]
+cffi = ">=1.4.1"
+
+[package.extras]
+docs = ["sphinx (>=1.6.5)", "sphinx-rtd-theme"]
+tests = ["hypothesis (>=3.27.0)", "pytest (>=3.2.1,!=3.3.0)"]
+
 [[package]]
 name = "pyrsistent"
 version = "0.19.3"
@@ -1935,6 +2188,91 @@ files = [
     {file = "websockets-11.0.2.tar.gz", hash = "sha256:b1a69701eb98ed83dd099de4a686dc892c413d974fa31602bc00aca7cb988ac9"},
 ]
 
+[[package]]
+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 = [
+    {file = "wrapt-1.15.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:ca1cccf838cd28d5a0883b342474c630ac48cac5df0ee6eacc9c7290f76b11c1"},
+    {file = "wrapt-1.15.0-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:e826aadda3cae59295b95343db8f3d965fb31059da7de01ee8d1c40a60398b29"},
+    {file = "wrapt-1.15.0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:5fc8e02f5984a55d2c653f5fea93531e9836abbd84342c1d1e17abc4a15084c2"},
+    {file = "wrapt-1.15.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:96e25c8603a155559231c19c0349245eeb4ac0096fe3c1d0be5c47e075bd4f46"},
+    {file = "wrapt-1.15.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:40737a081d7497efea35ab9304b829b857f21558acfc7b3272f908d33b0d9d4c"},
+    {file = "wrapt-1.15.0-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:f87ec75864c37c4c6cb908d282e1969e79763e0d9becdfe9fe5473b7bb1e5f09"},
+    {file = "wrapt-1.15.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:1286eb30261894e4c70d124d44b7fd07825340869945c79d05bda53a40caa079"},
+    {file = "wrapt-1.15.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:493d389a2b63c88ad56cdc35d0fa5752daac56ca755805b1b0c530f785767d5e"},
+    {file = "wrapt-1.15.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:58d7a75d731e8c63614222bcb21dd992b4ab01a399f1f09dd82af17bbfc2368a"},
+    {file = "wrapt-1.15.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:21f6d9a0d5b3a207cdf7acf8e58d7d13d463e639f0c7e01d82cdb671e6cb7923"},
+    {file = "wrapt-1.15.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ce42618f67741d4697684e501ef02f29e758a123aa2d669e2d964ff734ee00ee"},
+    {file = "wrapt-1.15.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41d07d029dd4157ae27beab04d22b8e261eddfc6ecd64ff7000b10dc8b3a5727"},
+    {file = "wrapt-1.15.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:54accd4b8bc202966bafafd16e69da9d5640ff92389d33d28555c5fd4f25ccb7"},
+    {file = "wrapt-1.15.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2fbfbca668dd15b744418265a9607baa970c347eefd0db6a518aaf0cfbd153c0"},
+    {file = "wrapt-1.15.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:76e9c727a874b4856d11a32fb0b389afc61ce8aaf281ada613713ddeadd1cfec"},
+    {file = "wrapt-1.15.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e20076a211cd6f9b44a6be58f7eeafa7ab5720eb796975d0c03f05b47d89eb90"},
+    {file = "wrapt-1.15.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a74d56552ddbde46c246b5b89199cb3fd182f9c346c784e1a93e4dc3f5ec9975"},
+    {file = "wrapt-1.15.0-cp310-cp310-win32.whl", hash = "sha256:26458da5653aa5b3d8dc8b24192f574a58984c749401f98fff994d41d3f08da1"},
+    {file = "wrapt-1.15.0-cp310-cp310-win_amd64.whl", hash = "sha256:75760a47c06b5974aa5e01949bf7e66d2af4d08cb8c1d6516af5e39595397f5e"},
+    {file = "wrapt-1.15.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ba1711cda2d30634a7e452fc79eabcadaffedf241ff206db2ee93dd2c89a60e7"},
+    {file = "wrapt-1.15.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:56374914b132c702aa9aa9959c550004b8847148f95e1b824772d453ac204a72"},
+    {file = "wrapt-1.15.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a89ce3fd220ff144bd9d54da333ec0de0399b52c9ac3d2ce34b569cf1a5748fb"},
+    {file = "wrapt-1.15.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3bbe623731d03b186b3d6b0d6f51865bf598587c38d6f7b0be2e27414f7f214e"},
+    {file = "wrapt-1.15.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3abbe948c3cbde2689370a262a8d04e32ec2dd4f27103669a45c6929bcdbfe7c"},
+    {file = "wrapt-1.15.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:b67b819628e3b748fd3c2192c15fb951f549d0f47c0449af0764d7647302fda3"},
+    {file = "wrapt-1.15.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:7eebcdbe3677e58dd4c0e03b4f2cfa346ed4049687d839adad68cc38bb559c92"},
+    {file = "wrapt-1.15.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:74934ebd71950e3db69960a7da29204f89624dde411afbfb3b4858c1409b1e98"},
+    {file = "wrapt-1.15.0-cp311-cp311-win32.whl", hash = "sha256:bd84395aab8e4d36263cd1b9308cd504f6cf713b7d6d3ce25ea55670baec5416"},
+    {file = "wrapt-1.15.0-cp311-cp311-win_amd64.whl", hash = "sha256:a487f72a25904e2b4bbc0817ce7a8de94363bd7e79890510174da9d901c38705"},
+    {file = "wrapt-1.15.0-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:4ff0d20f2e670800d3ed2b220d40984162089a6e2c9646fdb09b85e6f9a8fc29"},
+    {file = "wrapt-1.15.0-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:9ed6aa0726b9b60911f4aed8ec5b8dd7bf3491476015819f56473ffaef8959bd"},
+    {file = "wrapt-1.15.0-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:896689fddba4f23ef7c718279e42f8834041a21342d95e56922e1c10c0cc7afb"},
+    {file = "wrapt-1.15.0-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:75669d77bb2c071333417617a235324a1618dba66f82a750362eccbe5b61d248"},
+    {file = "wrapt-1.15.0-cp35-cp35m-win32.whl", hash = "sha256:fbec11614dba0424ca72f4e8ba3c420dba07b4a7c206c8c8e4e73f2e98f4c559"},
+    {file = "wrapt-1.15.0-cp35-cp35m-win_amd64.whl", hash = "sha256:fd69666217b62fa5d7c6aa88e507493a34dec4fa20c5bd925e4bc12fce586639"},
+    {file = "wrapt-1.15.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:b0724f05c396b0a4c36a3226c31648385deb6a65d8992644c12a4963c70326ba"},
+    {file = "wrapt-1.15.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bbeccb1aa40ab88cd29e6c7d8585582c99548f55f9b2581dfc5ba68c59a85752"},
+    {file = "wrapt-1.15.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:38adf7198f8f154502883242f9fe7333ab05a5b02de7d83aa2d88ea621f13364"},
+    {file = "wrapt-1.15.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:578383d740457fa790fdf85e6d346fda1416a40549fe8db08e5e9bd281c6a475"},
+    {file = "wrapt-1.15.0-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:a4cbb9ff5795cd66f0066bdf5947f170f5d63a9274f99bdbca02fd973adcf2a8"},
+    {file = "wrapt-1.15.0-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:af5bd9ccb188f6a5fdda9f1f09d9f4c86cc8a539bd48a0bfdc97723970348418"},
+    {file = "wrapt-1.15.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:b56d5519e470d3f2fe4aa7585f0632b060d532d0696c5bdfb5e8319e1d0f69a2"},
+    {file = "wrapt-1.15.0-cp36-cp36m-win32.whl", hash = "sha256:77d4c1b881076c3ba173484dfa53d3582c1c8ff1f914c6461ab70c8428b796c1"},
+    {file = "wrapt-1.15.0-cp36-cp36m-win_amd64.whl", hash = "sha256:077ff0d1f9d9e4ce6476c1a924a3332452c1406e59d90a2cf24aeb29eeac9420"},
+    {file = "wrapt-1.15.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:5c5aa28df055697d7c37d2099a7bc09f559d5053c3349b1ad0c39000e611d317"},
+    {file = "wrapt-1.15.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3a8564f283394634a7a7054b7983e47dbf39c07712d7b177b37e03f2467a024e"},
+    {file = "wrapt-1.15.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:780c82a41dc493b62fc5884fb1d3a3b81106642c5c5c78d6a0d4cbe96d62ba7e"},
+    {file = "wrapt-1.15.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e169e957c33576f47e21864cf3fc9ff47c223a4ebca8960079b8bd36cb014fd0"},
+    {file = "wrapt-1.15.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:b02f21c1e2074943312d03d243ac4388319f2456576b2c6023041c4d57cd7019"},
+    {file = "wrapt-1.15.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:f2e69b3ed24544b0d3dbe2c5c0ba5153ce50dcebb576fdc4696d52aa22db6034"},
+    {file = "wrapt-1.15.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:d787272ed958a05b2c86311d3a4135d3c2aeea4fc655705f074130aa57d71653"},
+    {file = "wrapt-1.15.0-cp37-cp37m-win32.whl", hash = "sha256:02fce1852f755f44f95af51f69d22e45080102e9d00258053b79367d07af39c0"},
+    {file = "wrapt-1.15.0-cp37-cp37m-win_amd64.whl", hash = "sha256:abd52a09d03adf9c763d706df707c343293d5d106aea53483e0ec8d9e310ad5e"},
+    {file = "wrapt-1.15.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cdb4f085756c96a3af04e6eca7f08b1345e94b53af8921b25c72f096e704e145"},
+    {file = "wrapt-1.15.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:230ae493696a371f1dbffaad3dafbb742a4d27a0afd2b1aecebe52b740167e7f"},
+    {file = "wrapt-1.15.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63424c681923b9f3bfbc5e3205aafe790904053d42ddcc08542181a30a7a51bd"},
+    {file = "wrapt-1.15.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d6bcbfc99f55655c3d93feb7ef3800bd5bbe963a755687cbf1f490a71fb7794b"},
+    {file = "wrapt-1.15.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c99f4309f5145b93eca6e35ac1a988f0dc0a7ccf9ccdcd78d3c0adf57224e62f"},
+    {file = "wrapt-1.15.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b130fe77361d6771ecf5a219d8e0817d61b236b7d8b37cc045172e574ed219e6"},
+    {file = "wrapt-1.15.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:96177eb5645b1c6985f5c11d03fc2dbda9ad24ec0f3a46dcce91445747e15094"},
+    {file = "wrapt-1.15.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d5fe3e099cf07d0fb5a1e23d399e5d4d1ca3e6dfcbe5c8570ccff3e9208274f7"},
+    {file = "wrapt-1.15.0-cp38-cp38-win32.whl", hash = "sha256:abd8f36c99512755b8456047b7be10372fca271bf1467a1caa88db991e7c421b"},
+    {file = "wrapt-1.15.0-cp38-cp38-win_amd64.whl", hash = "sha256:b06fa97478a5f478fb05e1980980a7cdf2712015493b44d0c87606c1513ed5b1"},
+    {file = "wrapt-1.15.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2e51de54d4fb8fb50d6ee8327f9828306a959ae394d3e01a1ba8b2f937747d86"},
+    {file = "wrapt-1.15.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0970ddb69bba00670e58955f8019bec4a42d1785db3faa043c33d81de2bf843c"},
+    {file = "wrapt-1.15.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76407ab327158c510f44ded207e2f76b657303e17cb7a572ffe2f5a8a48aa04d"},
+    {file = "wrapt-1.15.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cd525e0e52a5ff16653a3fc9e3dd827981917d34996600bbc34c05d048ca35cc"},
+    {file = "wrapt-1.15.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9d37ac69edc5614b90516807de32d08cb8e7b12260a285ee330955604ed9dd29"},
+    {file = "wrapt-1.15.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:078e2a1a86544e644a68422f881c48b84fef6d18f8c7a957ffd3f2e0a74a0d4a"},
+    {file = "wrapt-1.15.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:2cf56d0e237280baed46f0b5316661da892565ff58309d4d2ed7dba763d984b8"},
+    {file = "wrapt-1.15.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:7dc0713bf81287a00516ef43137273b23ee414fe41a3c14be10dd95ed98a2df9"},
+    {file = "wrapt-1.15.0-cp39-cp39-win32.whl", hash = "sha256:46ed616d5fb42f98630ed70c3529541408166c22cdfd4540b88d5f21006b0eff"},
+    {file = "wrapt-1.15.0-cp39-cp39-win_amd64.whl", hash = "sha256:eef4d64c650f33347c1f9266fa5ae001440b232ad9b98f1f43dfe7a79435c0a6"},
+    {file = "wrapt-1.15.0-py3-none-any.whl", hash = "sha256:64b1df0f83706b4ef4cfb4fb0e4c2669100fd7ecacfb59e091fad300d4e04640"},
+    {file = "wrapt-1.15.0.tar.gz", hash = "sha256:d06730c6aed78cee4126234cf2d071e01b44b915e725a6cb439a879ec9754a3a"},
+]
+
 [[package]]
 name = "yarl"
 version = "1.9.2"
@@ -2042,4 +2380,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p
 [metadata]
 lock-version = "2.0"
 python-versions = "^3.8.1"
-content-hash = "3fcd19c11b9c338a181e591b56e21d59c7834abff431fb9f40cc1ea874b64557"
+content-hash = "83880c8de27a4094fa8e695bd8db5d4053fc2d61ffc028f09cfa097f315c35f2"
diff --git a/continuedev/pyproject.toml b/continuedev/pyproject.toml
index 0abc9504..64d5e90c 100644
--- a/continuedev/pyproject.toml
+++ b/continuedev/pyproject.toml
@@ -27,6 +27,8 @@ directory-tree = "^0.0.3.1"
 anthropic = "^0.3.4"
 chevron = "^0.14.0"
 psutil = "^5.9.5"
+meilisearch = "^0.28.1"
+pygithub = "^1.59.0"
 
 [tool.poetry.scripts]
 typegen = "src.continuedev.models.generate_json_schema:main" 
diff --git a/continuedev/src/continuedev/core/autopilot.py b/continuedev/src/continuedev/core/autopilot.py
index abda50b0..c0f95414 100644
--- a/continuedev/src/continuedev/core/autopilot.py
+++ b/continuedev/src/continuedev/core/autopilot.py
@@ -9,10 +9,12 @@ from pydantic import root_validator
 from ..models.filesystem import RangeInFileWithContents
 from ..models.filesystem_edit import FileEditWithFullContents
 from .observation import Observation, InternalErrorObservation
+from .context import ContextItem, ContextItemDescription, ContextItemId, ContextManager
+from ..libs.context_providers.highlighted_code_context_provider import HighlightedCodeContextProvider
 from ..server.ide_protocol import AbstractIdeProtocolServer
 from ..libs.util.queue import AsyncSubscriptionQueue
 from ..models.main import ContinueBaseModel
-from .main import Context, ContinueCustomException, HighlightedRangeContext, Policy, History, FullState, Step, HistoryNode
+from .main import Context, ContinueCustomException, Policy, History, FullState, Step, HistoryNode
 from ..steps.core.core import ReversibleStep, ManualEditStep, UserInputStep
 from ..libs.util.telemetry import capture_event
 from .sdk import ContinueSDK
@@ -47,10 +49,11 @@ class Autopilot(ContinueBaseModel):
     history: History = History.from_empty()
     context: Context = Context()
     full_state: Union[FullState, None] = None
-    _on_update_callbacks: List[Callable[[FullState], None]] = []
-
+    context_manager: Union[ContextManager, None] = None
     continue_sdk: ContinueSDK = None
 
+    _on_update_callbacks: List[Callable[[FullState], None]] = []
+
     _active: bool = False
     _should_halt: bool = False
     _main_user_input_queue: List[str] = []
@@ -62,6 +65,14 @@ class Autopilot(ContinueBaseModel):
     async def create(cls, policy: Policy, ide: AbstractIdeProtocolServer, full_state: FullState) -> "Autopilot":
         autopilot = cls(ide=ide, policy=policy)
         autopilot.continue_sdk = await ContinueSDK.create(autopilot)
+
+        # Load documents into the search index
+        autopilot.context_manager = ContextManager(
+            autopilot.continue_sdk.config.context_providers + [
+                HighlightedCodeContextProvider(ide=ide)
+            ])
+        await autopilot.context_manager.load_index()
+
         return autopilot
 
     class Config:
@@ -75,15 +86,16 @@ class Autopilot(ContinueBaseModel):
             values['history'] = full_state.history
         return values
 
-    def get_full_state(self) -> FullState:
+    async def get_full_state(self) -> FullState:
         full_state = FullState(
             history=self.history,
             active=self._active,
             user_input_queue=self._main_user_input_queue,
             default_model=self.continue_sdk.config.default_model,
-            highlighted_ranges=self._highlighted_ranges,
             slash_commands=self.get_available_slash_commands(),
-            adding_highlighted_code=self._adding_highlighted_code,
+            adding_highlighted_code=self.context_manager.context_providers[
+                "code"].adding_highlighted_code,
+            selected_context_items=await self.context_manager.get_selected_items()
         )
         self.full_state = full_state
         return full_state
@@ -104,8 +116,8 @@ class Autopilot(ContinueBaseModel):
         self._main_user_input_queue = []
         self._active = False
 
-        # Also remove all context
-        self._highlighted_ranges = []
+        # Clear context
+        await self.context_manager.clear_context()
 
         await self.update_subscribers()
 
@@ -114,7 +126,7 @@ class Autopilot(ContinueBaseModel):
         self._on_update_callbacks.append(callback)
 
     async def update_subscribers(self):
-        full_state = self.get_full_state()
+        full_state = await self.get_full_state()
         for callback in self._on_update_callbacks:
             await callback(full_state)
 
@@ -159,81 +171,10 @@ class Autopilot(ContinueBaseModel):
                     step = tb_step.step({"output": output, **tb_step.params})
                     await self._run_singular_step(step)
 
-    _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
-
-    def _disambiguate_highlighted_ranges(self):
-        """If any files have the same name, also display their folder name"""
-        name_status: Dict[str, set] = {
-        }  # basename -> set of full paths with that basename
-        for rif in self._highlighted_ranges:
-            basename = os.path.basename(rif.range.filepath)
-            if basename in name_status:
-                name_status[basename].add(rif.range.filepath)
-            else:
-                name_status[basename] = {rif.range.filepath}
-
-        for rif in self._highlighted_ranges:
-            basename = os.path.basename(rif.range.filepath)
-            if len(name_status[basename]) > 1:
-                rif.display_name = os.path.join(
-                    os.path.basename(os.path.dirname(rif.range.filepath)), basename)
-            else:
-                rif.display_name = basename
-
     async def handle_highlighted_code(self, range_in_files: List[RangeInFileWithContents]):
-        # Filter out rifs from ~/.continue/diffs folder
-        range_in_files = [
-            rif for rif in range_in_files if not os.path.dirname(rif.filepath) == os.path.expanduser("~/.continue/diffs")]
-
-        # Make sure all filepaths are relative to workspace
-        workspace_path = self.continue_sdk.ide.workspace_directory
-
-        # If not adding highlighted code
-        if not self._adding_highlighted_code:
-            if len(self._highlighted_ranges) == 1 and len(range_in_files) <= 1 and (len(range_in_files) == 0 or range_in_files[0].range.start == range_in_files[0].range.end):
-                # If un-highlighting the range to edit, then remove the range
-                self._highlighted_ranges = []
-                await self.update_subscribers()
-            elif len(range_in_files) > 0:
-                # Otherwise, replace the current range with the new one
-                # This is the first range to be highlighted
-                self._highlighted_ranges = [HighlightedRangeContext(
-                    range=range_in_files[0], editing=True, pinned=False, display_name=os.path.basename(range_in_files[0].filepath))]
-                await self.update_subscribers()
-            return
-
-        # If current range overlaps with any others, delete them and only keep the new range
-        new_ranges = []
-        for i, rif in enumerate(self._highlighted_ranges):
-            found_overlap = False
-            for new_rif in range_in_files:
-                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.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 + [HighlightedRangeContext(
-            range=rif, editing=False, pinned=False, display_name=os.path.basename(rif.filepath)
-        ) for rif in range_in_files]
-
-        self._make_sure_is_editing_range()
-        self._disambiguate_highlighted_ranges()
+        # Add to context manager
+        await self.context_manager.context_providers["code"].handle_highlighted_code(
+            range_in_files)
 
         await self.update_subscribers()
 
@@ -250,29 +191,16 @@ class Autopilot(ContinueBaseModel):
 
         await self.update_subscribers()
 
-    async def delete_context_at_indices(self, indices: List[int]):
-        kept_ranges = []
-        for i, rif in enumerate(self._highlighted_ranges):
-            if i not in indices:
-                kept_ranges.append(rif)
-        self._highlighted_ranges = kept_ranges
-
-        self._make_sure_is_editing_range()
-
+    async def delete_context_with_ids(self, ids: List[str]):
+        await self.context_manager.delete_context_with_ids(ids)
         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
+        self.context_manager.context_providers["code"].adding_highlighted_code = not self.context_manager.context_providers["code"].adding_highlighted_code
         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
+    async def set_editing_at_ids(self, ids: List[str]):
+        self.context_manager.context_providers["code"].set_editing_at_ids(ids)
         await self.update_subscribers()
 
     async def _run_singular_step(self, step: "Step", is_future_step: bool = False) -> Coroutine[Observation, None, None]:
@@ -437,10 +365,6 @@ 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.
@@ -456,3 +380,7 @@ class Autopilot(ContinueBaseModel):
         await self._request_halt()
         await self.reverse_to_index(index)
         await self.run_from_step(UserInputStep(user_input=user_input))
+
+    async def select_context_item(self, id: str, query: str):
+        await self.context_manager.select_context_item(id, query)
+        await self.update_subscribers()
diff --git a/continuedev/src/continuedev/core/config.py b/continuedev/src/continuedev/core/config.py
index 54f15143..bb9ca323 100644
--- a/continuedev/src/continuedev/core/config.py
+++ b/continuedev/src/continuedev/core/config.py
@@ -1,6 +1,7 @@
 import json
 import os
 from .main import Step
+from .context import ContextProvider
 from pydantic import BaseModel, validator
 from typing import List, Literal, Optional, Dict, Type, Union
 import yaml
@@ -50,6 +51,8 @@ class ContinueConfig(BaseModel):
     system_message: Optional[str] = None
     azure_openai_info: Optional[AzureInfo] = None
 
+    context_providers: List[ContextProvider] = []
+
     # Want to force these to be the slash commands for now
     @validator('slash_commands', pre=True)
     def default_slash_commands_validator(cls, v):
diff --git a/continuedev/src/continuedev/core/context.py b/continuedev/src/continuedev/core/context.py
new file mode 100644
index 00000000..67bba651
--- /dev/null
+++ b/continuedev/src/continuedev/core/context.py
@@ -0,0 +1,205 @@
+
+from abc import abstractmethod
+from typing import Dict, List
+import meilisearch
+from pydantic import BaseModel
+
+
+from .main import ChatMessage, ContextItem, ContextItemDescription, ContextItemId
+from ..server.meilisearch_server import check_meilisearch_running
+
+
+SEARCH_INDEX_NAME = "continue_context_items"
+
+
+class ContextProvider(BaseModel):
+    """
+    The ContextProvider class is a plugin that lets you provide new information to the LLM by typing '@'.
+    When you type '@', the context provider will be asked to populate a list of options.
+    These options will be updated on each keystroke.
+    When you hit enter on an option, the context provider will add that item to the autopilot's list of context (which is all stored in the ContextManager object).
+    """
+
+    title: str
+
+    selected_items: List[ContextItem] = []
+
+    async def get_selected_items(self) -> List[ContextItem]:
+        """
+        Returns all of the selected ContextItems.
+
+        Default implementation simply returns self.selected_items.
+
+        Other implementations may add an async processing step.
+        """
+        return self.selected_items
+
+    @abstractmethod
+    async def provide_context_items(self) -> List[ContextItem]:
+        """
+        Provide documents for search index. This is run on startup.
+
+        This is the only method that must be implemented.
+        """
+
+    async def get_chat_messages(self) -> List[ChatMessage]:
+        """
+        Returns all of the chat messages for the context provider.
+
+        Default implementation has a string template.
+        """
+        return [ChatMessage(role="user", content=f"{item.description.name}: {item.description.description}\n\n{item.content}", summary=item.description.description) for item in await self.get_selected_items()]
+
+    async def get_item(self, id: ContextItemId, query: str, search_client: meilisearch.Client) -> ContextItem:
+        """
+        Returns the ContextItem with the given id.
+
+        Default implementation uses the search index to get the item.
+        """
+        result = search_client.index(
+            SEARCH_INDEX_NAME).get_document(id.to_string())
+        return ContextItem(
+            description=ContextItemDescription(
+                name=result.name,
+                description=result.description,
+                id=id
+            ),
+            content=result.content
+        )
+
+    async def delete_context_with_ids(self, ids: List[ContextItemId]):
+        """
+        Deletes the ContextItems with the given IDs, lets ContextProviders recalculate.
+
+        Default implementation simply deletes those with the given ids.
+        """
+        id_strings = {id.to_string() for id in ids}
+        self.selected_items = list(
+            filter(lambda item: item.description.id.to_string() not in id_strings, self.selected_items))
+
+    async def clear_context(self):
+        """
+        Clears all context.
+
+        Default implementation simply clears the selected items.
+        """
+        self.selected_items = []
+
+    async def add_context_item(self, id: ContextItemId, query: str, search_client: meilisearch.Client):
+        """
+        Adds the given ContextItem to the list of ContextItems.
+
+        Default implementation simply appends the item, not allowing duplicates.
+
+        This method also allows you not to have to load all of the information until an item is selected.
+        """
+
+        # Don't add duplicate context
+        for item in self.selected_items:
+            if item.description.id.item_id == id.item_id:
+                return
+
+        new_item = await self.get_item(id, query, search_client)
+        self.selected_items.append(new_item)
+
+
+class ContextManager:
+    """
+    The context manager is responsible for storing the context to be passed to the LLM, including
+    - ContextItems (highlighted code, GitHub Issues, etc.)
+    - ChatMessages in the history
+    - System Message
+    - Functions
+
+    It is responsible for compiling all of this information into a single prompt without exceeding the token limit.
+    """
+
+    async def get_selected_items(self) -> List[ContextItem]:
+        """
+        Returns all of the selected ContextItems.
+        """
+        return sum([await provider.get_selected_items() for provider in self.context_providers.values()], [])
+
+    async def get_chat_messages(self) -> List[ChatMessage]:
+        """
+        Returns chat messages from each provider.
+        """
+        return sum([await provider.get_chat_messages() for provider in self.context_providers.values()], [])
+
+    search_client: meilisearch.Client
+
+    def __init__(self, context_providers: List[ContextProvider]):
+        self.search_client = meilisearch.Client('http://localhost:7700')
+
+        # If meilisearch isn't running, don't use any ContextProviders that might depend on it
+        if not check_meilisearch_running():
+            context_providers = list(
+                filter(lambda cp: cp.title == "code", context_providers))
+
+        self.context_providers = {
+            prov.title: prov for prov in context_providers}
+        self.provider_titles = {
+            provider.title for provider in context_providers}
+
+    async def load_index(self):
+        for _, provider in self.context_providers.items():
+            context_items = await provider.provide_context_items()
+            documents = [
+                {
+                    "id": item.description.id.to_string(),
+                    "name": item.description.name,
+                    "description": item.description.description,
+                    "content": item.content
+                }
+                for item in context_items
+            ]
+            if len(documents) > 0:
+                self.search_client.index(
+                    SEARCH_INDEX_NAME).add_documents(documents)
+
+    # def compile_chat_messages(self, max_tokens: int) -> List[Dict]:
+    #     """
+    #     Compiles the chat prompt into a single string.
+    #     """
+    #     return compile_chat_messages(self.model, self.chat_history, max_tokens, self.prompt, self.functions, self.system_message)
+
+    async def select_context_item(self, id: str, query: str):
+        """
+        Selects the ContextItem with the given id.
+        """
+        id: ContextItemId = ContextItemId.from_string(id)
+        if id.provider_title not in self.provider_titles:
+            raise ValueError(
+                f"Context provider with title {id.provider_title} not found")
+
+        await self.context_providers[id.provider_title].add_context_item(id, query, self.search_client)
+
+    async def delete_context_with_ids(self, ids: List[str]):
+        """
+        Deletes the ContextItems with the given IDs, lets ContextProviders recalculate.
+        """
+
+        # Group by provider title
+        provider_title_to_ids: Dict[str, List[ContextItemId]] = {}
+        for id in ids:
+            id: ContextItemId = ContextItemId.from_string(id)
+            if id.provider_title not in provider_title_to_ids:
+                provider_title_to_ids[id.provider_title] = []
+            provider_title_to_ids[id.provider_title].append(id)
+
+        # Recalculate context for each updated provider
+        for provider_title, ids in provider_title_to_ids.items():
+            await self.context_providers[provider_title].delete_context_with_ids(ids)
+
+    async def clear_context(self):
+        """
+        Clears all context.
+        """
+        for provider in self.context_providers.values():
+            await self.context_providers[provider.title].clear_context()
+
+
+"""
+Should define "ArgsTransformer" and "PromptTransformer" classes for the different LLMs. A standard way for them to ingest the
+same format of prompts so you don't have to redo all of this logic.
+"""
diff --git a/continuedev/src/continuedev/core/context_manager.py b/continuedev/src/continuedev/core/context_manager.py
deleted file mode 100644
index 37905535..00000000
--- a/continuedev/src/continuedev/core/context_manager.py
+++ /dev/null
@@ -1,119 +0,0 @@
-
-from abc import ABC, abstractmethod, abstractproperty
-from ast import List
-from pydantic import BaseModel
-
-from ..libs.util.count_tokens import compile_chat_messages
-
-
-class ContextItemDescription(BaseModel):
-    """
-    A ContextItemDescription is a description of a ContextItem that is displayed to the user when they type '@'.
-
-    The id can be used to retrieve the ContextItem from the ContextManager.
-    """
-    name: str
-    description: str
-    id:  str
-
-
-class ContextItem(BaseModel):
-    """
-    A ContextItem is a single item that is stored in the ContextManager.
-    """
-    description: ContextItemDescription
-    content: str
-
-
-class ContextManager(ABC):
-    """
-    The context manager is responsible for storing the context to be passed to the LLM, including
-    - ContextItems (highlighted code, GitHub Issues, etc.)
-    - ChatMessages in the history
-    - System Message
-    - Functions
-
-    It is responsible for compiling all of this information into a single prompt without exceeding the token limit.
-    """
-
-    def compile_chat_messages(self, max_tokens: int) -> List[Dict]:
-        """
-        Compiles the chat prompt into a single string.
-        """
-        return compile_chat_messages(self.model, self.chat_history, max_tokens, self.prompt, self.functions, self.system_message)
-
-
-"""
-Should define "ArgsTransformer" and "PromptTransformer" classes for the different LLMs. A standard way for them to ingest the
-same format of prompts so you don't have to redo all of this logic.
-"""
-
-
-class ContextProvider(ABC):
-    """
-    The ContextProvider class is a plugin that lets you provide new information to the LLM by typing '@'.
-    When you type '@', the context provider will be asked to populate a list of options.
-    These options will be updated on each keystroke.
-    When you hit enter on an option, the context provider will add that item to the autopilot's list of context (which is all stored in the ContextManager object).
-    """
-
-    title: str
-
-    @abstractmethod
-    async def load(self):
-        """
-        Loads the ContextProvider, possibly reading persisted data from disk. This will be called on startup.
-        """
-
-    @abstractmethod
-    async def save(self):
-        """
-        Saves the ContextProvider, possibly writing persisted data to disk. This will be called upon cache refresh.
-        """
-
-    @abstractmethod
-    async def refresh_cache(self):
-        """
-        Refreshes the cache of items. This will be called on startup and periodically.
-        """
-
-    @abstractmethod
-    async def get_item_descriptions(self, query: str) -> List[ContextItemDescription]:
-        """
-        Returns a list of options that should be displayed to the user.
-        """
-
-    @abstractmethod
-    async def get_item(self, id: str) -> ContextItem:
-        """
-        Returns the ContextItem with the given id. This allows you not to have to load all of the information until an item is selected.
-        """
-
-    @abstractmethod
-    async def should_refresh(self) -> bool:
-        """
-        Returns whether the ContextProvider should be refreshed.
-
-        For example, embeddings might need to be recalculated after commits,
-        or GitHub issues might need to be refreshed after a new issue is created.
-
-        This method will be called every startup? Every once in a while? Every hour?
-        User defined? Maybe just have a schedule instead of this method.
-        """
-
-
-class GitHubIssuesContextProvider(ContextProvider):
-    """
-    The GitHubIssuesContextProvider is a ContextProvider that allows you to search GitHub issues in a repo.
-    """
-
-    title = "issues"
-
-    def __init__(self, repo: str):
-        self.repo = repo
-
-    async def get_item_descriptions(self, query: str) -> List[ContextItemDescription]:
-        pass
-
-    async def get_item(self, id: str) -> ContextItem:
-        pass
diff --git a/continuedev/src/continuedev/core/main.py b/continuedev/src/continuedev/core/main.py
index 50d01f8d..6c6adccc 100644
--- a/continuedev/src/continuedev/core/main.py
+++ b/continuedev/src/continuedev/core/main.py
@@ -1,12 +1,11 @@
 import json
-from textwrap import dedent
-from typing import Callable, Coroutine, Dict, Generator, List, Literal, Tuple, Union
+from typing import Coroutine, Dict, List, Literal, Union
+from pydantic.schema import schema
+
 
-from ..models.filesystem import RangeInFileWithContents
 from ..models.main import ContinueBaseModel
-from pydantic import validator
+from pydantic import BaseModel, validator
 from .observation import Observation
-from pydantic.schema import schema
 
 ChatMessageRole = Literal["assistant", "user", "system", "function"]
 
@@ -201,12 +200,48 @@ class SlashCommandDescription(ContinueBaseModel):
     description: str
 
 
-class HighlightedRangeContext(ContinueBaseModel):
-    """Context for a highlighted range"""
-    range: RangeInFileWithContents
-    editing: bool
-    pinned: bool
-    display_name: str
+class ContextItemId(BaseModel):
+    """
+    A ContextItemId is a unique identifier for a ContextItem.
+    """
+    provider_title: str
+    item_id: str
+
+    def to_string(self) -> str:
+        return f"{self.provider_title}-{self.item_id}"
+
+    @staticmethod
+    def from_string(string: str) -> 'ContextItemId':
+        provider_title, item_id = string.split('-')
+        return ContextItemId(provider_title=provider_title, item_id=item_id)
+
+
+class ContextItemDescription(BaseModel):
+    """
+    A ContextItemDescription is a description of a ContextItem that is displayed to the user when they type '@'.
+
+    The id can be used to retrieve the ContextItem from the ContextManager.
+    """
+    name: str
+    description: str
+    id:  ContextItemId
+
+
+class ContextItem(BaseModel):
+    """
+    A ContextItem is a single item that is stored in the ContextManager.
+    """
+    description: ContextItemDescription
+    content: str
+
+    @validator('content', pre=True)
+    def content_must_be_string(cls, v):
+        if v is None:
+            return ''
+        return v
+
+    editing: bool = False
+    editable: bool = False
 
 
 class FullState(ContinueBaseModel):
@@ -215,9 +250,9 @@ class FullState(ContinueBaseModel):
     active: bool
     user_input_queue: List[str]
     default_model: str
-    highlighted_ranges: List[HighlightedRangeContext]
     slash_commands: List[SlashCommandDescription]
     adding_highlighted_code: bool
+    selected_context_items: List[ContextItem]
 
 
 class ContinueSDK:
diff --git a/continuedev/src/continuedev/core/sdk.py b/continuedev/src/continuedev/core/sdk.py
index 4100efa6..59f33707 100644
--- a/continuedev/src/continuedev/core/sdk.py
+++ b/continuedev/src/continuedev/core/sdk.py
@@ -3,8 +3,10 @@ from functools import cached_property
 from typing import Coroutine, Dict, Union
 import os
 
+
 from ..steps.core.core import DefaultModelEditCodeStep
 from ..models.main import Range
+from .context import ContextItem
 from .abstract_sdk import AbstractContinueSDK
 from .config import ContinueConfig, load_config, load_global_config, update_global_config
 from ..models.filesystem_edit import FileEdit, FileSystemEdit, AddFile, DeleteFile, AddDirectory, DeleteDirectory
@@ -289,28 +291,13 @@ class ContinueSDK(AbstractContinueSDK):
 
     async def get_chat_context(self) -> List[ChatMessage]:
         history_context = self.history.to_chat_history()
-        highlighted_code = [
-            hr.range for hr in self.__autopilot._highlighted_ranges]
-
-        preface = "The following code is highlighted"
-
-        # If no higlighted ranges, use first file as context
-        if len(highlighted_code) == 0:
-            preface = "The following file is open"
-            visible_files = await self.ide.getVisibleFiles()
-            if len(visible_files) > 0:
-                content = await self.ide.readFile(visible_files[0])
-                highlighted_code = [
-                    RangeInFileWithContents.from_entire_file(visible_files[0], content)]
-
-        for rif in highlighted_code:
-            msg = ChatMessage(content=f"{preface} ({rif.filepath}):\n```\n{rif.contents}\n```",
-                              role="user", summary=f"{preface}: {rif.filepath}")
-
-            # Don't insert after latest user message or function call
-            i = -1
-            if len(history_context) > 0 and (history_context[i].role == "user" or history_context[i].role == "function"):
-                i -= 1
+
+        context_messages: List[ChatMessage] = await self.__autopilot.context_manager.get_chat_messages()
+
+        # Insert at the end, but don't insert after latest user message or function call
+        i = -2 if (len(history_context) > 0 and (
+            history_context[-1].role == "user" or history_context[-1].role == "function")) else -1
+        for msg in context_messages:
             history_context.insert(i, msg)
 
         return history_context
diff --git a/continuedev/src/continuedev/libs/context_providers/highlighted_code_context_provider.py b/continuedev/src/continuedev/libs/context_providers/highlighted_code_context_provider.py
new file mode 100644
index 00000000..23d4fc86
--- /dev/null
+++ b/continuedev/src/continuedev/libs/context_providers/highlighted_code_context_provider.py
@@ -0,0 +1,191 @@
+import os
+from typing import Any, Dict, List
+
+import meilisearch
+from ...core.main import ChatMessage
+from ...models.filesystem import RangeInFile, RangeInFileWithContents
+from ...core.context import ContextItem, ContextItemDescription, ContextItemId
+from pydantic import BaseModel
+
+
+class HighlightedRangeContextItem(BaseModel):
+    rif: RangeInFileWithContents
+    item: ContextItem
+
+
+class HighlightedCodeContextProvider(BaseModel):
+    """
+    The ContextProvider class is a plugin that lets you provide new information to the LLM by typing '@'.
+    When you type '@', the context provider will be asked to populate a list of options.
+    These options will be updated on each keystroke.
+    When you hit enter on an option, the context provider will add that item to the autopilot's list of context (which is all stored in the ContextManager object).
+    """
+
+    title = "code"
+
+    ide: Any  # IdeProtocolServer
+
+    highlighted_ranges: List[HighlightedRangeContextItem] = []
+    adding_highlighted_code: bool = False
+
+    should_get_fallback_context_item: bool = True
+    last_added_fallback: bool = False
+
+    async def _get_fallback_context_item(self) -> HighlightedRangeContextItem:
+        if not self.should_get_fallback_context_item:
+            return None
+
+        visible_files = await self.ide.getVisibleFiles()
+        if len(visible_files) > 0:
+            content = await self.ide.readFile(visible_files[0])
+            rif = RangeInFileWithContents.from_entire_file(
+                visible_files[0], content)
+
+            item = self._rif_to_context_item(rif, 0, True)
+            item.description.name = self._rif_to_name(
+                rif, show_line_nums=False)
+
+            self.last_added_fallback = True
+            return HighlightedRangeContextItem(rif=rif, item=item)
+
+        return None
+
+    async def get_selected_items(self) -> List[ContextItem]:
+        items = [hr.item for hr in self.highlighted_ranges]
+
+        if len(items) == 0 and (fallback_item := await self._get_fallback_context_item()):
+            items = [fallback_item.item]
+
+        return items
+
+    async def get_chat_messages(self) -> List[ContextItem]:
+        ranges = self.highlighted_ranges
+        if len(ranges) == 0 and (fallback_item := await self._get_fallback_context_item()):
+            ranges = [fallback_item]
+
+        return [ChatMessage(
+            role="user",
+            content=f"Code in this file is highlighted ({r.rif.filepath}):\n```\n{r.rif.contents}\n```",
+            summary=f"Code in this file is highlighted: {r.rif.filepath}"
+        ) for r in ranges]
+
+    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.item.editing, self.highlighted_ranges)):
+            self.highlighted_ranges[0].item.editing = True
+
+    def _disambiguate_highlighted_ranges(self):
+        """If any files have the same name, also display their folder name"""
+        name_status: Dict[str, set] = {
+        }  # basename -> set of full paths with that basename
+        for hr in self.highlighted_ranges:
+            basename = os.path.basename(hr.rif.filepath)
+            if basename in name_status:
+                name_status[basename].add(hr.rif.filepath)
+            else:
+                name_status[basename] = {hr.rif.filepath}
+
+        for hr in self.highlighted_ranges:
+            if len(name_status[basename]) > 1:
+                hr.item.description.name = self._rif_to_name(hr.rif, display_filename=os.path.join(
+                    os.path.basename(os.path.dirname(hr.rif.filepath)), basename))
+            else:
+                hr.item.description.name = self._rif_to_name(
+                    hr.rif, display_filename=basename)
+
+    async def provide_context_items(self) -> List[ContextItem]:
+        return []
+
+    async def delete_context_with_ids(self, ids: List[ContextItemId]) -> List[ContextItem]:
+        indices_to_delete = [
+            int(id.item_id) for id in ids
+        ]
+
+        kept_ranges = []
+        for i, hr in enumerate(self.highlighted_ranges):
+            if i not in indices_to_delete:
+                kept_ranges.append(hr)
+        self.highlighted_ranges = kept_ranges
+
+        self._make_sure_is_editing_range()
+
+        if len(self.highlighted_ranges) == 0 and self.last_added_fallback:
+            self.should_get_fallback_context_item = False
+
+        return [hr.item for hr in self.highlighted_ranges]
+
+    def _rif_to_name(self, rif: RangeInFileWithContents, display_filename: str = None, show_line_nums: bool = True) -> str:
+        line_nums = f" ({rif.range.start.line + 1}-{rif.range.end.line + 1})" if show_line_nums else ""
+        return f"{display_filename or os.path.basename(rif.filepath)}{line_nums}"
+
+    def _rif_to_context_item(self, rif: RangeInFileWithContents, idx: int, editing: bool) -> ContextItem:
+        return ContextItem(
+            description=ContextItemDescription(
+                name=self._rif_to_name(rif),
+                description=rif.filepath,
+                id=ContextItemId(
+                    provider_title=self.title,
+                    item_id=str(idx)
+                )
+            ),
+            content=rif.contents,
+            editing=editing,
+            editable=True
+        )
+
+    async def handle_highlighted_code(self, range_in_files: List[RangeInFileWithContents]):
+        self.should_get_fallback_context_item = True
+        self.last_added_fallback = False
+
+        # Filter out rifs from ~/.continue/diffs folder
+        range_in_files = [
+            rif for rif in range_in_files if not os.path.dirname(rif.filepath) == os.path.expanduser("~/.continue/diffs")]
+
+        # If not adding highlighted code
+        if not self.adding_highlighted_code:
+            if len(self.highlighted_ranges) == 1 and len(range_in_files) <= 1 and (len(range_in_files) == 0 or range_in_files[0].range.start == range_in_files[0].range.end):
+                # If un-highlighting the range to edit, then remove the range
+                self.highlighted_ranges = []
+            elif len(range_in_files) > 0:
+                # Otherwise, replace the current range with the new one
+                # This is the first range to be highlighted
+                self.highlighted_ranges = [
+                    HighlightedRangeContextItem(
+                        rif=range_in_files[0],
+                        item=self._rif_to_context_item(range_in_files[0], 0, True))]
+
+            return
+
+        # If current range overlaps with any others, delete them and only keep the new range
+        new_ranges = []
+        for i, hr in enumerate(self.highlighted_ranges):
+            found_overlap = False
+            for new_rif in range_in_files:
+                if hr.rif.filepath == new_rif.filepath and hr.rif.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 hr.rif.filepath == new_rif.filepath and hr.rif.contents == new_rif.contents:
+                    found_overlap = True
+                    break
+
+            if not found_overlap:
+                new_ranges.append(HighlightedRangeContextItem(rif=hr.rif, item=self._rif_to_context_item(
+                    hr.rif, len(new_ranges), False)))
+
+        self.highlighted_ranges = new_ranges + [HighlightedRangeContextItem(rif=rif, item=self._rif_to_context_item(
+            rif, len(new_ranges) + idx, False)) for idx, rif in enumerate(range_in_files)]
+
+        self._make_sure_is_editing_range()
+        self._disambiguate_highlighted_ranges()
+
+    async def set_editing_at_ids(self, ids: List[str]):
+        for hr in self.highlighted_ranges:
+            hr.item.editing = hr.item.description.id.to_string() in ids
+
+    async def add_context_item(self, id: ContextItemId, query: str, search_client: meilisearch.Client, prev: List[ContextItem] = None) -> List[ContextItem]:
+        raise NotImplementedError()
diff --git a/continuedev/src/continuedev/libs/util/paths.py b/continuedev/src/continuedev/libs/util/paths.py
index fddef887..d6ce13b3 100644
--- a/continuedev/src/continuedev/libs/util/paths.py
+++ b/continuedev/src/continuedev/libs/util/paths.py
@@ -2,16 +2,26 @@ import os
 
 from ..constants.main import CONTINUE_SESSIONS_FOLDER, CONTINUE_GLOBAL_FOLDER, CONTINUE_SERVER_FOLDER
 
-def getGlobalFolderPath():
-    return os.path.join(os.path.expanduser("~"), CONTINUE_GLOBAL_FOLDER)
 
+def getGlobalFolderPath():
+    path = os.path.join(os.path.expanduser("~"), CONTINUE_GLOBAL_FOLDER)
+    os.makedirs(path, exist_ok=True)
+    return path
 
 
 def getSessionsFolderPath():
-    return os.path.join(getGlobalFolderPath(), CONTINUE_SESSIONS_FOLDER)
+    path = os.path.join(getGlobalFolderPath(), CONTINUE_SESSIONS_FOLDER)
+    os.makedirs(path, exist_ok=True)
+    return path
+
 
 def getServerFolderPath():
-    return os.path.join(getGlobalFolderPath(), CONTINUE_SERVER_FOLDER)
+    path = os.path.join(getGlobalFolderPath(), CONTINUE_SERVER_FOLDER)
+    os.makedirs(path, exist_ok=True)
+    return path
+
 
 def getSessionFilePath(session_id: str):
-    return os.path.join(getSessionsFolderPath(), f"{session_id}.json")
\ No newline at end of file
+    path = os.path.join(getSessionsFolderPath(), f"{session_id}.json")
+    os.makedirs(os.path.dirname(path), exist_ok=True)
+    return path
diff --git a/continuedev/src/continuedev/models/generate_json_schema.py b/continuedev/src/continuedev/models/generate_json_schema.py
index 6cebf429..06614984 100644
--- a/continuedev/src/continuedev/models/generate_json_schema.py
+++ b/continuedev/src/continuedev/models/generate_json_schema.py
@@ -2,6 +2,7 @@ from .main import *
 from .filesystem import RangeInFile, FileEdit
 from .filesystem_edit import FileEditWithFullContents
 from ..core.main import History, HistoryNode, FullState
+from ..core.context import ContextItem
 from pydantic import schema_json_of
 import os
 
@@ -13,6 +14,8 @@ MODELS_TO_GENERATE = [
     FileEditWithFullContents
 ] + [
     History, HistoryNode, FullState
+] + [
+    ContextItem
 ]
 
 RENAMES = {
diff --git a/continuedev/src/continuedev/server/gui.py b/continuedev/src/continuedev/server/gui.py
index ae57c0b6..36b2f3fa 100644
--- a/continuedev/src/continuedev/server/gui.py
+++ b/continuedev/src/continuedev/server/gui.py
@@ -91,25 +91,19 @@ class GUIProtocolServer(AbstractGUIProtocolServer):
                 self.on_clear_history()
             elif message_type == "delete_at_index":
                 self.on_delete_at_index(data["index"])
-            elif message_type == "delete_context_at_indices":
-                self.on_delete_context_at_indices(data["indices"])
+            elif message_type == "delete_context_with_ids":
+                self.on_delete_context_with_ids(data["ids"])
             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"])
             elif message_type == "show_logs_at_index":
                 self.on_show_logs_at_index(data["index"])
+            elif message_type == "select_context_item":
+                self.select_context_item(data["id"], data["query"])
         except Exception as e:
             print(e)
 
-    async def send_state_update(self):
-        state = self.session.autopilot.get_full_state().dict()
-        await self._send_json("state_update", {
-            "state": state
-        })
-
     def on_main_input(self, input: str):
         # Do something with user input
         create_async_task(self.session.autopilot.accept_user_input(
@@ -144,10 +138,10 @@ class GUIProtocolServer(AbstractGUIProtocolServer):
         create_async_task(self.session.autopilot.delete_at_index(
             index), self.session.autopilot.continue_sdk.ide.unique_id)
 
-    def on_delete_context_at_indices(self, indices: List[int]):
+    def on_delete_context_with_ids(self, ids: List[str]):
         create_async_task(
-            self.session.autopilot.delete_context_at_indices(
-                indices), self.session.autopilot.continue_sdk.ide.unique_id
+            self.session.autopilot.delete_context_with_ids(
+                ids), self.session.autopilot.continue_sdk.ide.unique_id
         )
 
     def on_toggle_adding_highlighted_code(self):
@@ -162,18 +156,17 @@ class GUIProtocolServer(AbstractGUIProtocolServer):
                 indices), self.session.autopilot.continue_sdk.ide.unique_id
         )
 
-    def on_set_pinned_at_indices(self, indices: List[int]):
-        create_async_task(
-            self.session.autopilot.set_pinned_at_indices(
-                indices), self.session.autopilot.continue_sdk.ide.unique_id
-        )
-
     def on_show_logs_at_index(self, index: int):
         name = f"continue_logs.txt"
         logs = "\n\n############################################\n\n".join(
             ["This is a log of the exact prompt/completion pairs sent/received from the LLM during this step"] + self.session.autopilot.continue_sdk.history.timeline[index].logs)
         create_async_task(
-            self.session.autopilot.ide.showVirtualFile(name, logs))
+            self.session.autopilot.ide.showVirtualFile(name, logs), self.session.autopilot.continue_sdk.ide.unique_id)
+
+    def select_context_item(self, id: str, query: str):
+        """Called when user selects an item from the dropdown"""
+        create_async_task(
+            self.session.autopilot.select_context_item(id, query), self.session.autopilot.continue_sdk.ide.unique_id)
 
 
 @router.websocket("/ws")
@@ -188,7 +181,7 @@ async def websocket_endpoint(websocket: WebSocket, session: Session = Depends(we
         protocol.websocket = websocket
 
         # Update any history that may have happened before connection
-        await protocol.send_state_update()
+        await protocol.session.autopilot.update_subscribers()
 
         while AppStatus.should_exit is False:
             message = await websocket.receive_text()
@@ -214,5 +207,5 @@ async def websocket_endpoint(websocket: WebSocket, session: Session = Depends(we
         if websocket.client_state != WebSocketState.DISCONNECTED:
             await websocket.close()
 
-        session_manager.persist_session(session.session_id)
+        await session_manager.persist_session(session.session_id)
         session_manager.remove_session(session.session_id)
diff --git a/continuedev/src/continuedev/server/gui_protocol.py b/continuedev/src/continuedev/server/gui_protocol.py
index 9766fcd0..fb230216 100644
--- a/continuedev/src/continuedev/server/gui_protocol.py
+++ b/continuedev/src/continuedev/server/gui_protocol.py
@@ -1,6 +1,8 @@
 from typing import Any, Dict, List
 from abc import ABC, abstractmethod
 
+from ..core.context import ContextItem
+
 
 class AbstractGUIProtocolServer(ABC):
     @abstractmethod
@@ -23,10 +25,6 @@ class AbstractGUIProtocolServer(ABC):
     def on_step_user_input(self, input: str, index: int):
         """Called when the user inputs a step"""
 
-    @abstractmethod
-    async def send_state_update(self, state: dict):
-        """Send a state update to the client"""
-
     @abstractmethod
     def on_retry_at_index(self, index: int):
         """Called when the user requests a retry at a previous index"""
@@ -42,3 +40,7 @@ class AbstractGUIProtocolServer(ABC):
     @abstractmethod
     def on_delete_at_index(self, index: int):
         """Called when the user requests to delete a step at a given index"""
+
+    @abstractmethod
+    def select_context_item(self, id: str, query: str):
+        """Called when user selects an item from the dropdown"""
diff --git a/continuedev/src/continuedev/server/main.py b/continuedev/src/continuedev/server/main.py
index 42dc0cc1..7ee64041 100644
--- a/continuedev/src/continuedev/server/main.py
+++ b/continuedev/src/continuedev/server/main.py
@@ -1,15 +1,20 @@
+import asyncio
+import subprocess
 import time
+import meilisearch
 import psutil
 import os
 from fastapi import FastAPI
 from fastapi.middleware.cors import CORSMiddleware
-from .ide import router as ide_router
-from .gui import router as gui_router
-from .session_manager import session_manager
 import atexit
 import uvicorn
 import argparse
 
+from .ide import router as ide_router
+from .gui import router as gui_router
+from .session_manager import session_manager
+from .meilisearch_server import start_meilisearch
+
 app = FastAPI()
 
 app.include_router(ide_router)
@@ -41,15 +46,20 @@ args = parser.parse_args()
 # log_file = open('output.log', 'a')
 # sys.stdout = log_file
 
-
 def run_server():
     uvicorn.run(app, host="0.0.0.0", port=args.port)
 
 
-def cleanup():
+async def cleanup_coroutine():
     print("Cleaning up sessions")
     for session_id in session_manager.sessions:
-        session_manager.persist_session(session_id)
+        await session_manager.persist_session(session_id)
+
+
+def cleanup():
+    loop = asyncio.new_event_loop()
+    loop.run_until_complete(cleanup_coroutine())
+    loop.close()
 
 
 def cpu_usage_report():
@@ -77,6 +87,12 @@ if __name__ == "__main__":
         # cpu_thread = threading.Thread(target=cpu_usage_loop)
         # cpu_thread.start()
 
+        try:
+            start_meilisearch()
+        except Exception as e:
+            print("Failed to start MeiliSearch")
+            print(e)
+
         run_server()
     except Exception as e:
         cleanup()
diff --git a/continuedev/src/continuedev/server/meilisearch_server.py b/continuedev/src/continuedev/server/meilisearch_server.py
new file mode 100644
index 00000000..419f081f
--- /dev/null
+++ b/continuedev/src/continuedev/server/meilisearch_server.py
@@ -0,0 +1,56 @@
+import os
+import subprocess
+
+import meilisearch
+from ..libs.util.paths import getServerFolderPath
+
+
+def check_meilisearch_installed() -> bool:
+    """
+    Checks if MeiliSearch is installed.
+    """
+
+    serverPath = getServerFolderPath()
+    meilisearchPath = os.path.join(serverPath, "meilisearch")
+
+    return os.path.exists(meilisearchPath)
+
+
+def check_meilisearch_running() -> bool:
+    """
+    Checks if MeiliSearch is running.
+    """
+
+    try:
+        client = meilisearch.Client('http://localhost:7700')
+        resp = client.health()
+        if resp["status"] != "available":
+            return False
+        return True
+    except Exception:
+        return False
+
+
+def start_meilisearch():
+    """
+    Starts the MeiliSearch server, wait for it.
+    """
+
+    # Doesn't work on windows for now
+    if not os.name == "posix":
+        return
+
+    serverPath = getServerFolderPath()
+
+    # Check if MeiliSearch is installed
+    if not check_meilisearch_installed():
+        # Download MeiliSearch
+        print("Downloading MeiliSearch...")
+        subprocess.run(
+            f"curl -L https://install.meilisearch.com | sh", shell=True, check=True, cwd=serverPath)
+
+    # Check if MeiliSearch is running
+    if not check_meilisearch_running():
+        print("Starting MeiliSearch...")
+        subprocess.Popen(["./meilisearch"], cwd=serverPath, stdout=subprocess.DEVNULL,
+                         stderr=subprocess.STDOUT, close_fds=True, start_new_session=True)
diff --git a/continuedev/src/continuedev/server/session_manager.py b/continuedev/src/continuedev/server/session_manager.py
index 90172a4e..96daf92c 100644
--- a/continuedev/src/continuedev/server/session_manager.py
+++ b/continuedev/src/continuedev/server/session_manager.py
@@ -74,7 +74,7 @@ class SessionManager:
 
         async def on_update(state: FullState):
             await session_manager.send_ws_data(session_id, "state_update", {
-                "state": autopilot.get_full_state().dict()
+                "state": state.dict()
             })
 
         autopilot.on_update(on_update)
@@ -84,9 +84,9 @@ class SessionManager:
     def remove_session(self, session_id: str):
         del self.sessions[session_id]
 
-    def persist_session(self, session_id: str):
+    async def persist_session(self, session_id: str):
         """Save the session's FullState as a json file"""
-        full_state = self.sessions[session_id].autopilot.get_full_state()
+        full_state = await self.sessions[session_id].autopilot.get_full_state()
         if not os.path.exists(getSessionsFolderPath()):
             os.mkdir(getSessionsFolderPath())
         with open(getSessionFilePath(session_id), "w") as f:
diff --git a/extension/react-app/package-lock.json b/extension/react-app/package-lock.json
index 13e02e86..fa7834f1 100644
--- a/extension/react-app/package-lock.json
+++ b/extension/react-app/package-lock.json
@@ -13,6 +13,7 @@
         "@types/vscode-webview": "^1.57.1",
         "@uiw/react-markdown-preview": "^4.1.13",
         "downshift": "^7.6.0",
+        "meilisearch": "^0.33.0",
         "posthog-js": "^1.58.0",
         "prismjs": "^1.29.0",
         "react": "^18.2.0",
@@ -1423,6 +1424,14 @@
       "resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-2.0.4.tgz",
       "integrity": "sha512-y/ZA3BGnxoM/QHHQ2Uy49CLtnWPbt4tTPpEEZiEmmiWBFKjej7nEyH8Ryz54jH0MLXflUYA3Er2zUxPSJu5R+g=="
     },
+    "node_modules/cross-fetch": {
+      "version": "3.1.8",
+      "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.8.tgz",
+      "integrity": "sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==",
+      "dependencies": {
+        "node-fetch": "^2.6.12"
+      }
+    },
     "node_modules/css-color-keywords": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz",
@@ -2500,6 +2509,14 @@
         "url": "https://opencollective.com/unified"
       }
     },
+    "node_modules/meilisearch": {
+      "version": "0.33.0",
+      "resolved": "https://registry.npmjs.org/meilisearch/-/meilisearch-0.33.0.tgz",
+      "integrity": "sha512-bYPb9WyITnJfzf92e7QFK8Rc50DmshFWxypXCs3ILlpNh8pT15A7KSu9Xgnnk/K3G/4vb3wkxxtFS4sxNkWB8w==",
+      "dependencies": {
+        "cross-fetch": "^3.1.6"
+      }
+    },
     "node_modules/merge2": {
       "version": "1.4.1",
       "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
@@ -3092,6 +3109,25 @@
         "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
       }
     },
+    "node_modules/node-fetch": {
+      "version": "2.6.12",
+      "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.12.tgz",
+      "integrity": "sha512-C/fGU2E8ToujUivIO0H+tpQ6HWo4eEmchoPIoXtxCrVghxdKq+QOHqEZW7tuP3KlV3bC8FRMO5nMCC7Zm1VP6g==",
+      "dependencies": {
+        "whatwg-url": "^5.0.0"
+      },
+      "engines": {
+        "node": "4.x || >=6.0.0"
+      },
+      "peerDependencies": {
+        "encoding": "^0.1.0"
+      },
+      "peerDependenciesMeta": {
+        "encoding": {
+          "optional": true
+        }
+      }
+    },
     "node_modules/node-releases": {
       "version": "2.0.10",
       "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz",
@@ -4115,6 +4151,11 @@
         "node": ">=8.0"
       }
     },
+    "node_modules/tr46": {
+      "version": "0.0.3",
+      "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
+      "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
+    },
     "node_modules/trim-lines": {
       "version": "3.0.1",
       "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz",
@@ -4423,6 +4464,20 @@
         "url": "https://github.com/sponsors/wooorm"
       }
     },
+    "node_modules/webidl-conversions": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
+      "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
+    },
+    "node_modules/whatwg-url": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
+      "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
+      "dependencies": {
+        "tr46": "~0.0.3",
+        "webidl-conversions": "^3.0.0"
+      }
+    },
     "node_modules/xtend": {
       "version": "4.0.2",
       "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
@@ -5325,6 +5380,14 @@
       "resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-2.0.4.tgz",
       "integrity": "sha512-y/ZA3BGnxoM/QHHQ2Uy49CLtnWPbt4tTPpEEZiEmmiWBFKjej7nEyH8Ryz54jH0MLXflUYA3Er2zUxPSJu5R+g=="
     },
+    "cross-fetch": {
+      "version": "3.1.8",
+      "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.8.tgz",
+      "integrity": "sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==",
+      "requires": {
+        "node-fetch": "^2.6.12"
+      }
+    },
     "css-color-keywords": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz",
@@ -6098,6 +6161,14 @@
         "@types/mdast": "^3.0.0"
       }
     },
+    "meilisearch": {
+      "version": "0.33.0",
+      "resolved": "https://registry.npmjs.org/meilisearch/-/meilisearch-0.33.0.tgz",
+      "integrity": "sha512-bYPb9WyITnJfzf92e7QFK8Rc50DmshFWxypXCs3ILlpNh8pT15A7KSu9Xgnnk/K3G/4vb3wkxxtFS4sxNkWB8w==",
+      "requires": {
+        "cross-fetch": "^3.1.6"
+      }
+    },
     "merge2": {
       "version": "1.4.1",
       "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
@@ -6434,6 +6505,14 @@
       "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==",
       "dev": true
     },
+    "node-fetch": {
+      "version": "2.6.12",
+      "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.12.tgz",
+      "integrity": "sha512-C/fGU2E8ToujUivIO0H+tpQ6HWo4eEmchoPIoXtxCrVghxdKq+QOHqEZW7tuP3KlV3bC8FRMO5nMCC7Zm1VP6g==",
+      "requires": {
+        "whatwg-url": "^5.0.0"
+      }
+    },
     "node-releases": {
       "version": "2.0.10",
       "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz",
@@ -7129,6 +7208,11 @@
         "is-number": "^7.0.0"
       }
     },
+    "tr46": {
+      "version": "0.0.3",
+      "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
+      "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
+    },
     "trim-lines": {
       "version": "3.0.1",
       "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz",
@@ -7315,6 +7399,20 @@
       "resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-2.0.1.tgz",
       "integrity": "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ=="
     },
+    "webidl-conversions": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
+      "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
+    },
+    "whatwg-url": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
+      "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
+      "requires": {
+        "tr46": "~0.0.3",
+        "webidl-conversions": "^3.0.0"
+      }
+    },
     "xtend": {
       "version": "4.0.2",
       "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
diff --git a/extension/react-app/package.json b/extension/react-app/package.json
index 704f520a..e5f5a329 100644
--- a/extension/react-app/package.json
+++ b/extension/react-app/package.json
@@ -14,6 +14,7 @@
     "@types/vscode-webview": "^1.57.1",
     "@uiw/react-markdown-preview": "^4.1.13",
     "downshift": "^7.6.0",
+    "meilisearch": "^0.33.0",
     "posthog-js": "^1.58.0",
     "prismjs": "^1.29.0",
     "react": "^18.2.0",
diff --git a/extension/react-app/src/components/ComboBox.tsx b/extension/react-app/src/components/ComboBox.tsx
index f327e3a3..22a6d000 100644
--- a/extension/react-app/src/components/ComboBox.tsx
+++ b/extension/react-app/src/components/ComboBox.tsx
@@ -1,4 +1,9 @@
-import React, { useEffect, useImperativeHandle, useState } from "react";
+import React, {
+  useContext,
+  useEffect,
+  useImperativeHandle,
+  useState,
+} from "react";
 import { useCombobox } from "downshift";
 import styled from "styled-components";
 import {
@@ -8,13 +13,15 @@ import {
   vscBackground,
   vscForeground,
 } from ".";
-import CodeBlock from "./CodeBlock";
 import PillButton from "./PillButton";
 import HeaderButtonWithText from "./HeaderButtonWithText";
 import { DocumentPlus } from "@styled-icons/heroicons-outline";
-import { HighlightedRangeContext } from "../../../schema/FullState";
+import { ContextItem } from "../../../schema/FullState";
 import { postVscMessage } from "../vscode";
-import { getMetaKeyLabel } from "../util";
+import { GUIClientContext } from "../App";
+import { MeiliSearch } from "meilisearch";
+
+const SEARCH_INDEX_NAME = "continue_context_items";
 
 // #region styled components
 const mainInputFontSize = 13;
@@ -64,14 +71,14 @@ const Ul = styled.ul<{
   hidden: boolean;
   showAbove: boolean;
   ulHeightPixels: number;
+  inputBoxHeight?: string;
 }>`
   ${(props) =>
     props.showAbove
       ? `transform: translateY(-${props.ulHeightPixels + 8}px);`
-      : `transform: translateY(${2 * mainInputFontSize}px);`}
+      : `transform: translateY(${5 * mainInputFontSize}px);`}
   position: absolute;
   background: ${vscBackground};
-  background-color: ${secondaryDark};
   color: ${vscForeground};
   max-height: ${UlMaxHeight}px;
   width: calc(100% - 16px);
@@ -80,15 +87,9 @@ const Ul = styled.ul<{
   padding: 0;
   ${({ hidden }) => hidden && "display: none;"}
   border-radius: ${defaultBorderRadius};
-  outline: 0.5px solid gray;
+  outline: 1px solid ${lightGray};
   z-index: 2;
-  // Get rid of scrollbar and its padding
-  scrollbar-width: none;
   -ms-overflow-style: none;
-  &::-webkit-scrollbar {
-    width: 0px;
-    background: transparent; /* make scrollbar transparent */
-  }
 `;
 
 const Li = styled.li<{
@@ -96,49 +97,90 @@ const Li = styled.li<{
   selected: boolean;
   isLastItem: boolean;
 }>`
-  background-color: ${secondaryDark};
-  ${({ highlighted }) => highlighted && "background: #ff000066;"}
+  background-color: ${({ highlighted }) =>
+    highlighted ? lightGray : secondaryDark};
+  ${({ highlighted }) => highlighted && `background: ${vscBackground};`}
   ${({ selected }) => selected && "font-weight: bold;"}
     padding: 0.5rem 0.75rem;
   display: flex;
   flex-direction: column;
   ${({ isLastItem }) => isLastItem && "border-bottom: 1px solid gray;"}
-  border-top: 1px solid gray;
+  /* border-top: 1px solid gray; */
   cursor: pointer;
 `;
 
 // #endregion
 
 interface ComboBoxProps {
-  items: { name: string; description: string }[];
+  items: { name: string; description: string; id?: string }[];
   onInputValueChange: (inputValue: string) => void;
   disabled?: boolean;
   onEnter: (e: React.KeyboardEvent<HTMLInputElement>) => void;
-  highlightedCodeSections: HighlightedRangeContext[];
-  deleteContextItems: (indices: number[]) => void;
-  onTogglePin: () => void;
+  selectedContextItems: ContextItem[];
   onToggleAddContext: () => void;
   addingHighlightedCode: boolean;
 }
 
 const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
+  const searchClient = new MeiliSearch({ host: "http://127.0.0.1:7700" });
+  const client = useContext(GUIClientContext);
+
   const [history, setHistory] = React.useState<string[]>([]);
   // The position of the current command you are typing now, so the one that will be appended to history once you press enter
   const [positionInHistory, setPositionInHistory] = React.useState<number>(0);
   const [items, setItems] = React.useState(props.items);
-  const [highlightedCodeSections, setHighlightedCodeSections] = React.useState(
-    props.highlightedCodeSections || []
-  );
+
   const inputRef = React.useRef<HTMLInputElement>(null);
+  const [inputBoxHeight, setInputBoxHeight] = useState<string | undefined>(
+    undefined
+  );
 
-  useEffect(() => {
-    setHighlightedCodeSections(props.highlightedCodeSections || []);
-  }, [props.highlightedCodeSections]);
+  // Whether the current input follows an '@' and should be treated as context query
+  const [currentlyInContextQuery, setCurrentlyInContextQuery] = useState(false);
 
   const { getInputProps, ...downshiftProps } = useCombobox({
-    onInputValueChange({ inputValue }) {
+    onSelectedItemChange: ({ selectedItem }) => {
+      if (selectedItem?.id) {
+        // Get the query from the input value
+        const segs = downshiftProps.inputValue.split("@");
+        const query = segs[segs.length - 1];
+        const restOfInput = segs.splice(0, segs.length - 1).join("@");
+
+        // Tell server the context item was selected
+        client?.selectContextItem(selectedItem.id, query);
+
+        // Remove the '@' and the context query from the input
+        if (downshiftProps.inputValue.includes("@")) {
+          downshiftProps.setInputValue(restOfInput);
+        }
+      }
+    },
+    onInputValueChange({ inputValue, highlightedIndex }) {
       if (!inputValue) return;
       props.onInputValueChange(inputValue);
+
+      if (inputValue.endsWith("@") || currentlyInContextQuery) {
+        setCurrentlyInContextQuery(true);
+
+        const segs = inputValue.split("@");
+        const providerAndQuery = segs[segs.length - 1];
+        const [provider, query] = providerAndQuery.split(" ");
+        searchClient
+          .index(SEARCH_INDEX_NAME)
+          .search(providerAndQuery)
+          .then((res) => {
+            setItems(
+              res.hits.map((hit) => {
+                return {
+                  name: hit.name,
+                  description: hit.description,
+                  id: hit.id,
+                };
+              })
+            );
+          });
+        return;
+      }
       setItems(
         props.items.filter((item) =>
           item.name.toLowerCase().startsWith(inputValue.toLowerCase())
@@ -151,6 +193,16 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
     },
   });
 
+  useEffect(() => {
+    console.log(
+      "downshiftProps.highlightedIndex",
+      downshiftProps.highlightedIndex
+    );
+    if (downshiftProps.highlightedIndex < 0) {
+      downshiftProps.setHighlightedIndex(0);
+    }
+  }, [downshiftProps.inputValue]);
+
   useImperativeHandle(ref, () => downshiftProps, [downshiftProps]);
 
   const [metaKeyPressed, setMetaKeyPressed] = useState(false);
@@ -199,50 +251,22 @@ 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
-            warning={
-              section.range.contents.length > 4000 && section.editing
-                ? "Editing such a large range may be slow"
-                : undefined
-            }
-            onlyShowDelete={
-              highlightedCodeSections.length <= 1 || section.editing
-            }
-            editing={section.editing}
-            pinned={section.pinned}
-            index={idx}
-            key={`${section.display_name}${idx}`}
-            title={`${section.display_name} (${
-              section.range.range.start.line + 1
-            }-${section.range.range.end.line + 1})`}
-            onDelete={() => {
-              if (props.deleteContextItems) {
-                props.deleteContextItems([idx]);
+        {props.selectedContextItems.map((item, idx) => {
+          return (
+            <PillButton
+              key={`${item.description.id.item_id}${idx}`}
+              item={item}
+              warning={
+                item.content.length > 4000 && item.editing
+                  ? "Editing such a large range may be slow"
+                  : undefined
               }
-              setHighlightedCodeSections((prev) => {
-                const newSections = [...prev];
-                newSections.splice(idx, 1);
-                return newSections;
-              });
-            }}
-          />
-        ))}
-        {props.highlightedCodeSections.length > 0 &&
+              addingHighlightedCode={props.addingHighlightedCode}
+              index={idx}
+            />
+          );
+        })}
+        {props.selectedContextItems.length > 0 &&
           (props.addingHighlightedCode ? (
             <EmptyPillDiv
               onClick={() => {
@@ -275,6 +299,7 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
                 target.scrollHeight,
                 300
               ).toString()}px`;
+              setInputBoxHeight(target.style.height);
 
               // setShowContextDropdown(target.value.endsWith("@"));
             },
@@ -289,6 +314,7 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
               if (event.key === "Enter" && event.shiftKey) {
                 // Prevent Downshift's default 'Enter' behavior.
                 (event.nativeEvent as any).preventDownshiftDefault = true;
+                setCurrentlyInContextQuery(false);
               } else if (
                 event.key === "Enter" &&
                 (!downshiftProps.isOpen || items.length === 0)
@@ -302,6 +328,7 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
                 (event.nativeEvent as any).preventDownshiftDefault = true;
 
                 if (props.onEnter) props.onEnter(event);
+                setCurrentlyInContextQuery(false);
               } else if (event.key === "Tab" && items.length > 0) {
                 downshiftProps.setInputValue(items[0].name);
                 event.preventDefault();
@@ -321,6 +348,7 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
                 }
                 downshiftProps.setInputValue(history[positionInHistory - 1]);
                 setPositionInHistory((prev) => prev - 1);
+                setCurrentlyInContextQuery(false);
               } else if (event.key === "ArrowDown") {
                 if (positionInHistory < history.length) {
                   downshiftProps.setInputValue(history[positionInHistory + 1]);
@@ -328,6 +356,7 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
                 setPositionInHistory((prev) =>
                   Math.min(prev + 1, history.length)
                 );
+                setCurrentlyInContextQuery(false);
               }
             },
             ref: inputRef,
@@ -351,13 +380,14 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
                 selected={downshiftProps.selectedItem === item}
               >
                 <span>
-                  {item.name}: {item.description}
+                  {item.name}:{"  "}
+                  <span style={{ color: lightGray }}>{item.description}</span>
                 </span>
               </Li>
             ))}
         </Ul>
       </div>
-      {highlightedCodeSections.length === 0 &&
+      {props.selectedContextItems.length === 0 &&
         (downshiftProps.inputValue?.startsWith("/edit") ||
           (focused &&
             metaKeyPressed &&
diff --git a/extension/react-app/src/components/PillButton.tsx b/extension/react-app/src/components/PillButton.tsx
index c24dba83..af4263af 100644
--- a/extension/react-app/src/components/PillButton.tsx
+++ b/extension/react-app/src/components/PillButton.tsx
@@ -1,9 +1,10 @@
-import { useContext, useState } from "react";
+import { useContext, useEffect, useState } from "react";
 import styled from "styled-components";
 import {
   StyledTooltip,
   defaultBorderRadius,
   secondaryDark,
+  vscBackground,
   vscForeground,
 } from ".";
 import {
@@ -12,6 +13,14 @@ import {
   ExclamationTriangle,
 } from "@styled-icons/heroicons-outline";
 import { GUIClientContext } from "../App";
+import { useDispatch } from "react-redux";
+import {
+  setBottomMessage,
+  setBottomMessageCloseTimeout,
+} from "../redux/slices/uiStateSlice";
+import { ContextItem } from "../../../schema/FullState";
+import { ReactMarkdown } from "react-markdown/lib/react-markdown";
+import StyledMarkdownPreview from "./StyledMarkdownPreview";
 
 const Button = styled.button`
   border: none;
@@ -67,19 +76,48 @@ const CircleDiv = styled.div`
 
 interface PillButtonProps {
   onHover?: (arg0: boolean) => void;
-  onDelete?: () => void;
-  title: string;
-  index: number;
-  editing: boolean;
-  pinned: boolean;
+  item: ContextItem;
   warning?: string;
-  onlyShowDelete?: boolean;
+  index: number;
+  addingHighlightedCode?: boolean;
 }
 
 const PillButton = (props: PillButtonProps) => {
   const [isHovered, setIsHovered] = useState(false);
   const client = useContext(GUIClientContext);
 
+  const dispatch = useDispatch();
+
+  useEffect(() => {
+    if (isHovered) {
+      dispatch(setBottomMessageCloseTimeout(undefined));
+      dispatch(
+        setBottomMessage(
+          <>
+            <b>{props.item.description.name}</b>:{" "}
+            {props.item.description.description}
+            <StyledMarkdownPreview
+              source={`\`\`\`\n${props.item.content}\n\`\`\``}
+              wrapperElement={{
+                "data-color-mode": "dark",
+              }}
+            />
+          </>
+        )
+      );
+    } else {
+      dispatch(
+        setBottomMessageCloseTimeout(
+          setTimeout(() => {
+            if (!isHovered) {
+              dispatch(setBottomMessage(undefined));
+            }
+          }, 2000)
+        )
+      );
+    }
+  }, [isHovered]);
+
   return (
     <>
       <div style={{ position: "relative" }}>
@@ -88,10 +126,8 @@ const PillButton = (props: PillButtonProps) => {
             position: "relative",
             borderColor: props.warning
               ? "red"
-              : props.editing
+              : props.item.editing
               ? "#8800aa"
-              : props.pinned
-              ? "#ffff0099"
               : "transparent",
             borderWidth: "1px",
             borderStyle: "solid",
@@ -112,10 +148,14 @@ const PillButton = (props: PillButtonProps) => {
           {isHovered && (
             <GridDiv
               style={{
-                gridTemplateColumns: props.onlyShowDelete ? "1fr" : "1fr 1fr",
+                gridTemplateColumns:
+                  props.item.editable && props.addingHighlightedCode
+                    ? "1fr 1fr"
+                    : "1fr",
+                backgroundColor: vscBackground,
               }}
             >
-              {props.onlyShowDelete || (
+              {props.item.editable && props.addingHighlightedCode && (
                 <ButtonDiv
                   data-tooltip-id={`edit-${props.index}`}
                   backgroundColor={"#8800aa55"}
@@ -130,15 +170,6 @@ const PillButton = (props: PillButtonProps) => {
                 </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>
@@ -146,33 +177,33 @@ const PillButton = (props: PillButtonProps) => {
                 data-tooltip-id={`delete-${props.index}`}
                 backgroundColor={"#cc000055"}
                 onClick={() => {
-                  if (props.onDelete) {
-                    props.onDelete();
-                  }
+                  client?.deleteContextWithIds([props.item.description.id]);
                 }}
               >
                 <Trash style={{ margin: "auto" }} width="1.6em"></Trash>
               </ButtonDiv>
             </GridDiv>
           )}
-          {props.title}
+          {props.item.description.name}
         </Button>
         <StyledTooltip id={`edit-${props.index}`}>
-          {props.editing
+          {props.item.editing
             ? "Editing this section (with entire file as context)"
             : "Edit this section"}
         </StyledTooltip>
         <StyledTooltip id={`delete-${props.index}`}>Delete</StyledTooltip>
         {props.warning && (
           <>
-            <CircleDiv data-tooltip-id={`circle-div-${props.title}`}>
+            <CircleDiv
+              data-tooltip-id={`circle-div-${props.item.description.name}`}
+            >
               <ExclamationTriangle
                 style={{ margin: "auto" }}
                 width="1.0em"
                 strokeWidth={2}
               />
             </CircleDiv>
-            <StyledTooltip id={`circle-div-${props.title}`}>
+            <StyledTooltip id={`circle-div-${props.item.description.name}`}>
               {props.warning}
             </StyledTooltip>
           </>
diff --git a/extension/react-app/src/components/StepContainer.tsx b/extension/react-app/src/components/StepContainer.tsx
index bc8665fd..2cfe7ecd 100644
--- a/extension/react-app/src/components/StepContainer.tsx
+++ b/extension/react-app/src/components/StepContainer.tsx
@@ -18,9 +18,9 @@ import {
 import { StopCircle } from "@styled-icons/heroicons-solid";
 import { HistoryNode } from "../../../schema/HistoryNode";
 import HeaderButtonWithText from "./HeaderButtonWithText";
-import MarkdownPreview from "@uiw/react-markdown-preview";
 import { getMetaKeyLabel, isMetaEquivalentKeyPressed } from "../util";
 import { GUIClientContext } from "../App";
+import StyledMarkdownPreview from "./StyledMarkdownPreview";
 
 interface StepContainerProps {
   historyNode: HistoryNode;
@@ -109,33 +109,6 @@ const GradientBorder = styled.div<{
   background-size: 200% 200%;
 `;
 
-const StyledMarkdownPreview = styled(MarkdownPreview)`
-  pre {
-    background-color: ${secondaryDark};
-    padding: 1px;
-    border-radius: ${defaultBorderRadius};
-    border: 0.5px solid white;
-  }
-
-  code {
-    color: #f78383;
-    word-wrap: break-word;
-    border-radius: ${defaultBorderRadius};
-    background-color: ${secondaryDark};
-  }
-
-  pre > code {
-    background-color: ${secondaryDark};
-    color: ${vscForeground};
-  }
-
-  background-color: ${vscBackground};
-  font-family: "Lexend", sans-serif;
-  font-size: 13px;
-  padding: 8px;
-  color: ${vscForeground};
-`;
-
 // #endregion
 
 function StepContainer(props: StepContainerProps) {
diff --git a/extension/react-app/src/components/StyledMarkdownPreview.tsx b/extension/react-app/src/components/StyledMarkdownPreview.tsx
new file mode 100644
index 00000000..9c2ecb62
--- /dev/null
+++ b/extension/react-app/src/components/StyledMarkdownPreview.tsx
@@ -0,0 +1,37 @@
+import styled from "styled-components";
+import {
+  defaultBorderRadius,
+  secondaryDark,
+  vscBackground,
+  vscForeground,
+} from ".";
+import MarkdownPreview from "@uiw/react-markdown-preview";
+
+const StyledMarkdownPreview = styled(MarkdownPreview)`
+  pre {
+    background-color: ${secondaryDark};
+    padding: 1px;
+    border-radius: ${defaultBorderRadius};
+    border: 0.5px solid white;
+  }
+
+  code {
+    color: #f78383;
+    word-wrap: break-word;
+    border-radius: ${defaultBorderRadius};
+    background-color: ${secondaryDark};
+  }
+
+  pre > code {
+    background-color: ${secondaryDark};
+    color: ${vscForeground};
+  }
+
+  background-color: ${vscBackground};
+  font-family: "Lexend", sans-serif;
+  font-size: 13px;
+  padding: 8px;
+  color: ${vscForeground};
+`;
+
+export default StyledMarkdownPreview;
diff --git a/extension/react-app/src/components/TextDialog.tsx b/extension/react-app/src/components/TextDialog.tsx
index cba3852d..7c6ba052 100644
--- a/extension/react-app/src/components/TextDialog.tsx
+++ b/extension/react-app/src/components/TextDialog.tsx
@@ -5,7 +5,7 @@ import { Button, secondaryDark, vscBackground, vscForeground } from ".";
 import { isMetaEquivalentKeyPressed } from "../util";
 
 const ScreenCover = styled.div`
-  position: absolute;
+  position: fixed;
   width: 100%;
   height: 100%;
   background-color: rgba(168, 168, 168, 0.5);
diff --git a/extension/react-app/src/hooks/AbstractContinueGUIClientProtocol.ts b/extension/react-app/src/hooks/AbstractContinueGUIClientProtocol.ts
index 6c0df8fc..ddf65272 100644
--- a/extension/react-app/src/hooks/AbstractContinueGUIClientProtocol.ts
+++ b/extension/react-app/src/hooks/AbstractContinueGUIClientProtocol.ts
@@ -1,3 +1,5 @@
+import { ContextItemId } from "../../../schema/FullState";
+
 abstract class AbstractContinueGUIClientProtocol {
   abstract sendMainInput(input: string): void;
 
@@ -21,15 +23,15 @@ abstract class AbstractContinueGUIClientProtocol {
 
   abstract deleteAtIndex(index: number): void;
 
-  abstract deleteContextAtIndices(indices: number[]): void;
+  abstract deleteContextWithIds(ids: ContextItemId[]): void;
 
   abstract setEditingAtIndices(indices: number[]): void;
 
-  abstract setPinnedAtIndices(indices: number[]): void;
-
   abstract toggleAddingHighlightedCode(): void;
 
   abstract showLogsAtIndex(index: number): void;
+
+  abstract selectContextItem(id: string, query: string): void;
 }
 
 export default AbstractContinueGUIClientProtocol;
diff --git a/extension/react-app/src/hooks/ContinueGUIClientProtocol.ts b/extension/react-app/src/hooks/ContinueGUIClientProtocol.ts
index 7d6c2a71..1048e956 100644
--- a/extension/react-app/src/hooks/ContinueGUIClientProtocol.ts
+++ b/extension/react-app/src/hooks/ContinueGUIClientProtocol.ts
@@ -1,3 +1,4 @@
+import { ContextItemId } from "../../../schema/FullState";
 import AbstractContinueGUIClientProtocol from "./AbstractContinueGUIClientProtocol";
 import { Messenger, WebsocketMessenger } from "./messenger";
 import { VscodeMessenger } from "./vscodeMessenger";
@@ -68,18 +69,16 @@ class ContinueGUIClientProtocol extends AbstractContinueGUIClientProtocol {
     this.messenger.send("delete_at_index", { index });
   }
 
-  deleteContextAtIndices(indices: number[]) {
-    this.messenger.send("delete_context_at_indices", { indices });
+  deleteContextWithIds(ids: ContextItemId[]) {
+    this.messenger.send("delete_context_with_ids", {
+      ids: ids.map((id) => `${id.provider_title}-${id.item_id}`),
+    });
   }
 
   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", {});
   }
@@ -87,6 +86,10 @@ class ContinueGUIClientProtocol extends AbstractContinueGUIClientProtocol {
   showLogsAtIndex(index: number): void {
     this.messenger.send("show_logs_at_index", { index });
   }
+
+  selectContextItem(id: string, query: string): void {
+    this.messenger.send("select_context_item", { id, query });
+  }
 }
 
 export default ContinueGUIClientProtocol;
diff --git a/extension/react-app/src/pages/gui.tsx b/extension/react-app/src/pages/gui.tsx
index fccc9b4b..a1ba1c33 100644
--- a/extension/react-app/src/pages/gui.tsx
+++ b/extension/react-app/src/pages/gui.tsx
@@ -6,7 +6,7 @@ import {
 } from "../components";
 import Loader from "../components/Loader";
 import ContinueButton from "../components/ContinueButton";
-import { FullState, HighlightedRangeContext } from "../../../schema/FullState";
+import { ContextItem, FullState } from "../../../schema/FullState";
 import { useCallback, useEffect, useRef, useState, useContext } from "react";
 import { History } from "../../../schema/History";
 import { HistoryNode } from "../../../schema/HistoryNode";
@@ -22,12 +22,16 @@ import TextDialog from "../components/TextDialog";
 import HeaderButtonWithText from "../components/HeaderButtonWithText";
 import ReactSwitch from "react-switch";
 import { usePostHog } from "posthog-js/react";
-import { useSelector } from "react-redux";
+import { useDispatch, useSelector } from "react-redux";
 import { RootStore } from "../redux/store";
 import { postVscMessage } from "../vscode";
 import UserInputContainer from "../components/UserInputContainer";
 import Onboarding from "../components/Onboarding";
 import { isMetaEquivalentKeyPressed } from "../util";
+import {
+  setBottomMessage,
+  setBottomMessageCloseTimeout,
+} from "../redux/slices/uiStateSlice";
 
 const TopGUIDiv = styled.div`
   overflow: hidden;
@@ -78,15 +82,13 @@ function GUI(props: GUIProps) {
   const [usingFastModel, setUsingFastModel] = useState(false);
   const [waitingForSteps, setWaitingForSteps] = useState(false);
   const [userInputQueue, setUserInputQueue] = useState<string[]>([]);
-  const [highlightedRanges, setHighlightedRanges] = useState<
-    HighlightedRangeContext[]
-  >([]);
   const [addingHighlightedCode, setAddingHighlightedCode] = useState(false);
+  const [selectedContextItems, setSelectedContextItems] = useState<
+    ContextItem[]
+  >([]);
   const [availableSlashCommands, setAvailableSlashCommands] = useState<
     { name: string; description: string }[]
   >([]);
-  const [pinned, setPinned] = useState(false);
-  const [showDataSharingInfo, setShowDataSharingInfo] = useState(false);
   const [stepsOpen, setStepsOpen] = useState<boolean[]>([
     true,
     true,
@@ -118,6 +120,11 @@ function GUI(props: GUIProps) {
   const [showFeedbackDialog, setShowFeedbackDialog] = useState(false);
   const [feedbackDialogMessage, setFeedbackDialogMessage] = useState("");
 
+  const dispatch = useDispatch();
+  const bottomMessage = useSelector(
+    (state: RootStore) => state.uiState.bottomMessage
+  );
+
   const topGuiDivRef = useRef<HTMLDivElement>(null);
 
   const [scrollTimeout, setScrollTimeout] = useState<NodeJS.Timeout | null>(
@@ -179,7 +186,8 @@ function GUI(props: GUIProps) {
 
       setWaitingForSteps(waitingForSteps);
       setHistory(state.history);
-      setHighlightedRanges(state.highlighted_ranges);
+      console.log((state as any).selected_context_items);
+      setSelectedContextItems(state.selected_context_items);
       setUserInputQueue(state.user_input_queue);
       setAddingHighlightedCode(state.adding_highlighted_code);
       setAvailableSlashCommands(
@@ -214,13 +222,6 @@ function GUI(props: GUIProps) {
 
   const mainTextInputRef = useRef<HTMLInputElement>(null);
 
-  const deleteContextItems = useCallback(
-    (indices: number[]) => {
-      client?.deleteContextAtIndices(indices);
-    },
-    [client]
-  );
-
   const onMainTextInput = (event?: any) => {
     if (mainTextInputRef.current) {
       let input = (mainTextInputRef.current as any).inputValue;
@@ -360,11 +361,7 @@ function GUI(props: GUIProps) {
           }}
           onInputValueChange={() => {}}
           items={availableSlashCommands}
-          highlightedCodeSections={highlightedRanges}
-          deleteContextItems={deleteContextItems}
-          onTogglePin={() => {
-            setPinned((prev: boolean) => !prev);
-          }}
+          selectedContextItems={selectedContextItems}
           onToggleAddContext={() => {
             client?.toggleAddingHighlightedCode();
           }}
@@ -373,29 +370,30 @@ function GUI(props: GUIProps) {
         <ContinueButton onClick={onMainTextInput} />
       </TopGUIDiv>
       <div
+        onMouseEnter={() => {
+          dispatch(setBottomMessageCloseTimeout(undefined));
+        }}
+        onMouseLeave={() => {
+          dispatch(setBottomMessage(undefined));
+        }}
         style={{
           position: "fixed",
           bottom: "50px",
+          left: "0",
+          right: "0",
+          margin: "16px",
           backgroundColor: vscBackground,
           color: vscForeground,
           borderRadius: defaultBorderRadius,
           padding: "16px",
-          margin: "16px",
           zIndex: 100,
           boxShadow: `0px 0px 10px 0px ${vscForeground}`,
+          maxHeight: "50vh",
+          overflow: "scroll",
         }}
-        hidden={!showDataSharingInfo}
+        hidden={!bottomMessage}
       >
-        By turning on this switch, you will begin collecting accepted and
-        rejected suggestions in .continue/suggestions.json. This data is stored
-        locally on your machine and not sent anywhere.
-        <br />
-        <br />
-        <b>
-          {dataSwitchChecked
-            ? "👍 Data is being collected"
-            : "👎 No data is being collected"}
-        </b>
+        {bottomMessage}
       </div>
       <Footer dataSwitchChecked={dataSwitchChecked}>
         <div
@@ -406,10 +404,25 @@ function GUI(props: GUIProps) {
             alignItems: "center",
           }}
           onMouseEnter={() => {
-            setShowDataSharingInfo(true);
+            dispatch(
+              setBottomMessage(
+                <>
+                  By turning on this switch, you will begin collecting accepted
+                  and rejected suggestions in .continue/suggestions.json. This
+                  data is stored locally on your machine and not sent anywhere.
+                  <br />
+                  <br />
+                  <b>
+                    {dataSwitchChecked
+                      ? "👍 Data is being collected"
+                      : "👎 No data is being collected"}
+                  </b>
+                </>
+              )
+            );
           }}
           onMouseLeave={() => {
-            setShowDataSharingInfo(false);
+            dispatch(setBottomMessage(undefined));
           }}
         >
           <ReactSwitch
diff --git a/extension/react-app/src/redux/selectors/uiStateSelectors.ts b/extension/react-app/src/redux/selectors/uiStateSelectors.ts
new file mode 100644
index 00000000..7ebc9338
--- /dev/null
+++ b/extension/react-app/src/redux/selectors/uiStateSelectors.ts
@@ -0,0 +1,5 @@
+import { RootStore } from "../store";
+
+const selectBottomMessage = (state: RootStore) => state.uiState.bottomMessage;
+
+export { selectBottomMessage };
diff --git a/extension/react-app/src/redux/slices/uiStateSlice.ts b/extension/react-app/src/redux/slices/uiStateSlice.ts
new file mode 100644
index 00000000..837d19e9
--- /dev/null
+++ b/extension/react-app/src/redux/slices/uiStateSlice.ts
@@ -0,0 +1,24 @@
+import { createSlice } from "@reduxjs/toolkit";
+
+export const uiStateSlice = createSlice({
+  name: "uiState",
+  initialState: {
+    bottomMessage: undefined,
+    bottomMessageCloseTimeout: undefined,
+  },
+  reducers: {
+    setBottomMessage: (state, action) => {
+      state.bottomMessage = action.payload;
+    },
+    setBottomMessageCloseTimeout: (state, action) => {
+      if (state.bottomMessageCloseTimeout) {
+        clearTimeout(state.bottomMessageCloseTimeout);
+      }
+      state.bottomMessageCloseTimeout = action.payload;
+    },
+  },
+});
+
+export const { setBottomMessage, setBottomMessageCloseTimeout } =
+  uiStateSlice.actions;
+export default uiStateSlice.reducer;
diff --git a/extension/react-app/src/redux/store.ts b/extension/react-app/src/redux/store.ts
index b6eb55b3..d49513e5 100644
--- a/extension/react-app/src/redux/store.ts
+++ b/extension/react-app/src/redux/store.ts
@@ -3,6 +3,7 @@ import debugStateReducer from "./slices/debugContexSlice";
 import chatReducer from "./slices/chatSlice";
 import configReducer from "./slices/configSlice";
 import miscReducer from "./slices/miscSlice";
+import uiStateReducer from "./slices/uiStateSlice";
 import { RangeInFile, SerializedDebugContext } from "../../../src/client";
 
 export interface ChatMessage {
@@ -31,6 +32,10 @@ export interface RootStore {
   misc: {
     highlightedCode: RangeInFile | undefined;
   };
+  uiState: {
+    bottomMessage: JSX.Element | undefined;
+    bottomMessageCloseTimeout: NodeJS.Timeout | undefined;
+  };
 }
 
 const store = configureStore({
@@ -39,6 +44,7 @@ const store = configureStore({
     chat: chatReducer,
     config: configReducer,
     misc: miscReducer,
+    uiState: uiStateReducer,
   },
 });
 
diff --git a/extension/schema/ContextItem.d.ts b/extension/schema/ContextItem.d.ts
new file mode 100644
index 00000000..62d2c32f
--- /dev/null
+++ b/extension/schema/ContextItem.d.ts
@@ -0,0 +1,45 @@
+/* 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 ContextItem = ContextItem1;
+export type Name = string;
+export type Description = string;
+export type ProviderTitle = string;
+export type ItemId = string;
+export type Content = string;
+export type Editing = boolean;
+export type Editable = boolean;
+
+/**
+ * A ContextItem is a single item that is stored in the ContextManager.
+ */
+export interface ContextItem1 {
+  description: ContextItemDescription;
+  content: Content;
+  editing?: Editing;
+  editable?: Editable;
+  [k: string]: unknown;
+}
+/**
+ * A ContextItemDescription is a description of a ContextItem that is displayed to the user when they type '@'.
+ *
+ * The id can be used to retrieve the ContextItem from the ContextManager.
+ */
+export interface ContextItemDescription {
+  name: Name;
+  description: Description;
+  id: ContextItemId;
+  [k: string]: unknown;
+}
+/**
+ * A ContextItemId is a unique identifier for a ContextItem.
+ */
+export interface ContextItemId {
+  provider_title: ProviderTitle;
+  item_id: ItemId;
+  [k: string]: unknown;
+}
diff --git a/extension/schema/FullState.d.ts b/extension/schema/FullState.d.ts
index 1b7b1f3b..0095f41b 100644
--- a/extension/schema/FullState.d.ts
+++ b/extension/schema/FullState.d.ts
@@ -27,18 +27,18 @@ 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 DisplayName = string;
-export type HighlightedRanges = HighlightedRangeContext[];
 export type Name3 = string;
 export type Description1 = string;
 export type SlashCommands = SlashCommandDescription[];
 export type AddingHighlightedCode = boolean;
+export type Name4 = string;
+export type Description2 = string;
+export type ProviderTitle = string;
+export type ItemId = string;
+export type Content1 = string;
+export type Editing = boolean;
+export type Editable = boolean;
+export type SelectedContextItems = ContextItem[];
 
 /**
  * A full state of the program, including the history
@@ -48,9 +48,9 @@ export interface FullState1 {
   active: Active1;
   user_input_queue: UserInputQueue;
   default_model: DefaultModel;
-  highlighted_ranges: HighlightedRanges;
   slash_commands: SlashCommands;
   adding_highlighted_code: AddingHighlightedCode;
+  selected_context_items: SelectedContextItems;
   [k: string]: unknown;
 }
 /**
@@ -98,40 +98,37 @@ export interface FunctionCall {
 export interface Observation {
   [k: string]: unknown;
 }
-/**
- * Context for a highlighted range
- */
-export interface HighlightedRangeContext {
-  range: RangeInFileWithContents;
-  editing: Editing;
-  pinned: Pinned;
-  display_name: DisplayName;
+export interface SlashCommandDescription {
+  name: Name3;
+  description: Description1;
   [k: string]: unknown;
 }
 /**
- * A range in a file with the contents of the range.
+ * A ContextItem is a single item that is stored in the ContextManager.
  */
-export interface RangeInFileWithContents {
-  filepath: Filepath;
-  range: Range;
-  contents: Contents;
+export interface ContextItem {
+  description: ContextItemDescription;
+  content: Content1;
+  editing?: Editing;
+  editable?: Editable;
   [k: string]: unknown;
 }
 /**
- * A range in a file. 0-indexed.
+ * A ContextItemDescription is a description of a ContextItem that is displayed to the user when they type '@'.
+ *
+ * The id can be used to retrieve the ContextItem from the ContextManager.
  */
-export interface Range {
-  start: Position;
-  end: Position;
+export interface ContextItemDescription {
+  name: Name4;
+  description: Description2;
+  id: ContextItemId;
   [k: string]: unknown;
 }
-export interface Position {
-  line: Line;
-  character: Character;
-  [k: string]: unknown;
-}
-export interface SlashCommandDescription {
-  name: Name3;
-  description: Description1;
+/**
+ * A ContextItemId is a unique identifier for a ContextItem.
+ */
+export interface ContextItemId {
+  provider_title: ProviderTitle;
+  item_id: ItemId;
   [k: string]: unknown;
 }
diff --git a/schema/json/ContextItem.json b/schema/json/ContextItem.json
new file mode 100644
index 00000000..35766f11
--- /dev/null
+++ b/schema/json/ContextItem.json
@@ -0,0 +1,76 @@
+{
+  "title": "ContextItem",
+  "$ref": "#/definitions/src__continuedev__core__context__ContextItem",
+  "definitions": {
+    "ContextItemId": {
+      "title": "ContextItemId",
+      "description": "A ContextItemId is a unique identifier for a ContextItem.",
+      "type": "object",
+      "properties": {
+        "provider_title": {
+          "title": "Provider Title",
+          "type": "string"
+        },
+        "item_id": {
+          "title": "Item Id",
+          "type": "string"
+        }
+      },
+      "required": [
+        "provider_title",
+        "item_id"
+      ]
+    },
+    "ContextItemDescription": {
+      "title": "ContextItemDescription",
+      "description": "A ContextItemDescription is a description of a ContextItem that is displayed to the user when they type '@'.\n\nThe id can be used to retrieve the ContextItem from the ContextManager.",
+      "type": "object",
+      "properties": {
+        "name": {
+          "title": "Name",
+          "type": "string"
+        },
+        "description": {
+          "title": "Description",
+          "type": "string"
+        },
+        "id": {
+          "$ref": "#/definitions/ContextItemId"
+        }
+      },
+      "required": [
+        "name",
+        "description",
+        "id"
+      ]
+    },
+    "src__continuedev__core__context__ContextItem": {
+      "title": "ContextItem",
+      "description": "A ContextItem is a single item that is stored in the ContextManager.",
+      "type": "object",
+      "properties": {
+        "description": {
+          "$ref": "#/definitions/ContextItemDescription"
+        },
+        "content": {
+          "title": "Content",
+          "type": "string"
+        },
+        "editing": {
+          "title": "Editing",
+          "default": false,
+          "type": "boolean"
+        },
+        "editable": {
+          "title": "Editable",
+          "default": false,
+          "type": "boolean"
+        }
+      },
+      "required": [
+        "description",
+        "content"
+      ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/schema/json/FullState.json b/schema/json/FullState.json
index 62ed337b..7b6dfd6b 100644
--- a/schema/json/FullState.json
+++ b/schema/json/FullState.json
@@ -157,108 +157,92 @@
         "current_index"
       ]
     },
-    "Position": {
-      "title": "Position",
+    "SlashCommandDescription": {
+      "title": "SlashCommandDescription",
       "type": "object",
       "properties": {
-        "line": {
-          "title": "Line",
-          "type": "integer"
+        "name": {
+          "title": "Name",
+          "type": "string"
         },
-        "character": {
-          "title": "Character",
-          "type": "integer"
+        "description": {
+          "title": "Description",
+          "type": "string"
         }
       },
       "required": [
-        "line",
-        "character"
+        "name",
+        "description"
       ]
     },
-    "Range": {
-      "title": "Range",
-      "description": "A range in a file. 0-indexed.",
+    "ContextItemId": {
+      "title": "ContextItemId",
+      "description": "A ContextItemId is a unique identifier for a ContextItem.",
       "type": "object",
       "properties": {
-        "start": {
-          "$ref": "#/definitions/Position"
+        "provider_title": {
+          "title": "Provider Title",
+          "type": "string"
         },
-        "end": {
-          "$ref": "#/definitions/Position"
+        "item_id": {
+          "title": "Item Id",
+          "type": "string"
         }
       },
       "required": [
-        "start",
-        "end"
+        "provider_title",
+        "item_id"
       ]
     },
-    "RangeInFileWithContents": {
-      "title": "RangeInFileWithContents",
-      "description": "A range in a file with the contents of the range.",
+    "ContextItemDescription": {
+      "title": "ContextItemDescription",
+      "description": "A ContextItemDescription is a description of a ContextItem that is displayed to the user when they type '@'.\n\nThe id can be used to retrieve the ContextItem from the ContextManager.",
       "type": "object",
       "properties": {
-        "filepath": {
-          "title": "Filepath",
+        "name": {
+          "title": "Name",
           "type": "string"
         },
-        "range": {
-          "$ref": "#/definitions/Range"
-        },
-        "contents": {
-          "title": "Contents",
+        "description": {
+          "title": "Description",
           "type": "string"
+        },
+        "id": {
+          "$ref": "#/definitions/ContextItemId"
         }
       },
       "required": [
-        "filepath",
-        "range",
-        "contents"
+        "name",
+        "description",
+        "id"
       ]
     },
-    "HighlightedRangeContext": {
-      "title": "HighlightedRangeContext",
-      "description": "Context for a highlighted range",
+    "ContextItem": {
+      "title": "ContextItem",
+      "description": "A ContextItem is a single item that is stored in the ContextManager.",
       "type": "object",
       "properties": {
-        "range": {
-          "$ref": "#/definitions/RangeInFileWithContents"
+        "description": {
+          "$ref": "#/definitions/ContextItemDescription"
+        },
+        "content": {
+          "title": "Content",
+          "type": "string"
         },
         "editing": {
           "title": "Editing",
+          "default": false,
           "type": "boolean"
         },
-        "pinned": {
-          "title": "Pinned",
+        "editable": {
+          "title": "Editable",
+          "default": false,
           "type": "boolean"
-        },
-        "display_name": {
-          "title": "Display Name",
-          "type": "string"
-        }
-      },
-      "required": [
-        "range",
-        "editing",
-        "pinned",
-        "display_name"
-      ]
-    },
-    "SlashCommandDescription": {
-      "title": "SlashCommandDescription",
-      "type": "object",
-      "properties": {
-        "name": {
-          "title": "Name",
-          "type": "string"
-        },
-        "description": {
-          "title": "Description",
-          "type": "string"
         }
       },
       "required": [
-        "name",
-        "description"
+        "description",
+        "content"
       ]
     },
     "src__continuedev__core__main__FullState": {
@@ -284,13 +268,6 @@
           "title": "Default Model",
           "type": "string"
         },
-        "highlighted_ranges": {
-          "title": "Highlighted Ranges",
-          "type": "array",
-          "items": {
-            "$ref": "#/definitions/HighlightedRangeContext"
-          }
-        },
         "slash_commands": {
           "title": "Slash Commands",
           "type": "array",
@@ -301,6 +278,13 @@
         "adding_highlighted_code": {
           "title": "Adding Highlighted Code",
           "type": "boolean"
+        },
+        "selected_context_items": {
+          "title": "Selected Context Items",
+          "type": "array",
+          "items": {
+            "$ref": "#/definitions/ContextItem"
+          }
         }
       },
       "required": [
@@ -308,9 +292,9 @@
         "active",
         "user_input_queue",
         "default_model",
-        "highlighted_ranges",
         "slash_commands",
-        "adding_highlighted_code"
+        "adding_highlighted_code",
+        "selected_context_items"
       ]
     }
   }
-- 
cgit v1.2.3-70-g09d2


From 8c8f3f546ebfb10b23312e7cb980f16730ccc61f Mon Sep 17 00:00:00 2001
From: Nate Sesti <sestinj@gmail.com>
Date: Sat, 22 Jul 2023 23:16:51 -0700
Subject: cleaning

---
 extension/react-app/src/components/ComboBox.tsx | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

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

diff --git a/extension/react-app/src/components/ComboBox.tsx b/extension/react-app/src/components/ComboBox.tsx
index 22a6d000..fdd1e9b7 100644
--- a/extension/react-app/src/components/ComboBox.tsx
+++ b/extension/react-app/src/components/ComboBox.tsx
@@ -178,6 +178,9 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
                 };
               })
             );
+          })
+          .catch((err) => {
+            console.error(err);
           });
         return;
       }
@@ -194,10 +197,6 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
   });
 
   useEffect(() => {
-    console.log(
-      "downshiftProps.highlightedIndex",
-      downshiftProps.highlightedIndex
-    );
     if (downshiftProps.highlightedIndex < 0) {
       downshiftProps.setHighlightedIndex(0);
     }
-- 
cgit v1.2.3-70-g09d2


From 8141e205bae7e5e7537a721ca21ea7b6024ffca7 Mon Sep 17 00:00:00 2001
From: Nate Sesti <sestinj@gmail.com>
Date: Mon, 24 Jul 2023 17:47:37 -0700
Subject: file context provider and hovering niceties

---
 continuedev/src/continuedev/core/config.py         | 10 +++---
 continuedev/src/continuedev/core/main.py           | 11 +++++-
 .../context_providers/file_context_provider.py     |  5 +--
 extension/react-app/src/components/ComboBox.tsx    | 23 ++++++++-----
 extension/react-app/src/components/PillButton.tsx  | 23 +++++++++----
 extension/react-app/src/pages/gui.tsx              | 40 +++++++++++++++++-----
 6 files changed, 80 insertions(+), 32 deletions(-)

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

diff --git a/continuedev/src/continuedev/core/config.py b/continuedev/src/continuedev/core/config.py
index bb9ca323..565c617d 100644
--- a/continuedev/src/continuedev/core/config.py
+++ b/continuedev/src/continuedev/core/config.py
@@ -56,11 +56,11 @@ class ContinueConfig(BaseModel):
     # Want to force these to be the slash commands for now
     @validator('slash_commands', pre=True)
     def default_slash_commands_validator(cls, v):
-        from ..steps.open_config import OpenConfigStep
-        from ..steps.clear_history import ClearHistoryStep
-        from ..steps.feedback import FeedbackStep
-        from ..steps.comment_code import CommentCodeStep
-        from ..steps.main import EditHighlightedCodeStep
+        from ..plugins.steps.open_config import OpenConfigStep
+        from ..plugins.steps.clear_history import ClearHistoryStep
+        from ..plugins.steps.feedback import FeedbackStep
+        from ..plugins.steps.comment_code import CommentCodeStep
+        from ..plugins.steps.main import EditHighlightedCodeStep
 
         DEFAULT_SLASH_COMMANDS = [
             SlashCommand(
diff --git a/continuedev/src/continuedev/core/main.py b/continuedev/src/continuedev/core/main.py
index 6c6adccc..df9b98ef 100644
--- a/continuedev/src/continuedev/core/main.py
+++ b/continuedev/src/continuedev/core/main.py
@@ -207,12 +207,21 @@ class ContextItemId(BaseModel):
     provider_title: str
     item_id: str
 
+    @validator('provider_title', 'item_id')
+    def must_be_valid_id(cls, v):
+        import re
+        if not re.match(r'^[0-9a-zA-Z_-]*$', v):
+            raise ValueError(
+                "Both provider_title and item_id can only include characters 0-9, a-z, A-Z, -, and _")
+        return v
+
     def to_string(self) -> str:
         return f"{self.provider_title}-{self.item_id}"
 
     @staticmethod
     def from_string(string: str) -> 'ContextItemId':
-        provider_title, item_id = string.split('-')
+        provider_title, *rest = string.split('-')
+        item_id = '-'.join(rest)
         return ContextItemId(provider_title=provider_title, item_id=item_id)
 
 
diff --git a/continuedev/src/continuedev/plugins/context_providers/file_context_provider.py b/continuedev/src/continuedev/plugins/context_providers/file_context_provider.py
index 854310b1..632a876c 100644
--- a/continuedev/src/continuedev/plugins/context_providers/file_context_provider.py
+++ b/continuedev/src/continuedev/plugins/context_providers/file_context_provider.py
@@ -1,4 +1,5 @@
 import os
+import re
 from typing import List
 from ...core.main import ContextItem, ContextItemDescription, ContextItemId
 from ...core.context import ContextProvider
@@ -45,11 +46,11 @@ class FileContextProvider(ContextProvider):
             content=get_file_contents(file)[:min(
                 2000, len(get_file_contents(file)))],
             description=ContextItemDescription(
-                name=f"File {os.path.basename(file)}",
+                name=os.path.basename(file),
                 description=file,
                 id=ContextItemId(
                     provider_title=self.title,
-                    item_id=file
+                    item_id=re.sub(r'[^0-9a-zA-Z_-]', '', file)
                 )
             )
         ) for file in filepaths]
diff --git a/extension/react-app/src/components/ComboBox.tsx b/extension/react-app/src/components/ComboBox.tsx
index fdd1e9b7..7d266c6e 100644
--- a/extension/react-app/src/components/ComboBox.tsx
+++ b/extension/react-app/src/components/ComboBox.tsx
@@ -20,6 +20,8 @@ import { ContextItem } from "../../../schema/FullState";
 import { postVscMessage } from "../vscode";
 import { GUIClientContext } from "../App";
 import { MeiliSearch } from "meilisearch";
+import { setBottomMessageCloseTimeout } from "../redux/slices/uiStateSlice";
+import { useDispatch } from "react-redux";
 
 const SEARCH_INDEX_NAME = "continue_context_items";
 
@@ -124,6 +126,7 @@ interface ComboBoxProps {
 const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
   const searchClient = new MeiliSearch({ host: "http://127.0.0.1:7700" });
   const client = useContext(GUIClientContext);
+  const dispatch = useDispatch();
 
   const [history, setHistory] = React.useState<string[]>([]);
   // The position of the current command you are typing now, so the one that will be appended to history once you press enter
@@ -179,8 +182,8 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
               })
             );
           })
-          .catch((err) => {
-            console.error(err);
+          .catch(() => {
+            // Swallow errors, because this simply is not supported on Windows at the moment
           });
         return;
       }
@@ -202,6 +205,12 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
     }
   }, [downshiftProps.inputValue]);
 
+  const divRef = React.useRef<HTMLDivElement>(null);
+  const ulRef = React.useRef<HTMLUListElement>(null);
+  const showAbove = () => {
+    return (divRef.current?.getBoundingClientRect().top || 0) > UlMaxHeight;
+  };
+
   useImperativeHandle(ref, () => downshiftProps, [downshiftProps]);
 
   const [metaKeyPressed, setMetaKeyPressed] = useState(false);
@@ -241,12 +250,6 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
     };
   }, [inputRef.current]);
 
-  const divRef = React.useRef<HTMLDivElement>(null);
-  const ulRef = React.useRef<HTMLUListElement>(null);
-  const showAbove = () => {
-    return (divRef.current?.getBoundingClientRect().top || 0) > UlMaxHeight;
-  };
-
   return (
     <>
       <div className="px-2 flex gap-2 items-center flex-wrap mt-2">
@@ -304,6 +307,7 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
             },
             onFocus: (e) => {
               setFocused(true);
+              dispatch(setBottomMessageCloseTimeout(undefined));
             },
             onBlur: (e) => {
               setFocused(false);
@@ -358,6 +362,9 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
                 setCurrentlyInContextQuery(false);
               }
             },
+            onClick: () => {
+              dispatch(setBottomMessageCloseTimeout(undefined));
+            },
             ref: inputRef,
           })}
         />
diff --git a/extension/react-app/src/components/PillButton.tsx b/extension/react-app/src/components/PillButton.tsx
index af4263af..660ede09 100644
--- a/extension/react-app/src/components/PillButton.tsx
+++ b/extension/react-app/src/components/PillButton.tsx
@@ -1,8 +1,9 @@
-import { useContext, useEffect, useState } from "react";
+import { useContext, useEffect, useRef, useState } from "react";
 import styled from "styled-components";
 import {
   StyledTooltip,
   defaultBorderRadius,
+  lightGray,
   secondaryDark,
   vscBackground,
   vscForeground,
@@ -96,12 +97,19 @@ const PillButton = (props: PillButtonProps) => {
           <>
             <b>{props.item.description.name}</b>:{" "}
             {props.item.description.description}
-            <StyledMarkdownPreview
-              source={`\`\`\`\n${props.item.content}\n\`\`\``}
-              wrapperElement={{
-                "data-color-mode": "dark",
-              }}
-            />
+            <pre>
+              <code
+                style={{
+                  fontSize: "10px",
+                  backgroundColor: vscBackground,
+                  color: vscForeground,
+                  whiteSpace: "pre-wrap",
+                  wordWrap: "break-word",
+                }}
+              >
+                {props.item.content}
+              </code>
+            </pre>
           </>
         )
       );
@@ -178,6 +186,7 @@ const PillButton = (props: PillButtonProps) => {
                 backgroundColor={"#cc000055"}
                 onClick={() => {
                   client?.deleteContextWithIds([props.item.description.id]);
+                  dispatch(setBottomMessageCloseTimeout(undefined));
                 }}
               >
                 <Trash style={{ margin: "auto" }} width="1.6em"></Trash>
diff --git a/extension/react-app/src/pages/gui.tsx b/extension/react-app/src/pages/gui.tsx
index 9a00802b..03b24349 100644
--- a/extension/react-app/src/pages/gui.tsx
+++ b/extension/react-app/src/pages/gui.tsx
@@ -125,6 +125,24 @@ function GUI(props: GUIProps) {
     (state: RootStore) => state.uiState.bottomMessage
   );
 
+  const [displayBottomMessageOnBottom, setDisplayBottomMessageOnBottom] =
+    useState<boolean>(true);
+  const mainTextInputRef = useRef<HTMLInputElement>(null);
+
+  const aboveComboBoxDivRef = useRef<HTMLDivElement>(null);
+
+  useEffect(() => {
+    if (!aboveComboBoxDivRef.current) return;
+    if (
+      aboveComboBoxDivRef.current.getBoundingClientRect().top >
+      window.innerHeight / 2
+    ) {
+      setDisplayBottomMessageOnBottom(false);
+    } else {
+      setDisplayBottomMessageOnBottom(true);
+    }
+  }, [bottomMessage, aboveComboBoxDivRef.current]);
+
   const topGuiDivRef = useRef<HTMLDivElement>(null);
 
   const [scrollTimeout, setScrollTimeout] = useState<NodeJS.Timeout | null>(
@@ -156,6 +174,8 @@ function GUI(props: GUIProps) {
         history.timeline[history.current_index]?.active
       ) {
         client?.deleteAtIndex(history.current_index);
+      } else if (e.key === "Escape") {
+        dispatch(setBottomMessageCloseTimeout(undefined));
       }
     };
     window.addEventListener("keydown", listener);
@@ -182,7 +202,6 @@ function GUI(props: GUIProps) {
 
       setWaitingForSteps(waitingForSteps);
       setHistory(state.history);
-      console.log((state as any).selected_context_items);
       setSelectedContextItems(state.selected_context_items);
       setUserInputQueue(state.user_input_queue);
       setAddingHighlightedCode(state.adding_highlighted_code);
@@ -216,8 +235,6 @@ function GUI(props: GUIProps) {
     scrollToBottom();
   }, [waitingForSteps]);
 
-  const mainTextInputRef = useRef<HTMLInputElement>(null);
-
   const onMainTextInput = (event?: any) => {
     if (mainTextInputRef.current) {
       let input = (mainTextInputRef.current as any).inputValue;
@@ -349,6 +366,7 @@ function GUI(props: GUIProps) {
           })}
         </div>
 
+        <div ref={aboveComboBoxDivRef} />
         <ComboBox
           ref={mainTextInputRef}
           onEnter={(e) => {
@@ -370,21 +388,25 @@ function GUI(props: GUIProps) {
         onMouseEnter={() => {
           dispatch(setBottomMessageCloseTimeout(undefined));
         }}
-        onMouseLeave={() => {
-          dispatch(setBottomMessage(undefined));
+        onMouseLeave={(e) => {
+          if (!e.buttons) {
+            dispatch(setBottomMessage(undefined));
+          }
         }}
         style={{
           position: "fixed",
-          bottom: "50px",
+          bottom: displayBottomMessageOnBottom ? "50px" : undefined,
+          top: displayBottomMessageOnBottom ? undefined : "50px",
           left: "0",
           right: "0",
-          margin: "16px",
+          margin: "8px",
+          marginTop: "0px",
           backgroundColor: vscBackground,
           color: vscForeground,
           borderRadius: defaultBorderRadius,
-          padding: "16px",
+          padding: "12px",
           zIndex: 100,
-          boxShadow: `0px 0px 10px 0px ${vscForeground}`,
+          boxShadow: `0px 0px 6px 0px ${vscForeground}`,
           maxHeight: "50vh",
           overflow: "scroll",
         }}
-- 
cgit v1.2.3-70-g09d2


From c0799a92d3588cefa7c88a18452811d0153c685b Mon Sep 17 00:00:00 2001
From: Nate Sesti <sestinj@gmail.com>
Date: Mon, 24 Jul 2023 23:12:49 -0700
Subject: tweaks

---
 continuedev/.gitignore                             |   1 -
 continuedev/notes.md                               | 101 +++++++++++++++++++++
 continuedev/src/continuedev/core/autopilot.py      |   4 +-
 extension/package.json                             |   2 +-
 extension/react-app/public/continue-dev-square.png | Bin 0 -> 36355 bytes
 extension/react-app/src/components/ComboBox.tsx    |   2 +-
 .../react-app/src/components/ContinueButton.tsx    |   3 +-
 extension/react-app/src/components/PillButton.tsx  |   2 +-
 extension/react-app/src/pages/gui.tsx              |  58 +++---------
 9 files changed, 120 insertions(+), 53 deletions(-)
 delete mode 100644 continuedev/.gitignore
 create mode 100644 continuedev/notes.md
 create mode 100644 extension/react-app/public/continue-dev-square.png

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

diff --git a/continuedev/.gitignore b/continuedev/.gitignore
deleted file mode 100644
index a9d34b8b..00000000
--- a/continuedev/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-notes.md
\ No newline at end of file
diff --git a/continuedev/notes.md b/continuedev/notes.md
new file mode 100644
index 00000000..bfd8cf4a
--- /dev/null
+++ b/continuedev/notes.md
@@ -0,0 +1,101 @@
+### List of concrete things that will be built
+
+- Interface with language servers
+- Central place to initiate language model suggestions
+- Abstracted set of tools around language servers and other complicated sources of information
+- Way to keep track of reversible/replayable series of human/LLM changes to code, at better granularity that git
+- A library of prompts and tools to combine them to yield good examples
+- A basic LLM agnostic prompting interface
+- The server or something that can be integrated easily into an extension for any IDE
+- A CLI tool that can be called to make a one-off change on some codebase
+- A default interface that can run at localhost, but which we will also create a desktop application version of
+- Tools to parse LLM output to get file outputs
+- Parse and unparse tracebacks in any language
+- FileEdit/FileDiff creation from LLM output where you don't necessarily know the position of the lines
+- Test generation and tools to use
+- Tools/prompts for summarizing groups of file edits
+- Need to be able to remove/add files. Is there any other reversible action you should be considering? Does git track anything else? Renaming files, or adding/removing folders.
+
+There should be different levels of abstraction at which you can work with these concepts. One of them should be as simple as
+
+- You write a formatted string with FormattedStringPrompter
+- Specify a source for each of the strings, by a simple strongly typed enum, like traceback or something else
+  maybe not realistic or useful
+
+---
+
+- One big thing that happens as you're fixing errors is that you encounter a fork in the road. The language model should be able to present you with both options, and you just click to decide.
+- What I'm doing right now: I write a bunch of code without running it, then ahve to solve a bunch of errors at once, but small obvious ones. We can do this all automatically.
+
+---
+
+### Current limitations:
+
+- We are always specifying how to use the tools directly instead of letting the AI choose how to use them on its own. You should expand to allow this.
+- We want the history of both user and AI changes to be reflected as a single agent. So you need to watch for user updates to the filesystem. See https://pythonhosted.org/watchdog/quickstart.html#quickstart
+- Language servers are a big deal, you've not done anything about that quite yet.
+  - class to manage all of them, and some way to configure which to run.
+  - call them inside actions? Probably not. Does language server ever make changes? Maybe you just create a python client
+- You want this library to play well with IDEs, which means it should see file changes even before they are saved. What you're building might look more like a language server than anything else then. Just an extended language server. Something else that points at this is your need for watching the filesystem for changes. This is precisely what the LSP does.
+- Prompts don't always transfer well between models. So a prompt should actually have different versions for each model, instead of being just a single string.
+- Kind of weird syntax for creating your own actions, validators, etc... USE ANNOTATIONS
+- Stuff should be serializable
+- We also want to be able to answer questions, not just generate file edits.
+
+### Plugins
+
+Plugin is a more general word, which subsumes validator plugins, tool plugins, what else?
+
+### Continue as Extended Language Server
+
+- Language server capable of directly editing the filesystem and running commands.
+- Really just needs to write to files, or suggest file edits. But actually in an ideal future it can do more, like press every button in the IDE
+
+The question isn't now "do we want to use it," but "is it the actual thing we are building?" I've realized that we need 1) to watch files for changes and make suggestions based off of these, 2) need to be language agnostic, 3) need to plug in to any IDE ideally. All of these things are the bread and butter of LSP. It seems like what we might actually be building is a headless LSP client, or an LSP server with a backdoor, or an LSP server with more endpoints. Trying to figure out where it best fits in.
+
+- We're not totally focusing on responding to small updates, so it might be okay to later build our own endpoint to watch for non-save updates to files.
+- There aren't so many things that need to be done in their own language that aren't already done in LSP, are there?
+
+Overall, I think you should just think of this framework as a way of giving tools to language models and then putting them in a loop to edit, validate, run code. Tools are the plugins, and so you shouldn't have to build all of them, and they should be written in any language.
+
+The LSP Tool is just another tool. It will be common, so you want it built-in, but it's just another tool.
+The thing about LSP is that there's a lot of state going on, and it needs to be running the whole time.
+An edit in VS Code before saving can just be a hook to watch for, can replace the WatchDog thing.
+
+A cool feature of what we're doing is that we might summarize the changes made by a human, such that they can separate their work into describable and reversible parts.
+
+In essence, our framework makes it easy for people to match up problems to prompts. So people can share their solutions of the form "whenever you see this error, you can run this prompt with these tools, and it will fix it automatically".
+
+I'm finding that the validators are pretty tightly tied to the actions. Should this be reflected in a single class for both?
+
+---
+
+The final simplification you could make: policies are actions. So the very first action that is always called is actually a policy, but it might be instantiated with a specific action first.
+
+Don't do this right now. But you might want to, and make it DAGs all the way down.
+
+Other consideration: a good amount of work could go into defining the spaces of observations.
+
+"""
+What do they do that's interesting:
+
+- agent has get_allowed_tools() method
+- They have analog of Prompter with PromptTemplate
+- they pass an LLM object to instantiate the Chain object
+
+What doesn't LangChain do right?
+
+They don't have stopping as an action
+Not reversible
+"""
+
+Runners could also be pluginable. They are like the middleware for actions.
+
+- Ask for permission
+- Keep track of substeps in DAG
+- Keep locks on resources, have steps declare the resources they will use / want to lock up
+
+Policies should be generators! This makes it much more natural to group steps. Also means you can probably just define a decorator to a generator function that will turn it into a full policy class.
+This is just syntactic sugar though.
+
+can you also make an annotation for actions, so you just have to write the run function? And then automatically add it to the pluggy library somehow.
diff --git a/continuedev/src/continuedev/core/autopilot.py b/continuedev/src/continuedev/core/autopilot.py
index 0e355d78..d018c29e 100644
--- a/continuedev/src/continuedev/core/autopilot.py
+++ b/continuedev/src/continuedev/core/autopilot.py
@@ -9,8 +9,8 @@ from ..models.filesystem import RangeInFileWithContents
 from ..models.filesystem_edit import FileEditWithFullContents
 from .observation import Observation, InternalErrorObservation
 from .context import ContextManager
-from ..plugins.context_providers.file_context_provider import FileContextProvider
-from ..plugins.context_providers.highlighted_code_context_provider import HighlightedCodeContextProvider
+from ..plugins.context_providers.file import FileContextProvider
+from ..plugins.context_providers.highlighted_code import HighlightedCodeContextProvider
 from ..server.ide_protocol import AbstractIdeProtocolServer
 from ..libs.util.queue import AsyncSubscriptionQueue
 from ..models.main import ContinueBaseModel
diff --git a/extension/package.json b/extension/package.json
index cfce77df..f1add025 100644
--- a/extension/package.json
+++ b/extension/package.json
@@ -225,7 +225,7 @@
     "lint": "eslint src --ext ts",
     "test": "node ./out/test/runTest.js",
     "jest": "jest --config ./jest.config.js",
-    "package": "cp ./config/prod_config.json ./config/config.json && mkdir -p ./build && vsce package --out ./build && cp ./config/dev_config.json ./config/config.json",
+    "package": "mkdir -p ./build && vsce package --out ./build",
     "full-package": "cd ../continuedev && poetry install && poetry build && cp ./dist/continuedev-0.1.2-py3-none-any.whl ../extension/server/continuedev-0.1.2-py3-none-any.whl && cd ../extension && npm install && npm run typegen && npm run clientgen && cd react-app && npm install && npm run build && cd .. && npm run package",
     "install-extension": "code --install-extension ./build/continue-0.0.8.vsix",
     "uninstall": "code --uninstall-extension .continue",
diff --git a/extension/react-app/public/continue-dev-square.png b/extension/react-app/public/continue-dev-square.png
new file mode 100644
index 00000000..e4b62556
Binary files /dev/null and b/extension/react-app/public/continue-dev-square.png differ
diff --git a/extension/react-app/src/components/ComboBox.tsx b/extension/react-app/src/components/ComboBox.tsx
index 7d266c6e..4a1cdbc0 100644
--- a/extension/react-app/src/components/ComboBox.tsx
+++ b/extension/react-app/src/components/ComboBox.tsx
@@ -291,7 +291,7 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {
       <div className="flex px-2" ref={divRef} hidden={!downshiftProps.isOpen}>
         <MainTextInput
           disabled={props.disabled}
-          placeholder={`Ask a question, give instructions, or type '/' to see slash commands`}
+          placeholder={`Ask a question, give instructions, type '/' for slash commands, or '@' to add context`}
           {...getInputProps({
             onChange: (e) => {
               const target = e.target as HTMLTextAreaElement;
diff --git a/extension/react-app/src/components/ContinueButton.tsx b/extension/react-app/src/components/ContinueButton.tsx
index eda9bcff..6d753988 100644
--- a/extension/react-app/src/components/ContinueButton.tsx
+++ b/extension/react-app/src/components/ContinueButton.tsx
@@ -26,7 +26,8 @@ function ContinueButton(props: { onClick?: () => void; hidden?: boolean }) {
   return (
     <StyledButton
       hidden={props.hidden}
-      className="m-auto press-start-2p text-xs"
+      style={{ fontSize: "10px" }}
+      className="m-auto press-start-2p"
       onClick={props.onClick}
     >
       {vscMediaUrl ? (
diff --git a/extension/react-app/src/components/PillButton.tsx b/extension/react-app/src/components/PillButton.tsx
index 660ede09..548fdf9d 100644
--- a/extension/react-app/src/components/PillButton.tsx
+++ b/extension/react-app/src/components/PillButton.tsx
@@ -100,7 +100,7 @@ const PillButton = (props: PillButtonProps) => {
             <pre>
               <code
                 style={{
-                  fontSize: "10px",
+                  fontSize: "11px",
                   backgroundColor: vscBackground,
                   color: vscForeground,
                   whiteSpace: "pre-wrap",
diff --git a/extension/react-app/src/pages/gui.tsx b/extension/react-app/src/pages/gui.tsx
index d7efc288..76194db7 100644
--- a/extension/react-app/src/pages/gui.tsx
+++ b/extension/react-app/src/pages/gui.tsx
@@ -116,6 +116,9 @@ function GUI(props: GUIProps) {
     current_index: 3,
   } as any);
 
+  const vscMediaUrl = useSelector(
+    (state: RootStore) => state.config.vscMediaUrl
+  );
   const [showFeedbackDialog, setShowFeedbackDialog] = useState(false);
   const [feedbackDialogMessage, setFeedbackDialogMessage] = useState("");
   const [feedbackEntryOn, setFeedbackEntryOn] = useState(true);
@@ -415,52 +418,15 @@ function GUI(props: GUIProps) {
         {bottomMessage}
       </div>
       <Footer dataSwitchChecked={dataSwitchChecked}>
-        {/* <div
-          style={{
-            display: "flex",
-            gap: "4px",
-            marginRight: "auto",
-            alignItems: "center",
-          }}
-          onMouseEnter={() => {
-            dispatch(
-              setBottomMessage(
-                <>
-                  By turning on this switch, you will begin collecting accepted
-                  and rejected suggestions in .continue/suggestions.json. This
-                  data is stored locally on your machine and not sent anywhere.
-                  <br />
-                  <br />
-                  <b>
-                    {dataSwitchChecked
-                      ? "👍 Data is being collected"
-                      : "👎 No data is being collected"}
-                  </b>
-                </>
-              )
-            );
-          }}
-          onMouseLeave={() => {
-            dispatch(setBottomMessage(undefined));
-          }}
-        >
-          <ReactSwitch
-            height={20}
-            handleDiameter={20}
-            width={40}
-            onChange={() => {
-              posthog?.capture("data_switch_toggled", {
-                vscMachineId: vscMachineId,
-                dataSwitchChecked: !dataSwitchChecked,
-              });
-              postVscMessage("toggleDataSwitch", { on: !dataSwitchChecked });
-              setDataSwitchChecked((prev) => !prev);
-            }}
-            onColor="#12887a"
-            checked={dataSwitchChecked}
-          />
-          <span style={{ cursor: "help", fontSize: "14px" }}>Collect Data</span>
-        </div> */}
+        {vscMediaUrl && (
+          <a
+            href="https://github.com/continuedev/continue"
+            style={{ margin: "0", marginRight: "auto" }}
+          >
+            <img src={`${vscMediaUrl}/continue-dev-square.png`} width="22px" />
+            <p style={{ margin: "0" }}>Continue</p>
+          </a>
+        )}
         <HeaderButtonWithText
           onClick={() => {
             // Show the dialog
-- 
cgit v1.2.3-70-g09d2

