From d342c55ed2b8b229ccd40cc45f7af05cb73e7ad0 Mon Sep 17 00:00:00 2001 From: Nate Sesti Date: Sun, 9 Jul 2023 13:09:34 -0700 Subject: expand max_tokens for large highlighted ranges --- extension/src/activation/environmentSetup.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'extension/src/activation/environmentSetup.ts') diff --git a/extension/src/activation/environmentSetup.ts b/extension/src/activation/environmentSetup.ts index 90ec9259..714080e3 100644 --- a/extension/src/activation/environmentSetup.ts +++ b/extension/src/activation/environmentSetup.ts @@ -324,7 +324,14 @@ export async function startContinuePythonServer() { } } console.log("Killing old server..."); - await fkill(":65432"); + try { + await fkill(":65432"); + } catch (e) { + console.log( + "Failed to kill old server, likely because it didn't exist:", + e + ); + } } // Do this after above check so we don't have to waste time setting up the env -- cgit v1.2.3-70-g09d2 From d566dc90a32db926393e1d10f983c79bc3feb56a Mon Sep 17 00:00:00 2001 From: Nate Sesti Date: Sun, 9 Jul 2023 16:19:16 -0700 Subject: cache server env in .continue folder --- extension/DEV_README.md | 2 +- extension/package.json | 2 +- extension/react-app/src/tabs/gui.tsx | 2 +- extension/scripts/.gitignore | 5 - extension/scripts/README.md | 5 - extension/scripts/chroma.py | 152 ---------------------- extension/scripts/index.py | 52 -------- extension/scripts/query.py | 63 --------- extension/scripts/replace.py | 17 --- extension/scripts/requirements.txt | 6 - extension/scripts/run_continue_server.py | 4 - extension/scripts/update.py | 185 --------------------------- extension/server/.gitignore | 1 + extension/server/README.md | 3 + extension/server/requirements.txt | 1 + extension/server/run_continue_server.py | 4 + extension/src/activation/environmentSetup.ts | 97 ++++++++++---- 17 files changed, 85 insertions(+), 516 deletions(-) delete mode 100644 extension/scripts/.gitignore delete mode 100644 extension/scripts/README.md delete mode 100644 extension/scripts/chroma.py delete mode 100644 extension/scripts/index.py delete mode 100644 extension/scripts/query.py delete mode 100644 extension/scripts/replace.py delete mode 100644 extension/scripts/requirements.txt delete mode 100644 extension/scripts/run_continue_server.py delete mode 100644 extension/scripts/update.py create mode 100644 extension/server/.gitignore create mode 100644 extension/server/README.md create mode 100644 extension/server/requirements.txt create mode 100644 extension/server/run_continue_server.py (limited to 'extension/src/activation/environmentSetup.ts') diff --git a/extension/DEV_README.md b/extension/DEV_README.md index c247b82c..87ed9334 100644 --- a/extension/DEV_README.md +++ b/extension/DEV_README.md @@ -4,7 +4,7 @@ This is the Continue VS Code Extension. Its primary jobs are 1. Implement the IDE side of the Continue IDE protocol, allowing a Continue server to interact natively in an IDE. This happens in `src/continueIdeClient.ts`. 2. Open the Continue React app in a side panel. The React app's source code lives in the `react-app` directory. The panel is opened by the `continue.openContinueGUI` command, as defined in `src/commands.ts`. -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). +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 `server/` (unless extension settings define a server URL other than localhost:65432, in which case the extension will just connect to that). 4. Open Continue diff --git a/extension/package.json b/extension/package.json index 444372f8..3b23ff19 100644 --- a/extension/package.json +++ b/extension/package.json @@ -227,7 +227,7 @@ "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", + "full-package": "cd ../continuedev && 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", "reinstall": "rm -rf ./build && npm run package && npm run uninstall && npm run install-extension" diff --git a/extension/react-app/src/tabs/gui.tsx b/extension/react-app/src/tabs/gui.tsx index e1ecec9e..646aef50 100644 --- a/extension/react-app/src/tabs/gui.tsx +++ b/extension/react-app/src/tabs/gui.tsx @@ -438,7 +438,7 @@ function GUI(props: GUIProps) { if (!usingFastModel) { // Show the dialog setFeedbackDialogMessage( - "We don't yet support local models, but we're working on it! If privacy is a concern of yours, please use the feedback button in the bottom right to let us know." + "We don't yet support local models, but we're working on it! If privacy is a concern of yours, please write a short note to let us know." ); setShowFeedbackDialog(true); } diff --git a/extension/scripts/.gitignore b/extension/scripts/.gitignore deleted file mode 100644 index fbb3bf9f..00000000 --- a/extension/scripts/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -testdb -env -stdout.txt -.continue_env_installed -**.whl \ No newline at end of file diff --git a/extension/scripts/README.md b/extension/scripts/README.md deleted file mode 100644 index da1ad493..00000000 --- a/extension/scripts/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# Scripts - -Whenever we need python to run on the client side, we include a script file at the top level of this folder. All other files that are not to be run directly as a script (utility files) should be in a subfolder of `scripts`. You can call one of these scripts from the VS Code extension using the `runPythonScript` function in `bridge.ts`. - -When the extension is activated (`activate` function in `src/extension.ts`), we call `setupPythonEnv`, which makes the virtual environment and downloads all the necessary requirements as given in `requirements.txt`. With this in mind, be sure to run `pip freeze > requirements.txt` whenever you add a new requirement. diff --git a/extension/scripts/chroma.py b/extension/scripts/chroma.py deleted file mode 100644 index 7425394e..00000000 --- a/extension/scripts/chroma.py +++ /dev/null @@ -1,152 +0,0 @@ -import chromadb -import os -import json -import subprocess - -from typing import List, Tuple - -from chromadb.config import Settings - -client = chromadb.Client(Settings( - chroma_db_impl="duckdb+parquet", - persist_directory="./data/" -)) - -FILE_TYPES_TO_IGNORE = [ - '.pyc', - '.png', - '.jpg', - '.jpeg', - '.gif', - '.svg', - '.ico' -] - -def further_filter(files: List[str], root_dir: str): - """Further filter files before indexing.""" - for file in files: - if file.endswith(tuple(FILE_TYPES_TO_IGNORE)) or file.startswith('.git') or file.startswith('archive'): - continue - yield root_dir + "/" + file - -def get_git_root_dir(path: str): - """Get the root directory of a Git repository.""" - try: - return subprocess.check_output(['git', 'rev-parse', '--show-toplevel'], cwd=path).strip().decode() - except subprocess.CalledProcessError: - return None - -def get_git_ignored_files(root_dir: str): - """Get the list of ignored files in a Git repository.""" - try: - output = subprocess.check_output(['git', 'ls-files', '--ignored', '--others', '--exclude-standard'], cwd=root_dir).strip().decode() - return output.split('\n') - except subprocess.CalledProcessError: - return [] - -def get_all_files(root_dir: str): - """Get a list of all files in a directory.""" - for dir_path, _, file_names in os.walk(root_dir): - for file_name in file_names: - yield os.path.join(os.path.relpath(dir_path, root_dir), file_name) - -def get_input_files(root_dir: str): - """Get a list of all files in a Git repository that are not ignored.""" - ignored_files = set(get_git_ignored_files(root_dir)) - all_files = set(get_all_files(root_dir)) - nonignored_files = all_files - ignored_files - return further_filter(nonignored_files, root_dir) - -def get_git_root_dir(cwd: str): - """Get the root directory of a Git repository.""" - result = subprocess.run(['git', 'rev-parse', '--show-toplevel'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=cwd) - return result.stdout.decode().strip() - -def get_current_branch(cwd: str) -> str: - """Get the current Git branch.""" - try: - return subprocess.check_output(["git", "rev-parse", "--abbrev-ref", "HEAD"], cwd=cwd).decode("utf-8").strip() - except: - return "main" - -def get_current_commit(cwd: str) -> str: - try: - return subprocess.check_output(["git", "rev-parse", "HEAD"], cwd=cwd).decode("utf-8").strip() - except: - return "NO_COMMITS" - -def get_modified_deleted_files(cwd: str) -> Tuple[List[str], List[str]]: - """Get a list of all files that have been modified since the last commit.""" - branch = get_current_branch(cwd) - current_commit = get_current_commit(cwd) - - with open(f"./data/{branch}.json", 'r') as f: - previous_commit = json.load(f)["commit"] - - modified_deleted_files = subprocess.check_output(["git", "diff", "--name-only", previous_commit, current_commit], cwd=cwd).decode("utf-8").strip() - modified_deleted_files = modified_deleted_files.split("\n") - modified_deleted_files = [f for f in modified_deleted_files if f] - - root = get_git_root_dir(cwd) - deleted_files = [f for f in modified_deleted_files if not os.path.exists(root + "/" + f)] - modified_files = [f for f in modified_deleted_files if os.path.exists(root + "/" + f)] - - return further_filter(modified_files, root), further_filter(deleted_files, root) - -def create_collection(branch: str, cwd: str): - """Create a new collection, returning whether it already existed.""" - try: - collection = client.create_collection(name=branch) - except Exception as e: - print(e) - return - - files = get_input_files(get_git_root_dir(cwd)) - for file in files: - with open(file, 'r') as f: - collection.add(documents=[f.read()], ids=[file]) - print(f"Added {file}") - with open(f"./data/{branch}.json", 'w') as f: - json.dump({"commit": get_current_commit(cwd)}, f) - -def collection_exists(cwd: str): - """Check if a collection exists.""" - branch = get_current_branch(cwd) - return branch in client.list_collections() - -def update_collection(cwd: str): - """Update the collection.""" - branch = get_current_branch(cwd) - - try: - - collection = client.get_collection(branch) - - modified_files, deleted_files = get_modified_deleted_files(cwd) - - for file in deleted_files: - collection.delete(ids=[file]) - print(f"Deleted {file}") - - for file in modified_files: - with open(file, 'r') as f: - collection.update(documents=[f.read()], ids=[file]) - print(f"Updated {file}") - - with open(f"./data/{branch}.json", 'w') as f: - json.dump({"commit": get_current_commit(cwd)}, f) - - except: - - create_collection(branch, cwd) - -def query_collection(query: str, n_results: int, cwd: str): - """Query the collection.""" - branch = get_current_branch(cwd) - try: - collection = client.get_collection(branch) - except: - create_collection(branch, cwd) - collection = client.get_collection(branch) - results = collection.query(query_texts=[query], n_results=n_results) - return results \ No newline at end of file diff --git a/extension/scripts/index.py b/extension/scripts/index.py deleted file mode 100644 index 3afc9131..00000000 --- a/extension/scripts/index.py +++ /dev/null @@ -1,52 +0,0 @@ -import sys -import os -from typing import TextIO -from chroma import update_collection, query_collection, create_collection, collection_exists, get_current_branch -from typer import Typer - -app = Typer() - -class SilenceStdoutContextManager: - saved_stdout: TextIO - - def __enter__(self): - self._original_stdout = sys.stdout - sys.stdout = open(os.devnull, 'w') - - def __exit__(self, exc_type, exc_val, exc_tb): - sys.stdout.close() - sys.stdout = self._original_stdout - -silence = SilenceStdoutContextManager() - -@app.command("exists") -def exists(cwd: str): - with silence: - exists = collection_exists(cwd) - print({"exists": exists}) - -@app.command("create") -def create(cwd: str): - with silence: - branch = get_current_branch(cwd) - create_collection(branch, cwd) - print({"success": True}) - -@app.command("update") -def update(cwd: str): - with silence: - update_collection(cwd) - print({"success": True}) - -@app.command("query") -def query(query: str, n_results: int, cwd: str): - with silence: - resp = query_collection(query, n_results, cwd) - results = [{ - "id": resp["ids"][0][i], - "document": resp["documents"][0][i] - } for i in range(len(resp["ids"][0]))] - print({"results": results}) - -if __name__ == "__main__": - app() \ No newline at end of file diff --git a/extension/scripts/query.py b/extension/scripts/query.py deleted file mode 100644 index f2e44413..00000000 --- a/extension/scripts/query.py +++ /dev/null @@ -1,63 +0,0 @@ -import subprocess -import sys -from gpt_index import GPTSimpleVectorIndex, GPTFaissIndex -import os -from typer import Typer -from enum import Enum -from update import update_codebase_index, create_codebase_index, index_dir_for, get_current_branch -from replace import replace_additional_index - -app = Typer() - -def query_codebase_index(query: str) -> str: - """Query the codebase index.""" - branch = subprocess.check_output(["git", "rev-parse", "--abbrev-ref", "HEAD"]).decode("utf-8").strip() - path = 'data/{branch}/index.json' - if not os.path.exists(path): - print("No index found for the codebase") - return "" - index = GPTFaissIndex.load_from_disk(path) - return index.query(query) - -def query_additional_index(query: str) -> str: - """Query the additional index.""" - index = GPTSimpleVectorIndex.load_from_disk('data/additional_index.json') - return index.query(query) - -class IndexTypeOption(str, Enum): - codebase = "codebase" - additional = "additional" - -@app.command() -def query(context: IndexTypeOption, query: str): - if context == IndexTypeOption.additional: - response = query_additional_index(query) - elif context == IndexTypeOption.codebase: - response = query_codebase_index(query) - else: - print("Error: unknown context") - print({ "response": response }) - -@app.command() -def check_index_exists(root_path: str): - branch = get_current_branch() - exists = os.path.exists(index_dir_for(branch)) - print({ "exists": exists }) - -@app.command() -def update(): - update_codebase_index() - print("Updated codebase index") - -@app.command() -def create_index(path: str): - create_codebase_index() - print("Created file index") - -@app.command() -def replace_additional_index(info: str): - replace_additional_index() - print("Replaced additional index") - -if __name__ == '__main__': - app() \ No newline at end of file diff --git a/extension/scripts/replace.py b/extension/scripts/replace.py deleted file mode 100644 index 08810243..00000000 --- a/extension/scripts/replace.py +++ /dev/null @@ -1,17 +0,0 @@ -import sys -from gpt_index import GPTSimpleVectorIndex, Document - -def replace_additional_index(info: str): - """Replace the additional index.""" - with open('data/additional_context.txt', 'w') as f: - f.write(info) - documents = [Document(info)] - index = GPTSimpleVectorIndex(documents) - index.save_to_disk('data/additional_index.json') - print("Additional index replaced") - -if __name__ == "__main__": - """python3 replace.py """ - info = sys.argv[1] if len(sys.argv) > 1 else None - if info: - replace_additional_index(info) \ No newline at end of file diff --git a/extension/scripts/requirements.txt b/extension/scripts/requirements.txt deleted file mode 100644 index c51c9d73..00000000 --- a/extension/scripts/requirements.txt +++ /dev/null @@ -1,6 +0,0 @@ -# chromadb==0.3.10 -# pathspec==0.11.0 -# typer==0.7.0 -# pydantic -# pytest -./continuedev-0.1.2-py3-none-any.whl \ No newline at end of file diff --git a/extension/scripts/run_continue_server.py b/extension/scripts/run_continue_server.py deleted file mode 100644 index 089cc54d..00000000 --- a/extension/scripts/run_continue_server.py +++ /dev/null @@ -1,4 +0,0 @@ -from continuedev.server.main import run_server - -if __name__ == "__main__": - run_server() diff --git a/extension/scripts/update.py b/extension/scripts/update.py deleted file mode 100644 index 15ad6ac0..00000000 --- a/extension/scripts/update.py +++ /dev/null @@ -1,185 +0,0 @@ -# import faiss -import json -import os -import subprocess - -from gpt_index.langchain_helpers.text_splitter import TokenTextSplitter -from gpt_index import GPTSimpleVectorIndex, SimpleDirectoryReader, Document, GPTFaissIndex -from typing import List, Generator, Tuple - -FILE_TYPES_TO_IGNORE = [ - '.pyc', - '.png', - '.jpg', - '.jpeg', - '.gif', - '.svg', - '.ico' -] - -def further_filter(files: List[str], root_dir: str): - """Further filter files before indexing.""" - for file in files: - if file.endswith(tuple(FILE_TYPES_TO_IGNORE)) or file.startswith('.git') or file.startswith('archive'): - continue - yield root_dir + "/" + file - -def get_git_root_dir(path: str): - """Get the root directory of a Git repository.""" - try: - return subprocess.check_output(['git', 'rev-parse', '--show-toplevel'], cwd=path).strip().decode() - except subprocess.CalledProcessError: - return None - -def get_git_ignored_files(root_dir: str): - """Get the list of ignored files in a Git repository.""" - try: - output = subprocess.check_output(['git', 'ls-files', '--ignored', '--others', '--exclude-standard'], cwd=root_dir).strip().decode() - return output.split('\n') - except subprocess.CalledProcessError: - return [] - -def get_all_files(root_dir: str): - """Get a list of all files in a directory.""" - for dir_path, _, file_names in os.walk(root_dir): - for file_name in file_names: - yield os.path.join(os.path.relpath(dir_path, root_dir), file_name) - -def get_input_files(root_dir: str): - """Get a list of all files in a Git repository that are not ignored.""" - ignored_files = set(get_git_ignored_files(root_dir)) - all_files = set(get_all_files(root_dir)) - nonignored_files = all_files - ignored_files - return further_filter(nonignored_files, root_dir) - -def load_gpt_index_documents(root: str) -> List[Document]: - """Loads a list of GPTIndex Documents, respecting .gitignore files.""" - # Get input files - input_files = get_input_files(root) - # Use SimpleDirectoryReader to load the files into Documents - return SimpleDirectoryReader(root, input_files=input_files, file_metadata=lambda filename: {"filename": filename}).load_data() - -def index_dir_for(branch: str) -> str: - return f"data/{branch}" - -def get_git_root_dir(): - result = subprocess.run(['git', 'rev-parse', '--show-toplevel'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) - return result.stdout.decode().strip() - -def get_current_branch() -> str: - return subprocess.check_output(["git", "rev-parse", "--abbrev-ref", "HEAD"]).decode("utf-8").strip() - -def get_current_commit() -> str: - return subprocess.check_output(["git", "rev-parse", "HEAD"]).decode("utf-8").strip() - -def create_codebase_index(): - """Create a new index for the current branch.""" - branch = get_current_branch() - if not os.path.exists(index_dir_for(branch)): - os.makedirs(index_dir_for(branch)) - - documents = load_gpt_index_documents(get_git_root_dir()) - - chunks = {} - doc_chunks = [] - for doc in documents: - text_splitter = TokenTextSplitter() - text_chunks = text_splitter.split_text(doc.text) - filename = doc.extra_info["filename"] - chunks[filename] = len(text_chunks) - for i, text in enumerate(text_chunks): - doc_chunks.append(Document(text, doc_id=f"{filename}::{i}")) - - with open(f"{index_dir_for(branch)}/metadata.json", "w") as f: - json.dump({"commit": get_current_commit(), "chunks" : chunks}, f, indent=4) - - index = GPTSimpleVectorIndex([]) - for chunk in doc_chunks: - index.insert(chunk) - - # d = 1536 # Dimension of text-ada-embedding-002 - # faiss_index = faiss.IndexFlatL2(d) - # index = GPTFaissIndex(documents, faiss_index=faiss_index) - # index.save_to_disk(f"{index_dir_for(branch)}/index.json", faiss_index_save_path=f"{index_dir_for(branch)}/index_faiss_core.index") - - index.save_to_disk(f"{index_dir_for(branch)}/index.json") - - print("Codebase index created") - -def get_modified_deleted_files() -> Tuple[List[str], List[str]]: - """Get a list of all files that have been modified since the last commit.""" - branch = get_current_branch() - current_commit = get_current_commit() - - metadata = f"{index_dir_for(branch)}/metadata.json" - with open(metadata, "r") as f: - previous_commit = json.load(f)["commit"] - - modified_deleted_files = subprocess.check_output(["git", "diff", "--name-only", previous_commit, current_commit]).decode("utf-8").strip() - modified_deleted_files = modified_deleted_files.split("\n") - modified_deleted_files = [f for f in modified_deleted_files if f] - - root = get_git_root_dir() - deleted_files = [f for f in modified_deleted_files if not os.path.exists(root + "/" + f)] - modified_files = [f for f in modified_deleted_files if os.path.exists(root + "/" + f)] - - return further_filter(modified_files, index_dir_for(branch)), further_filter(deleted_files, index_dir_for(branch)) - -def update_codebase_index(): - """Update the index with a list of files.""" - branch = get_current_branch() - - if not os.path.exists(index_dir_for(branch)): - create_codebase_index() - else: - # index = GPTFaissIndex.load_from_disk(f"{index_dir_for(branch)}/index.json", faiss_index_save_path=f"{index_dir_for(branch)}/index_faiss_core.index") - index = GPTSimpleVectorIndex.load_from_disk(f"{index_dir_for(branch)}/index.json") - modified_files, deleted_files = get_modified_deleted_files() - - with open(f"{index_dir_for(branch)}/metadata.json", "r") as f: - metadata = json.load(f) - - for file in deleted_files: - - num_chunks = metadata["chunks"][file] - for i in range(num_chunks): - index.delete(f"{file}::{i}") - - del metadata["chunks"][file] - - print(f"Deleted {file}") - - for file in modified_files: - - if file in metadata["chunks"]: - - num_chunks = metadata["chunks"][file] - - for i in range(num_chunks): - index.delete(f"{file}::{i}") - - print(f"Deleted old version of {file}") - - with open(file, "r") as f: - text = f.read() - - text_splitter = TokenTextSplitter() - text_chunks = text_splitter.split_text(text) - - for i, text in enumerate(text_chunks): - index.insert(Document(text, doc_id=f"{file}::{i}")) - - metadata["chunks"][file] = len(text_chunks) - - print(f"Inserted new version of {file}") - - metadata["commit"] = get_current_commit() - - with open(f"{index_dir_for(branch)}/metadata.json", "w") as f: - json.dump(metadata, f, indent=4) - - print("Codebase index updated") - -if __name__ == "__main__": - """python3 update.py""" - update_codebase_index() \ No newline at end of file diff --git a/extension/server/.gitignore b/extension/server/.gitignore new file mode 100644 index 00000000..0b6e11dd --- /dev/null +++ b/extension/server/.gitignore @@ -0,0 +1 @@ +**.whl \ No newline at end of file diff --git a/extension/server/README.md b/extension/server/README.md new file mode 100644 index 00000000..56208b5a --- /dev/null +++ b/extension/server/README.md @@ -0,0 +1,3 @@ +# server + +These are the files that get copied over to `~/.continue/server` in order to create the Python environment and start the Continue server. diff --git a/extension/server/requirements.txt b/extension/server/requirements.txt new file mode 100644 index 00000000..eb1f3738 --- /dev/null +++ b/extension/server/requirements.txt @@ -0,0 +1 @@ +./continuedev-0.1.2-py3-none-any.whl \ No newline at end of file diff --git a/extension/server/run_continue_server.py b/extension/server/run_continue_server.py new file mode 100644 index 00000000..089cc54d --- /dev/null +++ b/extension/server/run_continue_server.py @@ -0,0 +1,4 @@ +from continuedev.server.main import run_server + +if __name__ == "__main__": + run_server() diff --git a/extension/src/activation/environmentSetup.ts b/extension/src/activation/environmentSetup.ts index 714080e3..02118501 100644 --- a/extension/src/activation/environmentSetup.ts +++ b/extension/src/activation/environmentSetup.ts @@ -7,6 +7,7 @@ import * as fs from "fs"; import { getContinueServerUrl } from "../bridge"; import fetch from "node-fetch"; import * as vscode from "vscode"; +import * as os from "os"; import fkill from "fkill"; import { sendTelemetryEvent, TelemetryEvent } from "../telemetry"; @@ -127,8 +128,7 @@ function getActivateUpgradeCommands(pythonCmd: string, pipCmd: string) { function checkEnvExists() { const envBinPath = path.join( - getExtensionUri().fsPath, - "scripts", + serverPath(), "env", process.platform == "win32" ? "Scripts" : "bin" ); @@ -140,10 +140,32 @@ function checkEnvExists() { ); } -function checkRequirementsInstalled() { +async function checkRequirementsInstalled() { + // First, check if the requirements have been installed most recently for a later version of the extension + if (fs.existsSync(requirementsVersionPath())) { + const requirementsVersion = fs.readFileSync( + requirementsVersionPath(), + "utf8" + ); + if (requirementsVersion !== getExtensionVersion()) { + // Remove the old version of continuedev from site-packages + const [pythonCmd, pipCmd] = await getPythonPipCommands(); + const [activateCmd] = getActivateUpgradeCommands(pythonCmd, pipCmd); + const removeOldVersionCommand = [ + `cd "${serverPath()}"`, + activateCmd, + `${pipCmd} uninstall -y continuedev`, + ].join(" ; "); + const [, stderr] = await runCommand(removeOldVersionCommand); + if (stderr) { + throw new Error(stderr); + } + return false; + } + } + let envLibsPath = path.join( - getExtensionUri().fsPath, - "scripts", + serverPath(), "env", process.platform == "win32" ? "Lib" : "lib" ); @@ -165,10 +187,6 @@ function checkRequirementsInstalled() { const continuePath = path.join(envLibsPath, "continuedev"); return fs.existsSync(continuePath); - - // return fs.existsSync( - // path.join(getExtensionUri().fsPath, "scripts", ".continue_env_installed") - // ); } async function setupPythonEnv() { @@ -180,12 +198,13 @@ async function setupPythonEnv() { pipCmd ); + // First, create the virtual environment if (checkEnvExists()) { console.log("Python env already exists, skipping..."); } else { // Assemble the command to create the env const createEnvCommand = [ - `cd "${path.join(getExtensionUri().fsPath, "scripts")}"`, + `cd "${serverPath()}"`, `${pythonCmd} -m venv env`, ].join(" ; "); @@ -216,10 +235,7 @@ async function setupPythonEnv() { console.log(msg); await vscode.window.showErrorMessage(msg); } else if (checkEnvExists()) { - console.log( - "Successfully set up python env at ", - getExtensionUri().fsPath + "/scripts/env" - ); + console.log("Successfully set up python env at ", `${serverPath()}/env`); } else { const msg = [ "Python environment not successfully created. Trying again. Here was the stdout + stderr: ", @@ -231,12 +247,13 @@ async function setupPythonEnv() { } } + // Install the requirements await retryThenFail(async () => { - if (checkRequirementsInstalled()) { + if (await checkRequirementsInstalled()) { console.log("Python requirements already installed, skipping..."); } else { const installRequirementsCommand = [ - `cd "${path.join(getExtensionUri().fsPath, "scripts")}"`, + `cd "${serverPath()}"`, activateCmd, pipUpgradeCmd, `${pipCmd} install -r requirements.txt`, @@ -245,6 +262,8 @@ async function setupPythonEnv() { if (stderr) { throw new Error(stderr); } + // Write the version number for which requirements were installed + fs.writeFileSync(requirementsVersionPath(), getExtensionVersion()); } }); } @@ -297,9 +316,39 @@ async function checkServerRunning(serverUrl: string): Promise { } } +export function getContinueGlobalPath(): string { + // This is ~/.continue on mac/linux + const continuePath = path.join(os.homedir(), ".continue"); + if (!fs.existsSync(continuePath)) { + fs.mkdirSync(continuePath); + } + return continuePath; +} + +function setupServerPath() { + const sPath = serverPath(); + const extensionServerPath = path.join(getExtensionUri().fsPath, "server"); + const files = fs.readdirSync(extensionServerPath); + files.forEach((file) => { + const filePath = path.join(extensionServerPath, file); + fs.copyFileSync(filePath, path.join(sPath, file)); + }); +} + +function serverPath(): string { + const sPath = path.join(getContinueGlobalPath(), "server"); + if (!fs.existsSync(sPath)) { + fs.mkdirSync(sPath); + } + return sPath; +} + function serverVersionPath(): string { - const extensionPath = getExtensionUri().fsPath; - return path.join(extensionPath, "server_version.txt"); + return path.join(serverPath(), "server_version.txt"); +} + +function requirementsVersionPath(): string { + return path.join(serverPath(), "requirements_version.txt"); } function getExtensionVersion() { @@ -314,6 +363,8 @@ export async function startContinuePythonServer() { return; } + setupServerPath(); + return await retryThenFail(async () => { if (await checkServerRunning(serverUrl)) { // Kill the server if it is running an old version @@ -337,16 +388,14 @@ export async function startContinuePythonServer() { // Do this after above check so we don't have to waste time setting up the env await setupPythonEnv(); + // Spawn the server process on port 65432 const [pythonCmd] = await getPythonPipCommands(); const activateCmd = process.platform == "win32" ? ".\\env\\Scripts\\activate" : ". env/bin/activate"; - const command = `cd "${path.join( - getExtensionUri().fsPath, - "scripts" - )}" && ${activateCmd} && cd .. && ${pythonCmd} -m scripts.run_continue_server`; + const command = `cd "${serverPath()}" && ${activateCmd} && cd .. && ${pythonCmd} -m server.run_continue_server`; console.log("Starting Continue python server..."); @@ -392,8 +441,8 @@ export async function startContinuePythonServer() { } export function isPythonEnvSetup(): boolean { - let pathToEnvCfg = getExtensionUri().fsPath + "/scripts/env/pyvenv.cfg"; - return fs.existsSync(path.join(pathToEnvCfg)); + const pathToEnvCfg = path.join(serverPath(), "env", "pyvenv.cfg"); + return fs.existsSync(pathToEnvCfg); } export async function downloadPython3() { -- cgit v1.2.3-70-g09d2 From 84910d445f44f8de1f160ff81e06c4eaf9c17ee7 Mon Sep 17 00:00:00 2001 From: Nate Sesti Date: Tue, 11 Jul 2023 11:48:43 -0700 Subject: air on the side of killing server --- extension/package-lock.json | 4 ++-- extension/package.json | 2 +- extension/src/activation/environmentSetup.ts | 34 +++++++++++++++------------- 3 files changed, 21 insertions(+), 19 deletions(-) (limited to 'extension/src/activation/environmentSetup.ts') diff --git a/extension/package-lock.json b/extension/package-lock.json index 71f4d974..d778b097 100644 --- a/extension/package-lock.json +++ b/extension/package-lock.json @@ -1,12 +1,12 @@ { "name": "continue", - "version": "0.0.147", + "version": "0.0.149", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "continue", - "version": "0.0.147", + "version": "0.0.149", "license": "Apache-2.0", "dependencies": { "@electron/rebuild": "^3.2.10", diff --git a/extension/package.json b/extension/package.json index d9f155df..56c49f27 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.147", + "version": "0.0.149", "publisher": "Continue", "engines": { "vscode": "^1.67.0" diff --git a/extension/src/activation/environmentSetup.ts b/extension/src/activation/environmentSetup.ts index 02118501..ff8d3158 100644 --- a/extension/src/activation/environmentSetup.ts +++ b/extension/src/activation/environmentSetup.ts @@ -366,24 +366,26 @@ export async function startContinuePythonServer() { setupServerPath(); return await retryThenFail(async () => { - if (await checkServerRunning(serverUrl)) { - // Kill the server if it is running an old version - if (fs.existsSync(serverVersionPath())) { - const serverVersion = fs.readFileSync(serverVersionPath(), "utf8"); - if (serverVersion === getExtensionVersion()) { - return; - } - } - console.log("Killing old server..."); - try { - await fkill(":65432"); - } catch (e) { - console.log( - "Failed to kill old server, likely because it didn't exist:", - e - ); + // Kill the server if it is running an old version + if (fs.existsSync(serverVersionPath())) { + const serverVersion = fs.readFileSync(serverVersionPath(), "utf8"); + if ( + serverVersion === getExtensionVersion() && + (await checkServerRunning(serverUrl)) + ) { + // The current version is already up and running, no need to continue + return; } } + console.log("Killing old server..."); + try { + await fkill(":65432"); + } catch (e) { + console.log( + "Failed to kill old server, likely because it didn't exist:", + e + ); + } // Do this after above check so we don't have to waste time setting up the env await setupPythonEnv(); -- cgit v1.2.3-70-g09d2 From a3e0a8432c096de463378756a82979f5d327b3a3 Mon Sep 17 00:00:00 2001 From: Nate Sesti Date: Tue, 11 Jul 2023 12:15:35 -0700 Subject: don't override error messages with a second one --- extension/src/activation/environmentSetup.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'extension/src/activation/environmentSetup.ts') diff --git a/extension/src/activation/environmentSetup.ts b/extension/src/activation/environmentSetup.ts index ff8d3158..f5d825c9 100644 --- a/extension/src/activation/environmentSetup.ts +++ b/extension/src/activation/environmentSetup.ts @@ -22,7 +22,7 @@ async function retryThenFail( if (retries > 0) { return await retryThenFail(fn, retries - 1); } - vscode.window.showErrorMessage( + vscode.window.showInformationMessage( "Failed to set up Continue extension. Please email nate@continue.dev and we'll get this fixed ASAP!" ); sendTelemetryEvent(TelemetryEvent.ExtensionSetupError, { -- cgit v1.2.3-70-g09d2 From f515c9179b27885a024c197f8dead0c2e311aa8e Mon Sep 17 00:00:00 2001 From: Nate Sesti Date: Tue, 11 Jul 2023 12:33:02 -0700 Subject: patch --- extension/package-lock.json | 4 ++-- extension/package.json | 2 +- extension/src/activation/environmentSetup.ts | 3 +++ 3 files changed, 6 insertions(+), 3 deletions(-) (limited to 'extension/src/activation/environmentSetup.ts') diff --git a/extension/package-lock.json b/extension/package-lock.json index d778b097..c43851a2 100644 --- a/extension/package-lock.json +++ b/extension/package-lock.json @@ -1,12 +1,12 @@ { "name": "continue", - "version": "0.0.149", + "version": "0.0.150", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "continue", - "version": "0.0.149", + "version": "0.0.150", "license": "Apache-2.0", "dependencies": { "@electron/rebuild": "^3.2.10", diff --git a/extension/package.json b/extension/package.json index 56c49f27..e2fe6e8e 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.149", + "version": "0.0.150", "publisher": "Continue", "engines": { "vscode": "^1.67.0" diff --git a/extension/src/activation/environmentSetup.ts b/extension/src/activation/environmentSetup.ts index f5d825c9..8b384e1d 100644 --- a/extension/src/activation/environmentSetup.ts +++ b/extension/src/activation/environmentSetup.ts @@ -224,6 +224,9 @@ async function setupPythonEnv() { // First, try to run the command to install python3-venv let [stdout, stderr] = await runCommand(`${pythonCmd} --version`); if (stderr) { + await vscode.window.showErrorMessage( + "Python3 is not installed. Please install from https://www.python.org/downloads, reload VS Code, and try again." + ); throw new Error(stderr); } const version = stdout.split(" ")[1].split(".")[1]; -- cgit v1.2.3-70-g09d2 From ea76462f971d6d235baacbb85d6e9ae6fe09d7e0 Mon Sep 17 00:00:00 2001 From: Nate Sesti Date: Tue, 11 Jul 2023 12:43:15 -0700 Subject: fix bug uninstalling continuedev --- extension/package-lock.json | 4 ++-- extension/package.json | 2 +- extension/src/activation/environmentSetup.ts | 5 +---- 3 files changed, 4 insertions(+), 7 deletions(-) (limited to 'extension/src/activation/environmentSetup.ts') diff --git a/extension/package-lock.json b/extension/package-lock.json index c43851a2..b6147b2c 100644 --- a/extension/package-lock.json +++ b/extension/package-lock.json @@ -1,12 +1,12 @@ { "name": "continue", - "version": "0.0.150", + "version": "0.0.151", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "continue", - "version": "0.0.150", + "version": "0.0.151", "license": "Apache-2.0", "dependencies": { "@electron/rebuild": "^3.2.10", diff --git a/extension/package.json b/extension/package.json index e2fe6e8e..a57f6065 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.150", + "version": "0.0.151", "publisher": "Continue", "engines": { "vscode": "^1.67.0" diff --git a/extension/src/activation/environmentSetup.ts b/extension/src/activation/environmentSetup.ts index 8b384e1d..881da9b5 100644 --- a/extension/src/activation/environmentSetup.ts +++ b/extension/src/activation/environmentSetup.ts @@ -156,10 +156,7 @@ async function checkRequirementsInstalled() { activateCmd, `${pipCmd} uninstall -y continuedev`, ].join(" ; "); - const [, stderr] = await runCommand(removeOldVersionCommand); - if (stderr) { - throw new Error(stderr); - } + await runCommand(removeOldVersionCommand); return false; } } -- cgit v1.2.3-70-g09d2 From 9846f4769ff33a346d76e26ad730d19770fe7e02 Mon Sep 17 00:00:00 2001 From: Nate Sesti Date: Tue, 11 Jul 2023 15:14:03 -0700 Subject: check for old version of Continue, notify --- extension/src/activation/activate.ts | 22 +++++++++++++++++++++- extension/src/activation/environmentSetup.ts | 2 +- 2 files changed, 22 insertions(+), 2 deletions(-) (limited to 'extension/src/activation/environmentSetup.ts') diff --git a/extension/src/activation/activate.ts b/extension/src/activation/activate.ts index 18650561..2c5ba58c 100644 --- a/extension/src/activation/activate.ts +++ b/extension/src/activation/activate.ts @@ -7,9 +7,16 @@ import IdeProtocolClient from "../continueIdeClient"; import { getContinueServerUrl } from "../bridge"; import { CapturedTerminal } from "../terminal/terminalEmulator"; import { setupDebugPanel, ContinueGUIWebviewViewProvider } from "../debugPanel"; -import { startContinuePythonServer } from "./environmentSetup"; +import { + getExtensionVersion, + startContinuePythonServer, +} from "./environmentSetup"; +import fetch from "node-fetch"; // import { CapturedTerminal } from "../terminal/terminalEmulator"; +const PACKAGE_JSON_RAW_GITHUB_URL = + "https://raw.githubusercontent.com/continuedev/continue/main/extension/package.json"; + export let extensionContext: vscode.ExtensionContext | undefined = undefined; export let ideProtocolClient: IdeProtocolClient; @@ -20,6 +27,19 @@ export async function activateExtension( ) { extensionContext = context; + // Before anything else, check whether this is an out-of-date version of the extension + // Do so by grabbing the package.json off of the GitHub respository for now. + fetch(PACKAGE_JSON_RAW_GITHUB_URL) + .then(async (res) => res.json()) + .then((packageJson) => { + if (packageJson.version !== getExtensionVersion()) { + vscode.window.showInformationMessage( + `You are using an out-of-date version of the Continue extension. Please update to the latest version.` + ); + } + }) + .catch((e) => console.log("Error checking for extension updates: ", e)); + await new Promise((resolve, reject) => { vscode.window.withProgress( { diff --git a/extension/src/activation/environmentSetup.ts b/extension/src/activation/environmentSetup.ts index 881da9b5..c277a539 100644 --- a/extension/src/activation/environmentSetup.ts +++ b/extension/src/activation/environmentSetup.ts @@ -351,7 +351,7 @@ function requirementsVersionPath(): string { return path.join(serverPath(), "requirements_version.txt"); } -function getExtensionVersion() { +export function getExtensionVersion() { const extension = vscode.extensions.getExtension("continue.continue"); return extension?.packageJSON.version || ""; } -- cgit v1.2.3-70-g09d2 From 51f620524cd8d658058b4a07d8e8f8e1b3be49bd Mon Sep 17 00:00:00 2001 From: Nate Sesti Date: Wed, 12 Jul 2023 12:43:42 -0700 Subject: remove eventemitter from codelens classes --- extension/src/activation/activate.ts | 5 +--- extension/src/activation/environmentSetup.ts | 9 ++++--- extension/src/extension.ts | 9 +++---- extension/src/lang-server/codeLens.ts | 36 ++-------------------------- 4 files changed, 10 insertions(+), 49 deletions(-) (limited to 'extension/src/activation/environmentSetup.ts') diff --git a/extension/src/activation/activate.ts b/extension/src/activation/activate.ts index c46d6362..fe72eaf6 100644 --- a/extension/src/activation/activate.ts +++ b/extension/src/activation/activate.ts @@ -21,10 +21,7 @@ export let extensionContext: vscode.ExtensionContext | undefined = undefined; export let ideProtocolClient: IdeProtocolClient; -export async function activateExtension( - context: vscode.ExtensionContext, - showTutorial: boolean -) { +export async function activateExtension(context: vscode.ExtensionContext) { extensionContext = context; // Before anything else, check whether this is an out-of-date version of the extension diff --git a/extension/src/activation/environmentSetup.ts b/extension/src/activation/environmentSetup.ts index c277a539..7bd08929 100644 --- a/extension/src/activation/environmentSetup.ts +++ b/extension/src/activation/environmentSetup.ts @@ -380,11 +380,10 @@ export async function startContinuePythonServer() { console.log("Killing old server..."); try { await fkill(":65432"); - } catch (e) { - console.log( - "Failed to kill old server, likely because it didn't exist:", - e - ); + } catch (e: any) { + if (!e.message.includes("Process doesn't exist")) { + console.log("Failed to kill old server:", e); + } } // Do this after above check so we don't have to waste time setting up the env diff --git a/extension/src/extension.ts b/extension/src/extension.ts index de8f55e3..1f9f7914 100644 --- a/extension/src/extension.ts +++ b/extension/src/extension.ts @@ -8,12 +8,9 @@ import { startContinuePythonServer, } from "./activation/environmentSetup"; -async function dynamicImportAndActivate( - context: vscode.ExtensionContext, - showTutorial: boolean -) { +async function dynamicImportAndActivate(context: vscode.ExtensionContext) { const { activateExtension } = await import("./activation/activate"); - await activateExtension(context, showTutorial); + await activateExtension(context); } export function activate(context: vscode.ExtensionContext) { @@ -25,7 +22,7 @@ export function activate(context: vscode.ExtensionContext) { cancellable: false, }, async () => { - dynamicImportAndActivate(context, true); + dynamicImportAndActivate(context); } ); } diff --git a/extension/src/lang-server/codeLens.ts b/extension/src/lang-server/codeLens.ts index 79126eaa..778b98dc 100644 --- a/extension/src/lang-server/codeLens.ts +++ b/extension/src/lang-server/codeLens.ts @@ -6,7 +6,7 @@ import { DIFF_DIRECTORY } from "../diffs"; class SuggestionsCodeLensProvider implements vscode.CodeLensProvider { public provideCodeLenses( document: vscode.TextDocument, - token: vscode.CancellationToken + _: vscode.CancellationToken ): vscode.CodeLens[] | Thenable { const suggestions = editorToSuggestions.get(document.uri.toString()); if (!suggestions) { @@ -44,28 +44,12 @@ class SuggestionsCodeLensProvider implements vscode.CodeLensProvider { return codeLenses; } - - onDidChangeCodeLenses?: vscode.Event | undefined; - - constructor(emitter?: vscode.EventEmitter) { - if (emitter) { - this.onDidChangeCodeLenses = emitter.event; - this.onDidChangeCodeLenses(() => { - if (vscode.window.activeTextEditor) { - this.provideCodeLenses( - vscode.window.activeTextEditor.document, - new vscode.CancellationTokenSource().token - ); - } - }); - } - } } class DiffViewerCodeLensProvider implements vscode.CodeLensProvider { public provideCodeLenses( document: vscode.TextDocument, - token: vscode.CancellationToken + _: vscode.CancellationToken ): vscode.CodeLens[] | Thenable { if (path.dirname(document.uri.fsPath) === DIFF_DIRECTORY) { const codeLenses: vscode.CodeLens[] = []; @@ -87,22 +71,6 @@ class DiffViewerCodeLensProvider implements vscode.CodeLensProvider { return []; } } - - onDidChangeCodeLenses?: vscode.Event | undefined; - - constructor(emitter?: vscode.EventEmitter) { - if (emitter) { - this.onDidChangeCodeLenses = emitter.event; - this.onDidChangeCodeLenses(() => { - if (vscode.window.activeTextEditor) { - this.provideCodeLenses( - vscode.window.activeTextEditor.document, - new vscode.CancellationTokenSource().token - ); - } - }); - } - } } let diffsCodeLensDisposable: vscode.Disposable | undefined = undefined; -- cgit v1.2.3-70-g09d2 From f6229ad2ab4f5587b2f48f2ec098aa109be9ebf3 Mon Sep 17 00:00:00 2001 From: sestinj Date: Sat, 15 Jul 2023 16:25:51 -0700 Subject: Reliably show error messages when environmentSetup fails --- extension/src/activation/environmentSetup.ts | 59 +++++++++++++++++++--------- extension/src/diffs.ts | 5 +++ 2 files changed, 46 insertions(+), 18 deletions(-) (limited to 'extension/src/activation/environmentSetup.ts') diff --git a/extension/src/activation/environmentSetup.ts b/extension/src/activation/environmentSetup.ts index 7bd08929..374c38c0 100644 --- a/extension/src/activation/environmentSetup.ts +++ b/extension/src/activation/environmentSetup.ts @@ -11,6 +11,8 @@ import * as os from "os"; import fkill from "fkill"; import { sendTelemetryEvent, TelemetryEvent } from "../telemetry"; +const WINDOWS_REMOTE_SIGNED_SCRIPTS_ERROR = "A Python virtual enviroment cannot be activated because running scripts is disabled for this user. Please enable signed scripts to run with this command in PowerShell: `Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser`, reload VS Code, and then try again."; + const MAX_RETRIES = 3; async function retryThenFail( fn: () => Promise, @@ -22,9 +24,25 @@ async function retryThenFail( if (retries > 0) { return await retryThenFail(fn, retries - 1); } - vscode.window.showInformationMessage( - "Failed to set up Continue extension. Please email nate@continue.dev and we'll get this fixed ASAP!" - ); + + // Show corresponding error message depending on the platform + let msg = "Failed to set up Continue extension. Please email nate@continue.dev and we'll get this fixed ASAP!"; + try { + switch (process.platform) { + case "win32": + msg = WINDOWS_REMOTE_SIGNED_SCRIPTS_ERROR; + break; + case "darwin": + break; + case "linux": + const [pythonCmd,] = await getPythonPipCommands(); + msg = await getLinuxAptInstallError(pythonCmd); + break; + } + } finally { + vscode.window.showErrorMessage(msg); + } + sendTelemetryEvent(TelemetryEvent.ExtensionSetupError, { error: e.message, }); @@ -186,6 +204,24 @@ async function checkRequirementsInstalled() { return fs.existsSync(continuePath); } +async function getLinuxAptInstallError(pythonCmd: string) { + // First, try to run the command to install python3-venv + let [stdout, stderr] = await runCommand(`${pythonCmd} --version`); + if (stderr) { + await vscode.window.showErrorMessage( + "Python3 is not installed. Please install from https://www.python.org/downloads, reload VS Code, and try again." + ); + throw new Error(stderr); + } + const version = stdout.split(" ")[1].split(".")[1]; + const installVenvCommand = `apt-get install python3.${version}-venv`; + await runCommand("apt-get update"); + // Ask the user to run the command to install python3-venv (requires sudo, so we can't) + // First, get the python version + const msg = `[Important] Continue needs to create a Python virtual environment, but python3.${version}-venv is not installed. Please run this command in your terminal: \`${installVenvCommand}\`, reload VS Code, and then try again.`; + return msg; +} + async function setupPythonEnv() { console.log("Setting up python env for Continue extension..."); @@ -211,27 +247,14 @@ async function setupPythonEnv() { stderr.includes("running scripts is disabled on this system") ) { await vscode.window.showErrorMessage( - "A Python virtual enviroment cannot be activated because running scripts is disabled for this user. Please enable signed scripts to run with this command in PowerShell: `Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser`, reload VS Code, and then try again." + WINDOWS_REMOTE_SIGNED_SCRIPTS_ERROR ); throw new Error(stderr); } else if ( stderr?.includes("On Debian/Ubuntu systems") || stdout?.includes("On Debian/Ubuntu systems") ) { - // First, try to run the command to install python3-venv - let [stdout, stderr] = await runCommand(`${pythonCmd} --version`); - if (stderr) { - await vscode.window.showErrorMessage( - "Python3 is not installed. Please install from https://www.python.org/downloads, reload VS Code, and try again." - ); - throw new Error(stderr); - } - const version = stdout.split(" ")[1].split(".")[1]; - const installVenvCommand = `apt-get install python3.${version}-venv`; - await runCommand("apt-get update"); - // Ask the user to run the command to install python3-venv (requires sudo, so we can't) - // First, get the python version - const msg = `[Important] Continue needs to create a Python virtual environment, but python3.${version}-venv is not installed. Please run this command in your terminal: \`${installVenvCommand}\`, reload VS Code, and then try again.`; + const msg = await getLinuxAptInstallError(pythonCmd); console.log(msg); await vscode.window.showErrorMessage(msg); } else if (checkEnvExists()) { diff --git a/extension/src/diffs.ts b/extension/src/diffs.ts index 19004dfb..2860258d 100644 --- a/extension/src/diffs.ts +++ b/extension/src/diffs.ts @@ -149,6 +149,11 @@ class DiffManager { this.diffs.set(newFilepath, diffInfo); } + vscode.commands.executeCommand( + "workbench.action.files.revert", + vscode.Uri.file(newFilepath) + ); + return newFilepath; } -- cgit v1.2.3-70-g09d2 From 3a39b979c55b005d9bb18b88b43ca7293ee5410d Mon Sep 17 00:00:00 2001 From: Nate Sesti Date: Sat, 15 Jul 2023 16:32:56 -0700 Subject: patch --- extension/package-lock.json | 4 ++-- extension/package.json | 2 +- extension/react-app/src/components/TextDialog.tsx | 1 + extension/react-app/src/pages/gui.tsx | 1 + extension/src/activation/environmentSetup.ts | 19 ++++++++----------- 5 files changed, 13 insertions(+), 14 deletions(-) (limited to 'extension/src/activation/environmentSetup.ts') diff --git a/extension/package-lock.json b/extension/package-lock.json index 0edd4885..e77bfac2 100644 --- a/extension/package-lock.json +++ b/extension/package-lock.json @@ -1,12 +1,12 @@ { "name": "continue", - "version": "0.0.166", + "version": "0.0.167", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "continue", - "version": "0.0.166", + "version": "0.0.167", "license": "Apache-2.0", "dependencies": { "@electron/rebuild": "^3.2.10", diff --git a/extension/package.json b/extension/package.json index 7cd7b793..bbd18b12 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.166", + "version": "0.0.167", "publisher": "Continue", "engines": { "vscode": "^1.67.0" diff --git a/extension/react-app/src/components/TextDialog.tsx b/extension/react-app/src/components/TextDialog.tsx index c724697d..646d6846 100644 --- a/extension/react-app/src/components/TextDialog.tsx +++ b/extension/react-app/src/components/TextDialog.tsx @@ -2,6 +2,7 @@ import React, { useEffect, useState } from "react"; import styled from "styled-components"; import { Button, buttonColor, secondaryDark, vscBackground } from "."; +import { isMetaEquivalentKeyPressed } from "../util"; const ScreenCover = styled.div` position: absolute; diff --git a/extension/react-app/src/pages/gui.tsx b/extension/react-app/src/pages/gui.tsx index cb0404ab..64207487 100644 --- a/extension/react-app/src/pages/gui.tsx +++ b/extension/react-app/src/pages/gui.tsx @@ -23,6 +23,7 @@ import { RootStore } from "../redux/store"; import { postVscMessage } from "../vscode"; import UserInputContainer from "../components/UserInputContainer"; import Onboarding from "../components/Onboarding"; +import { isMetaEquivalentKeyPressed } from "../util"; const TopGUIDiv = styled.div` overflow: hidden; diff --git a/extension/src/activation/environmentSetup.ts b/extension/src/activation/environmentSetup.ts index 374c38c0..6a66532e 100644 --- a/extension/src/activation/environmentSetup.ts +++ b/extension/src/activation/environmentSetup.ts @@ -11,7 +11,8 @@ import * as os from "os"; import fkill from "fkill"; import { sendTelemetryEvent, TelemetryEvent } from "../telemetry"; -const WINDOWS_REMOTE_SIGNED_SCRIPTS_ERROR = "A Python virtual enviroment cannot be activated because running scripts is disabled for this user. Please enable signed scripts to run with this command in PowerShell: `Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser`, reload VS Code, and then try again."; +const WINDOWS_REMOTE_SIGNED_SCRIPTS_ERROR = + "A Python virtual enviroment cannot be activated because running scripts is disabled for this user. In order to use Continue, please enable signed scripts to run with this command in PowerShell: `Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser`, reload VS Code, and then try again."; const MAX_RETRIES = 3; async function retryThenFail( @@ -26,7 +27,8 @@ async function retryThenFail( } // Show corresponding error message depending on the platform - let msg = "Failed to set up Continue extension. Please email nate@continue.dev and we'll get this fixed ASAP!"; + let msg = + "Failed to set up Continue extension. Please email nate@continue.dev and we'll get this fixed ASAP!"; try { switch (process.platform) { case "win32": @@ -35,14 +37,14 @@ async function retryThenFail( case "darwin": break; case "linux": - const [pythonCmd,] = await getPythonPipCommands(); + const [pythonCmd] = await getPythonPipCommands(); msg = await getLinuxAptInstallError(pythonCmd); break; } } finally { vscode.window.showErrorMessage(msg); } - + sendTelemetryEvent(TelemetryEvent.ExtensionSetupError, { error: e.message, }); @@ -216,10 +218,7 @@ async function getLinuxAptInstallError(pythonCmd: string) { const version = stdout.split(" ")[1].split(".")[1]; const installVenvCommand = `apt-get install python3.${version}-venv`; await runCommand("apt-get update"); - // Ask the user to run the command to install python3-venv (requires sudo, so we can't) - // First, get the python version - const msg = `[Important] Continue needs to create a Python virtual environment, but python3.${version}-venv is not installed. Please run this command in your terminal: \`${installVenvCommand}\`, reload VS Code, and then try again.`; - return msg; + return `[Important] Continue needs to create a Python virtual environment, but python3.${version}-venv is not installed. Please run this command in your terminal: \`${installVenvCommand}\`, reload VS Code, and then try again.`; } async function setupPythonEnv() { @@ -246,9 +245,7 @@ async function setupPythonEnv() { stderr && stderr.includes("running scripts is disabled on this system") ) { - await vscode.window.showErrorMessage( - WINDOWS_REMOTE_SIGNED_SCRIPTS_ERROR - ); + await vscode.window.showErrorMessage(WINDOWS_REMOTE_SIGNED_SCRIPTS_ERROR); throw new Error(stderr); } else if ( stderr?.includes("On Debian/Ubuntu systems") || -- cgit v1.2.3-70-g09d2 From 2e52eb4cc50f7c6fffcf7687ecd15d80073b07c6 Mon Sep 17 00:00:00 2001 From: sestinj Date: Sat, 15 Jul 2023 16:42:58 -0700 Subject: Change to remote signed in order to setup python venv --- extension/src/activation/environmentSetup.ts | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'extension/src/activation/environmentSetup.ts') diff --git a/extension/src/activation/environmentSetup.ts b/extension/src/activation/environmentSetup.ts index 6a66532e..43e7832c 100644 --- a/extension/src/activation/environmentSetup.ts +++ b/extension/src/activation/environmentSetup.ts @@ -20,6 +20,10 @@ async function retryThenFail( retries: number = MAX_RETRIES ): Promise { try { + if (retries < MAX_RETRIES && process.platform === "win32") { + const [stdout, stderr] = await runCommand("Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser"); + } + return await fn(); } catch (e: any) { if (retries > 0) { -- cgit v1.2.3-70-g09d2 From 21dc20871347165a8526bbbea1d351e2f10f4d93 Mon Sep 17 00:00:00 2001 From: Nate Sesti Date: Sat, 15 Jul 2023 17:46:03 -0700 Subject: patch --- extension/package-lock.json | 4 ++-- extension/package.json | 2 +- extension/src/activation/environmentSetup.ts | 6 +++++- 3 files changed, 8 insertions(+), 4 deletions(-) (limited to 'extension/src/activation/environmentSetup.ts') diff --git a/extension/package-lock.json b/extension/package-lock.json index ba455540..edd0f0d0 100644 --- a/extension/package-lock.json +++ b/extension/package-lock.json @@ -1,12 +1,12 @@ { "name": "continue", - "version": "0.0.168", + "version": "0.0.169", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "continue", - "version": "0.0.168", + "version": "0.0.169", "license": "Apache-2.0", "dependencies": { "@electron/rebuild": "^3.2.10", diff --git a/extension/package.json b/extension/package.json index 0c8e2037..91a863ff 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.168", + "version": "0.0.169", "publisher": "Continue", "engines": { "vscode": "^1.67.0" diff --git a/extension/src/activation/environmentSetup.ts b/extension/src/activation/environmentSetup.ts index 43e7832c..b4ada632 100644 --- a/extension/src/activation/environmentSetup.ts +++ b/extension/src/activation/environmentSetup.ts @@ -21,7 +21,11 @@ async function retryThenFail( ): Promise { try { if (retries < MAX_RETRIES && process.platform === "win32") { - const [stdout, stderr] = await runCommand("Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser"); + const [stdout, stderr] = await runCommand( + "Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser" + ); + console.log("Execution policy stdout: ", stdout); + console.log("Execution policy stderr: ", stderr); } return await fn(); -- cgit v1.2.3-70-g09d2 From 1c41fb0a803c886841dbea9fa5e4129059a32e5d Mon Sep 17 00:00:00 2001 From: Nate Sesti Date: Sat, 15 Jul 2023 17:57:51 -0700 Subject: patch --- extension/package-lock.json | 4 +- extension/package.json | 2 +- extension/src/activation/environmentSetup.ts | 92 +++++++++++++++------------- 3 files changed, 54 insertions(+), 44 deletions(-) (limited to 'extension/src/activation/environmentSetup.ts') diff --git a/extension/package-lock.json b/extension/package-lock.json index edd0f0d0..f793abae 100644 --- a/extension/package-lock.json +++ b/extension/package-lock.json @@ -1,12 +1,12 @@ { "name": "continue", - "version": "0.0.169", + "version": "0.0.171", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "continue", - "version": "0.0.169", + "version": "0.0.171", "license": "Apache-2.0", "dependencies": { "@electron/rebuild": "^3.2.10", diff --git a/extension/package.json b/extension/package.json index 91a863ff..38dc4542 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.169", + "version": "0.0.171", "publisher": "Continue", "engines": { "vscode": "^1.67.0" diff --git a/extension/src/activation/environmentSetup.ts b/extension/src/activation/environmentSetup.ts index b4ada632..be1c220c 100644 --- a/extension/src/activation/environmentSetup.ts +++ b/extension/src/activation/environmentSetup.ts @@ -21,11 +21,16 @@ async function retryThenFail( ): Promise { try { if (retries < MAX_RETRIES && process.platform === "win32") { - const [stdout, stderr] = await runCommand( - "Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser" - ); - console.log("Execution policy stdout: ", stdout); - console.log("Execution policy stderr: ", stderr); + let [stdout, stderr] = await runCommand("Get-ExecutionPolicy"); + if (!stdout.includes("RemoteSigned")) { + [stdout, stderr] = await runCommand( + "Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser" + ); + console.log("Execution policy stdout: ", stdout); + console.log("Execution policy stderr: ", stderr); + // Then reload the window for this to take effect + await vscode.commands.executeCommand("workbench.action.reloadWindow"); + } } return await fn(); @@ -238,45 +243,50 @@ async function setupPythonEnv() { pipCmd ); - // First, create the virtual environment - if (checkEnvExists()) { - console.log("Python env already exists, skipping..."); - } else { - // Assemble the command to create the env - const createEnvCommand = [ - `cd "${serverPath()}"`, - `${pythonCmd} -m venv env`, - ].join(" ; "); - - const [stdout, stderr] = await runCommand(createEnvCommand); - if ( - stderr && - stderr.includes("running scripts is disabled on this system") - ) { - await vscode.window.showErrorMessage(WINDOWS_REMOTE_SIGNED_SCRIPTS_ERROR); - throw new Error(stderr); - } else if ( - stderr?.includes("On Debian/Ubuntu systems") || - stdout?.includes("On Debian/Ubuntu systems") - ) { - const msg = await getLinuxAptInstallError(pythonCmd); - console.log(msg); - await vscode.window.showErrorMessage(msg); - } else if (checkEnvExists()) { - console.log("Successfully set up python env at ", `${serverPath()}/env`); + await retryThenFail(async () => { + // First, create the virtual environment + if (checkEnvExists()) { + console.log("Python env already exists, skipping..."); } else { - const msg = [ - "Python environment not successfully created. Trying again. Here was the stdout + stderr: ", - `stdout: ${stdout}`, - `stderr: ${stderr}`, - ].join("\n\n"); - console.log(msg); - throw new Error(msg); + // Assemble the command to create the env + const createEnvCommand = [ + `cd "${serverPath()}"`, + `${pythonCmd} -m venv env`, + ].join(" ; "); + + const [stdout, stderr] = await runCommand(createEnvCommand); + if ( + stderr && + stderr.includes("running scripts is disabled on this system") + ) { + await vscode.window.showErrorMessage( + WINDOWS_REMOTE_SIGNED_SCRIPTS_ERROR + ); + throw new Error(stderr); + } else if ( + stderr?.includes("On Debian/Ubuntu systems") || + stdout?.includes("On Debian/Ubuntu systems") + ) { + const msg = await getLinuxAptInstallError(pythonCmd); + console.log(msg); + await vscode.window.showErrorMessage(msg); + } else if (checkEnvExists()) { + console.log( + "Successfully set up python env at ", + `${serverPath()}/env` + ); + } else { + const msg = [ + "Python environment not successfully created. Trying again. Here was the stdout + stderr: ", + `stdout: ${stdout}`, + `stderr: ${stderr}`, + ].join("\n\n"); + console.log(msg); + throw new Error(msg); + } } - } - // Install the requirements - await retryThenFail(async () => { + // Install the requirements if (await checkRequirementsInstalled()) { console.log("Python requirements already installed, skipping..."); } else { -- cgit v1.2.3-70-g09d2 From 07809c6717856e854d9005f77d51d274dec0fcc4 Mon Sep 17 00:00:00 2001 From: Nate Sesti Date: Sat, 15 Jul 2023 18:47:28 -0700 Subject: 5s timeout on websocket connections --- continuedev/src/continuedev/server/gui.py | 9 +++++++-- continuedev/src/continuedev/server/ide.py | 8 ++++++-- extension/package-lock.json | 4 ++-- extension/package.json | 2 +- extension/src/activation/environmentSetup.ts | 5 ++--- 5 files changed, 18 insertions(+), 10 deletions(-) (limited to 'extension/src/activation/environmentSetup.ts') diff --git a/continuedev/src/continuedev/server/gui.py b/continuedev/src/continuedev/server/gui.py index 9a411fbe..4201353e 100644 --- a/continuedev/src/continuedev/server/gui.py +++ b/continuedev/src/continuedev/server/gui.py @@ -1,3 +1,4 @@ +import asyncio import json from fastapi import Depends, Header, WebSocket, APIRouter from starlette.websockets import WebSocketState, WebSocketDisconnect @@ -60,8 +61,12 @@ class GUIProtocolServer(AbstractGUIProtocolServer): "data": data }) - async def _receive_json(self, message_type: str) -> Any: - return await self.sub_queue.get(message_type) + async def _receive_json(self, message_type: str, timeout: int = 5) -> Any: + try: + return await asyncio.wait_for(self.sub_queue.get(message_type), timeout=timeout) + except asyncio.TimeoutError: + raise Exception( + "GUI Protocol _receive_json timed out after 5 seconds") async def _send_and_receive_json(self, data: Any, resp_model: Type[T], message_type: str) -> T: await self._send_json(message_type, data) diff --git a/continuedev/src/continuedev/server/ide.py b/continuedev/src/continuedev/server/ide.py index 77b13483..e5e8de02 100644 --- a/continuedev/src/continuedev/server/ide.py +++ b/continuedev/src/continuedev/server/ide.py @@ -156,8 +156,12 @@ class IdeProtocolServer(AbstractIdeProtocolServer): "data": data }) - async def _receive_json(self, message_type: str) -> Any: - return await self.sub_queue.get(message_type) + async def _receive_json(self, message_type: str, timeout: int = 5) -> Any: + try: + return await asyncio.wait_for(self.sub_queue.get(message_type), timeout=timeout) + except asyncio.TimeoutError: + raise Exception( + "IDE Protocol _receive_json timed out after 5 seconds") async def _send_and_receive_json(self, data: Any, resp_model: Type[T], message_type: str) -> T: await self._send_json(message_type, data) diff --git a/extension/package-lock.json b/extension/package-lock.json index f793abae..b86cb10e 100644 --- a/extension/package-lock.json +++ b/extension/package-lock.json @@ -1,12 +1,12 @@ { "name": "continue", - "version": "0.0.171", + "version": "0.0.172", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "continue", - "version": "0.0.171", + "version": "0.0.172", "license": "Apache-2.0", "dependencies": { "@electron/rebuild": "^3.2.10", diff --git a/extension/package.json b/extension/package.json index 38dc4542..6b719723 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.171", + "version": "0.0.172", "publisher": "Continue", "engines": { "vscode": "^1.67.0" diff --git a/extension/src/activation/environmentSetup.ts b/extension/src/activation/environmentSetup.ts index be1c220c..7a0d24d4 100644 --- a/extension/src/activation/environmentSetup.ts +++ b/extension/src/activation/environmentSetup.ts @@ -28,8 +28,6 @@ async function retryThenFail( ); console.log("Execution policy stdout: ", stdout); console.log("Execution policy stderr: ", stderr); - // Then reload the window for this to take effect - await vscode.commands.executeCommand("workbench.action.reloadWindow"); } } @@ -447,7 +445,8 @@ export async function startContinuePythonServer() { console.log(`stdout: ${data}`); if ( data.includes("Uvicorn running on") || // Successfully started the server - data.includes("address already in use") // The server is already running (probably a simultaneously opened VS Code window) + data.includes("only one usage of each socket address") || // [windows] The server is already running (probably a simultaneously opened VS Code window) + data.includes("address already in use") // [mac/linux] The server is already running (probably a simultaneously opened VS Code window) ) { console.log("Successfully started Continue python server"); resolve(null); -- cgit v1.2.3-70-g09d2 From 1cc788de843169400d70f26e533417f3a0a95b29 Mon Sep 17 00:00:00 2001 From: Nate Sesti Date: Sat, 15 Jul 2023 19:14:01 -0700 Subject: one window wait for other to create venv --- extension/package-lock.json | 4 +- extension/package.json | 2 +- extension/src/activation/environmentSetup.ts | 99 +++++++++++++++++----------- 3 files changed, 63 insertions(+), 42 deletions(-) (limited to 'extension/src/activation/environmentSetup.ts') diff --git a/extension/package-lock.json b/extension/package-lock.json index b86cb10e..f1423041 100644 --- a/extension/package-lock.json +++ b/extension/package-lock.json @@ -1,12 +1,12 @@ { "name": "continue", - "version": "0.0.172", + "version": "0.0.173", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "continue", - "version": "0.0.172", + "version": "0.0.173", "license": "Apache-2.0", "dependencies": { "@electron/rebuild": "^3.2.10", diff --git a/extension/package.json b/extension/package.json index 6b719723..0638e768 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.172", + "version": "0.0.173", "publisher": "Continue", "engines": { "vscode": "^1.67.0" diff --git a/extension/src/activation/environmentSetup.ts b/extension/src/activation/environmentSetup.ts index 7a0d24d4..928fe04b 100644 --- a/extension/src/activation/environmentSetup.ts +++ b/extension/src/activation/environmentSetup.ts @@ -53,6 +53,7 @@ async function retryThenFail( break; } } finally { + console.log("After retries, failed to set up Continue extension", msg); vscode.window.showErrorMessage(msg); } @@ -232,57 +233,77 @@ async function getLinuxAptInstallError(pythonCmd: string) { return `[Important] Continue needs to create a Python virtual environment, but python3.${version}-venv is not installed. Please run this command in your terminal: \`${installVenvCommand}\`, reload VS Code, and then try again.`; } -async function setupPythonEnv() { - console.log("Setting up python env for Continue extension..."); - - const [pythonCmd, pipCmd] = await getPythonPipCommands(); - const [activateCmd, pipUpgradeCmd] = getActivateUpgradeCommands( - pythonCmd, - pipCmd - ); +async function createPythonVenv(pythonCmd: string) { + if (checkEnvExists()) { + console.log("Python env already exists, skipping..."); + } else { + // Assemble the command to create the env + const createEnvCommand = [ + `cd "${serverPath()}"`, + `${pythonCmd} -m venv env`, + ].join(" ; "); - await retryThenFail(async () => { - // First, create the virtual environment - if (checkEnvExists()) { - console.log("Python env already exists, skipping..."); + const [stdout, stderr] = await runCommand(createEnvCommand); + if ( + stderr && + stderr.includes("running scripts is disabled on this system") + ) { + console.log("Scripts disabled error when trying to create env"); + await vscode.window.showErrorMessage(WINDOWS_REMOTE_SIGNED_SCRIPTS_ERROR); + throw new Error(stderr); + } else if ( + stderr?.includes("On Debian/Ubuntu systems") || + stdout?.includes("On Debian/Ubuntu systems") + ) { + const msg = await getLinuxAptInstallError(pythonCmd); + console.log(msg); + await vscode.window.showErrorMessage(msg); + } else if (checkEnvExists()) { + console.log("Successfully set up python env at ", `${serverPath()}/env`); } else { - // Assemble the command to create the env - const createEnvCommand = [ - `cd "${serverPath()}"`, - `${pythonCmd} -m venv env`, - ].join(" ; "); - - const [stdout, stderr] = await runCommand(createEnvCommand); - if ( - stderr && - stderr.includes("running scripts is disabled on this system") - ) { - await vscode.window.showErrorMessage( - WINDOWS_REMOTE_SIGNED_SCRIPTS_ERROR - ); - throw new Error(stderr); - } else if ( - stderr?.includes("On Debian/Ubuntu systems") || - stdout?.includes("On Debian/Ubuntu systems") - ) { - const msg = await getLinuxAptInstallError(pythonCmd); - console.log(msg); - await vscode.window.showErrorMessage(msg); - } else if (checkEnvExists()) { - console.log( - "Successfully set up python env at ", - `${serverPath()}/env` + try { + // This might mean that another window is currently using the python.exe file to install requirements + // So we want to wait and try again + let i = 0; + await new Promise((resolve, reject) => + setInterval(() => { + if (i > 5) { + reject(); + } + if (checkEnvExists()) { + resolve(null); + } else { + console.log("Waiting for other window to create env..."); + } + i++; + }, 5000) ); - } else { + } catch (e) { const msg = [ "Python environment not successfully created. Trying again. Here was the stdout + stderr: ", `stdout: ${stdout}`, `stderr: ${stderr}`, + `e: ${e}`, ].join("\n\n"); console.log(msg); throw new Error(msg); } } + } +} + +async function setupPythonEnv() { + console.log("Setting up python env for Continue extension..."); + + const [pythonCmd, pipCmd] = await getPythonPipCommands(); + const [activateCmd, pipUpgradeCmd] = getActivateUpgradeCommands( + pythonCmd, + pipCmd + ); + + await retryThenFail(async () => { + // First, create the virtual environment + await createPythonVenv(pythonCmd); // Install the requirements if (await checkRequirementsInstalled()) { -- cgit v1.2.3-70-g09d2 From 53536dce999f2858102b7bf969824141140c5fc7 Mon Sep 17 00:00:00 2001 From: Nate Sesti Date: Sat, 15 Jul 2023 21:55:47 -0700 Subject: fixed reading of terminal and other vscode windows --- continuedev/src/continuedev/server/ide.py | 34 ++++++--------- extension/package-lock.json | 4 +- extension/package.json | 2 +- extension/src/activation/environmentSetup.ts | 54 ++++++++++++------------ extension/src/continueIdeClient.ts | 63 ++++++++++++++++------------ 5 files changed, 79 insertions(+), 78 deletions(-) (limited to 'extension/src/activation/environmentSetup.ts') diff --git a/continuedev/src/continuedev/server/ide.py b/continuedev/src/continuedev/server/ide.py index e5e8de02..a8868a9a 100644 --- a/continuedev/src/continuedev/server/ide.py +++ b/continuedev/src/continuedev/server/ide.py @@ -126,7 +126,8 @@ class IdeProtocolServer(AbstractIdeProtocolServer): workspace_directory: str = None unique_id: str = None - async def initialize(self) -> List[str]: + async def initialize(self, session_id: str) -> List[str]: + self.session_id = session_id await self._send_json("workspaceDirectory", {}) await self._send_json("uniqueId", {}) other_msgs = [] @@ -287,32 +288,24 @@ class IdeProtocolServer(AbstractIdeProtocolServer): pass def onFileEdits(self, edits: List[FileEditWithFullContents]): - # Send the file edits to ALL autopilots. - # Maybe not ideal behavior - for _, session in self.session_manager.sessions.items(): - session.autopilot.handle_manual_edits(edits) + session_manager.sessions[self.session_id].autopilot.handle_manual_edits( + edits) def onDeleteAtIndex(self, index: int): - for _, session in self.session_manager.sessions.items(): - create_async_task( - session.autopilot.delete_at_index(index), self.unique_id) + create_async_task( + session_manager.sessions[self.session_id].autopilot.delete_at_index(index), self.unique_id) def onCommandOutput(self, output: str): - # Send the output to ALL autopilots. - # Maybe not ideal behavior - for _, session in self.session_manager.sessions.items(): - create_async_task( - session.autopilot.handle_command_output(output), self.unique_id) + create_async_task( + self.session_manager.sessions[self.session_id].autopilot.handle_command_output(output), self.unique_id) def onHighlightedCodeUpdate(self, range_in_files: List[RangeInFileWithContents]): - for _, session in self.session_manager.sessions.items(): - create_async_task( - session.autopilot.handle_highlighted_code(range_in_files), self.unique_id) + create_async_task( + self.session_manager.sessions[self.session_id].autopilot.handle_highlighted_code(range_in_files), self.unique_id) def onMainUserInput(self, input: str): - for _, session in self.session_manager.sessions.items(): - create_async_task( - session.autopilot.accept_user_input(input), self.unique_id) + create_async_task( + self.session_manager.sessions[self.session_id].autopilot.accept_user_input(input), self.unique_id) # Request information. Session doesn't matter. async def getOpenFiles(self) -> List[str]: @@ -440,10 +433,9 @@ async def websocket_endpoint(websocket: WebSocket, session_id: str = None): 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() + other_msgs = await ideProtocolServer.initialize(session_id) for other_msg in other_msgs: handle_msg(other_msg) diff --git a/extension/package-lock.json b/extension/package-lock.json index f1423041..6f777c72 100644 --- a/extension/package-lock.json +++ b/extension/package-lock.json @@ -1,12 +1,12 @@ { "name": "continue", - "version": "0.0.173", + "version": "0.0.174", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "continue", - "version": "0.0.173", + "version": "0.0.174", "license": "Apache-2.0", "dependencies": { "@electron/rebuild": "^3.2.10", diff --git a/extension/package.json b/extension/package.json index 0638e768..9fe38f7f 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.173", + "version": "0.0.174", "publisher": "Continue", "engines": { "vscode": "^1.67.0" diff --git a/extension/src/activation/environmentSetup.ts b/extension/src/activation/environmentSetup.ts index 928fe04b..df609a34 100644 --- a/extension/src/activation/environmentSetup.ts +++ b/extension/src/activation/environmentSetup.ts @@ -260,34 +260,34 @@ async function createPythonVenv(pythonCmd: string) { await vscode.window.showErrorMessage(msg); } else if (checkEnvExists()) { console.log("Successfully set up python env at ", `${serverPath()}/env`); + } else if ( + stderr?.includes("Permission denied") && + stderr?.includes("python.exe") + ) { + // This might mean that another window is currently using the python.exe file to install requirements + // So we want to wait and try again + let i = 0; + await new Promise((resolve, reject) => + setInterval(() => { + if (i > 5) { + reject("Timed out waiting for other window to create env..."); + } + if (checkEnvExists()) { + resolve(null); + } else { + console.log("Waiting for other window to create env..."); + } + i++; + }, 5000) + ); } else { - try { - // This might mean that another window is currently using the python.exe file to install requirements - // So we want to wait and try again - let i = 0; - await new Promise((resolve, reject) => - setInterval(() => { - if (i > 5) { - reject(); - } - if (checkEnvExists()) { - resolve(null); - } else { - console.log("Waiting for other window to create env..."); - } - i++; - }, 5000) - ); - } catch (e) { - const msg = [ - "Python environment not successfully created. Trying again. Here was the stdout + stderr: ", - `stdout: ${stdout}`, - `stderr: ${stderr}`, - `e: ${e}`, - ].join("\n\n"); - console.log(msg); - throw new Error(msg); - } + const msg = [ + "Python environment not successfully created. Trying again. Here was the stdout + stderr: ", + `stdout: ${stdout}`, + `stderr: ${stderr}`, + ].join("\n\n"); + console.log(msg); + throw new Error(msg); } } } diff --git a/extension/src/continueIdeClient.ts b/extension/src/continueIdeClient.ts index 2c96763d..fac0a227 100644 --- a/extension/src/continueIdeClient.ts +++ b/extension/src/continueIdeClient.ts @@ -104,8 +104,11 @@ class IdeProtocolClient { // } // }); - // Setup listeners for any file changes in open editors + // Setup listeners for any selection changes in open editors vscode.window.onDidChangeTextEditorSelection((event) => { + if (this.editorIsTerminal(event.textEditor)) { + return; + } if (this._highlightDebounce) { clearTimeout(this._highlightDebounce); } @@ -376,20 +379,24 @@ class IdeProtocolClient { } saveFile(filepath: string) { - vscode.window.visibleTextEditors.forEach((editor) => { - if (editor.document.uri.fsPath === filepath) { - editor.document.save(); - } - }); + vscode.window.visibleTextEditors + .filter((editor) => !this.editorIsTerminal(editor)) + .forEach((editor) => { + if (editor.document.uri.fsPath === filepath) { + editor.document.save(); + } + }); } readFile(filepath: string): string { let contents: string | undefined; - vscode.window.visibleTextEditors.forEach((editor) => { - if (editor.document.uri.fsPath === filepath) { - contents = editor.document.getText(); - } - }); + vscode.window.visibleTextEditors + .filter((editor) => !this.editorIsTerminal(editor)) + .forEach((editor) => { + if (editor.document.uri.fsPath === filepath) { + contents = editor.document.getText(); + } + }); if (typeof contents === "undefined") { if (fs.existsSync(filepath)) { contents = fs.readFileSync(filepath, "utf-8"); @@ -429,25 +436,27 @@ class IdeProtocolClient { getHighlightedCode(): RangeInFile[] { // TODO let rangeInFiles: RangeInFile[] = []; - vscode.window.visibleTextEditors.forEach((editor) => { - editor.selections.forEach((selection) => { - // if (!selection.isEmpty) { - rangeInFiles.push({ - filepath: editor.document.uri.fsPath, - range: { - start: { - line: selection.start.line, - character: selection.start.character, - }, - end: { - line: selection.end.line, - character: selection.end.character, + vscode.window.visibleTextEditors + .filter((editor) => !this.editorIsTerminal(editor)) + .forEach((editor) => { + editor.selections.forEach((selection) => { + // if (!selection.isEmpty) { + rangeInFiles.push({ + filepath: editor.document.uri.fsPath, + range: { + start: { + line: selection.start.line, + character: selection.start.character, + }, + end: { + line: selection.end.line, + character: selection.end.character, + }, }, - }, + }); + // } }); - // } }); - }); return rangeInFiles; } -- cgit v1.2.3-70-g09d2 From 6e2634f70662ce04207e4a1fad2e27761179b123 Mon Sep 17 00:00:00 2001 From: Nate Sesti Date: Sun, 16 Jul 2023 16:10:50 -0700 Subject: record accept/reject --- extension/src/activation/environmentSetup.ts | 8 ++++ extension/src/diffs.ts | 46 ++++++++++++++++++++- extension/src/suggestions.ts | 60 +--------------------------- 3 files changed, 54 insertions(+), 60 deletions(-) (limited to 'extension/src/activation/environmentSetup.ts') diff --git a/extension/src/activation/environmentSetup.ts b/extension/src/activation/environmentSetup.ts index df609a34..69a3b75a 100644 --- a/extension/src/activation/environmentSetup.ts +++ b/extension/src/activation/environmentSetup.ts @@ -400,6 +400,14 @@ function serverPath(): string { return sPath; } +export function devDataPath(): string { + const sPath = path.join(getContinueGlobalPath(), "dev_data"); + if (!fs.existsSync(sPath)) { + fs.mkdirSync(sPath); + } + return sPath; +} + function serverVersionPath(): string { return path.join(serverPath(), "server_version.txt"); } diff --git a/extension/src/diffs.ts b/extension/src/diffs.ts index 2860258d..0bab326a 100644 --- a/extension/src/diffs.ts +++ b/extension/src/diffs.ts @@ -4,6 +4,7 @@ import * as fs from "fs"; import * as vscode from "vscode"; import { extensionContext, ideProtocolClient } from "./activation/activate"; import { getMetaKeyLabel } from "./util/util"; +import { devDataPath } from "./activation/environmentSetup"; interface DiffInfo { originalFilepath: string; @@ -13,7 +14,9 @@ interface DiffInfo { range: vscode.Range; } -export const DIFF_DIRECTORY = path.join(os.homedir(), ".continue", "diffs").replace(/^C:/, "c:"); +export const DIFF_DIRECTORY = path + .join(os.homedir(), ".continue", "diffs") + .replace(/^C:/, "c:"); class DiffManager { // Create a temporary file in the global .continue directory which displays the updated version @@ -222,6 +225,8 @@ class DiffManager { ); this.cleanUpDiff(diffInfo); }); + + recordAcceptReject(true, diffInfo); } rejectDiff(newFilepath?: string) { @@ -251,11 +256,50 @@ class DiffManager { .then(() => { this.cleanUpDiff(diffInfo); }); + + recordAcceptReject(false, diffInfo); } } export const diffManager = new DiffManager(); +function recordAcceptReject(accepted: boolean, diffInfo: DiffInfo) { + const collectOn = vscode.workspace + .getConfiguration("continue") + .get("dataSwitch"); + + if (collectOn) { + const devDataDir = devDataPath(); + const suggestionsPath = path.join(devDataDir, "suggestions.json"); + + // Initialize suggestions list + let suggestions = []; + + // Check if suggestions.json exists + if (fs.existsSync(suggestionsPath)) { + const rawData = fs.readFileSync(suggestionsPath, "utf-8"); + suggestions = JSON.parse(rawData); + } + + // Add the new suggestion to the list + suggestions.push({ + accepted, + timestamp: Date.now(), + suggestion: diffInfo.originalFilepath, + }); + + // Send the suggestion to the server + ideProtocolClient.sendAcceptRejectSuggestion(accepted); + + // Write the updated suggestions back to the file + fs.writeFileSync( + suggestionsPath, + JSON.stringify(suggestions, null, 4), + "utf-8" + ); + } +} + export async function acceptDiffCommand(newFilepath?: string) { diffManager.acceptDiff(newFilepath); ideProtocolClient.sendAcceptRejectDiff(true); diff --git a/extension/src/suggestions.ts b/extension/src/suggestions.ts index 6e5a444f..c2373223 100644 --- a/extension/src/suggestions.ts +++ b/extension/src/suggestions.ts @@ -1,9 +1,7 @@ import * as vscode from "vscode"; import { sendTelemetryEvent, TelemetryEvent } from "./telemetry"; import { openEditorAndRevealRange } from "./util/vscode"; -import { translate, readFileAtRange } from "./util/vscode"; -import * as fs from "fs"; -import * as path from "path"; +import { translate } from "./util/vscode"; import { registerAllCodeLensProviders } from "./lang-server/codeLens"; import { extensionContext, ideProtocolClient } from "./activation/activate"; @@ -214,62 +212,6 @@ function selectSuggestion( : suggestion.newRange; } - let workspaceDir = vscode.workspace.workspaceFolders - ? vscode.workspace.workspaceFolders[0]?.uri.fsPath - : undefined; - - let collectOn = vscode.workspace - .getConfiguration("continue") - .get("dataSwitch"); - - if (workspaceDir && collectOn) { - let continueDir = path.join(workspaceDir, ".continue"); - - // Check if .continue directory doesn't exists - if (!fs.existsSync(continueDir)) { - fs.mkdirSync(continueDir); - } - - let suggestionsPath = path.join(continueDir, "suggestions.json"); - - // Initialize suggestions list - let suggestions = []; - - // Check if suggestions.json exists - if (fs.existsSync(suggestionsPath)) { - let rawData = fs.readFileSync(suggestionsPath, "utf-8"); - suggestions = JSON.parse(rawData); - } - - const accepted = - accept === "new" || (accept === "selected" && suggestion.newSelected); - suggestions.push({ - accepted, - timestamp: Date.now(), - suggestion: suggestion.newContent, - }); - ideProtocolClient.sendAcceptRejectSuggestion(accepted); - - // Write the updated suggestions back to the file - fs.writeFileSync( - suggestionsPath, - JSON.stringify(suggestions, null, 4), - "utf-8" - ); - - // If it's not already there, add .continue to .gitignore - const gitignorePath = path.join(workspaceDir, ".gitignore"); - if (fs.existsSync(gitignorePath)) { - const gitignoreData = fs.readFileSync(gitignorePath, "utf-8"); - const gitIgnoreLines = gitignoreData.split("\n"); - if (!gitIgnoreLines.includes(".continue")) { - fs.appendFileSync(gitignorePath, "\n.continue\n"); - } - } else { - fs.writeFileSync(gitignorePath, ".continue\n"); - } - } - rangeToDelete = new vscode.Range( rangeToDelete.start, new vscode.Position(rangeToDelete.end.line, 0) -- cgit v1.2.3-70-g09d2 From 53ac7b93f456b471eaa7f03e015e2d8c0ef393e5 Mon Sep 17 00:00:00 2001 From: Nate Sesti Date: Tue, 18 Jul 2023 14:02:03 -0700 Subject: error handle on invalid config file, don't immediately show loading message --- continuedev/src/continuedev/core/sdk.py | 19 ++++++++++- extension/package-lock.json | 4 +-- extension/package.json | 2 +- extension/schema/FullState.d.ts | 2 ++ extension/schema/History.d.ts | 2 ++ extension/schema/HistoryNode.d.ts | 2 ++ extension/src/activation/activate.ts | 48 ++++++++++++++++++++-------- extension/src/activation/environmentSetup.ts | 2 +- extension/src/extension.ts | 12 +------ schema/json/FullState.json | 8 +++++ schema/json/History.json | 8 +++++ schema/json/HistoryNode.json | 8 +++++ 12 files changed, 88 insertions(+), 29 deletions(-) (limited to 'extension/src/activation/environmentSetup.ts') diff --git a/continuedev/src/continuedev/core/sdk.py b/continuedev/src/continuedev/core/sdk.py index 53214384..37a51efa 100644 --- a/continuedev/src/continuedev/core/sdk.py +++ b/continuedev/src/continuedev/core/sdk.py @@ -15,7 +15,7 @@ from ..libs.llm.anthropic import AnthropicLLM from ..libs.llm.ggml import GGML from .observation import Observation from ..server.ide_protocol import AbstractIdeProtocolServer -from .main import Context, ContinueCustomException, History, Step, ChatMessage +from .main import Context, ContinueCustomException, History, HistoryNode, Step, ChatMessage from ..steps.core.core import * from ..libs.llm.proxy_server import ProxyServer @@ -155,6 +155,23 @@ class ContinueSDK(AbstractContinueSDK): @classmethod async def create(cls, autopilot: Autopilot) -> "ContinueSDK": sdk = ContinueSDK(autopilot) + + try: + config = sdk._load_config() + sdk.config = config + except Exception as e: + print(e) + sdk.config = ContinueConfig() + msg_step = MessageStep( + name="Invalid Continue Config File", message=e.__repr__()) + msg_step.description = e.__repr__() + sdk.history.add_node(HistoryNode( + step=msg_step, + observation=None, + depth=0, + active=False + )) + sdk.models = await Models.create(sdk) return sdk diff --git a/extension/package-lock.json b/extension/package-lock.json index 107a7001..6818857b 100644 --- a/extension/package-lock.json +++ b/extension/package-lock.json @@ -1,12 +1,12 @@ { "name": "continue", - "version": "0.0.179", + "version": "0.0.181", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "continue", - "version": "0.0.179", + "version": "0.0.181", "license": "Apache-2.0", "dependencies": { "@electron/rebuild": "^3.2.10", diff --git a/extension/package.json b/extension/package.json index 89c6daf5..b37bb1b6 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.179", + "version": "0.0.181", "publisher": "Continue", "engines": { "vscode": "^1.67.0" diff --git a/extension/schema/FullState.d.ts b/extension/schema/FullState.d.ts index abb0832d..1b7b1f3b 100644 --- a/extension/schema/FullState.d.ts +++ b/extension/schema/FullState.d.ts @@ -21,6 +21,7 @@ export type ManageOwnChatContext = boolean; export type Depth = number; export type Deleted = boolean; export type Active = boolean; +export type Logs = string[]; export type Timeline = HistoryNode[]; export type CurrentIndex = number; export type Active1 = boolean; @@ -69,6 +70,7 @@ export interface HistoryNode { depth: Depth; deleted?: Deleted; active?: Active; + logs?: Logs; [k: string]: unknown; } export interface Step { diff --git a/extension/schema/History.d.ts b/extension/schema/History.d.ts index 6eb8ad81..90124f4a 100644 --- a/extension/schema/History.d.ts +++ b/extension/schema/History.d.ts @@ -21,6 +21,7 @@ export type ManageOwnChatContext = boolean; export type Depth = number; export type Deleted = boolean; export type Active = boolean; +export type Logs = string[]; export type Timeline = HistoryNode[]; export type CurrentIndex = number; @@ -41,6 +42,7 @@ export interface HistoryNode { depth: Depth; deleted?: Deleted; active?: Active; + logs?: Logs; [k: string]: unknown; } export interface Step { diff --git a/extension/schema/HistoryNode.d.ts b/extension/schema/HistoryNode.d.ts index bc77be89..5ad32061 100644 --- a/extension/schema/HistoryNode.d.ts +++ b/extension/schema/HistoryNode.d.ts @@ -21,6 +21,7 @@ export type ManageOwnChatContext = boolean; export type Depth = number; export type Deleted = boolean; export type Active = boolean; +export type Logs = string[]; /** * A point in history, a list of which make up History @@ -31,6 +32,7 @@ export interface HistoryNode1 { depth: Depth; deleted?: Deleted; active?: Active; + logs?: Logs; [k: string]: unknown; } export interface Step { diff --git a/extension/src/activation/activate.ts b/extension/src/activation/activate.ts index 5c6ffa02..8ea08e89 100644 --- a/extension/src/activation/activate.ts +++ b/extension/src/activation/activate.ts @@ -36,22 +36,44 @@ export async function activateExtension(context: vscode.ExtensionContext) { }) .catch((e) => console.log("Error checking for extension updates: ", e)); - // Start the Python server - await new Promise((resolve, reject) => { - vscode.window.withProgress( - { - location: vscode.ProgressLocation.Notification, - title: - "Starting Continue Server... (it may take a minute to download Python packages)", - cancellable: false, - }, - async (progress, token) => { - await startContinuePythonServer(); - resolve(null); + // Wrap the server start logic in a new Promise + const serverStartPromise = new Promise((resolve, reject) => { + let serverStarted = false; + + // Start the server and set serverStarted to true when done + startContinuePythonServer().then(() => { + serverStarted = true; + resolve(null); + }); + + // Wait for 2 seconds + setTimeout(() => { + // If the server hasn't started after 2 seconds, show the notification + if (!serverStarted) { + vscode.window.withProgress( + { + location: vscode.ProgressLocation.Notification, + title: + "Starting Continue Server... (it may take a minute to download Python packages)", + cancellable: false, + }, + async (progress, token) => { + // Wait for the server to start + while (!serverStarted) { + await new Promise((innerResolve) => + setTimeout(innerResolve, 1000) + ); + } + return Promise.resolve(); + } + ); } - ); + }, 2000); }); + // Await the server start promise + await serverStartPromise; + // Register commands and providers sendTelemetryEvent(TelemetryEvent.ExtensionActivated); registerAllCodeLensProviders(context); diff --git a/extension/src/activation/environmentSetup.ts b/extension/src/activation/environmentSetup.ts index 69a3b75a..c341db39 100644 --- a/extension/src/activation/environmentSetup.ts +++ b/extension/src/activation/environmentSetup.ts @@ -39,7 +39,7 @@ async function retryThenFail( // Show corresponding error message depending on the platform let msg = - "Failed to set up Continue extension. Please email nate@continue.dev and we'll get this fixed ASAP!"; + "Failed to set up Continue extension. Please email hi@continue.dev and we'll get this fixed ASAP!"; try { switch (process.platform) { case "win32": diff --git a/extension/src/extension.ts b/extension/src/extension.ts index 6959ec05..f2e580a1 100644 --- a/extension/src/extension.ts +++ b/extension/src/extension.ts @@ -17,15 +17,5 @@ async function dynamicImportAndActivate(context: vscode.ExtensionContext) { } export function activate(context: vscode.ExtensionContext) { - // Only show progress if we have to setup - vscode.window.withProgress( - { - location: vscode.ProgressLocation.Notification, - title: "Setting up Continue extension...", - cancellable: false, - }, - async () => { - dynamicImportAndActivate(context); - } - ); + dynamicImportAndActivate(context); } diff --git a/schema/json/FullState.json b/schema/json/FullState.json index 5a7e9d10..62ed337b 100644 --- a/schema/json/FullState.json +++ b/schema/json/FullState.json @@ -120,6 +120,14 @@ "title": "Active", "default": true, "type": "boolean" + }, + "logs": { + "title": "Logs", + "default": [], + "type": "array", + "items": { + "type": "string" + } } }, "required": [ diff --git a/schema/json/History.json b/schema/json/History.json index ee797412..56415520 100644 --- a/schema/json/History.json +++ b/schema/json/History.json @@ -120,6 +120,14 @@ "title": "Active", "default": true, "type": "boolean" + }, + "logs": { + "title": "Logs", + "default": [], + "type": "array", + "items": { + "type": "string" + } } }, "required": [ diff --git a/schema/json/HistoryNode.json b/schema/json/HistoryNode.json index d0e12ac5..81e239b3 100644 --- a/schema/json/HistoryNode.json +++ b/schema/json/HistoryNode.json @@ -120,6 +120,14 @@ "title": "Active", "default": true, "type": "boolean" + }, + "logs": { + "title": "Logs", + "default": [], + "type": "array", + "items": { + "type": "string" + } } }, "required": [ -- cgit v1.2.3-70-g09d2