From 89bc7de85fdf1c8a4bbc35c29ef92e7a1044110a 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 +++++++++++++++++++--------- 1 file changed, 41 insertions(+), 18 deletions(-) (limited to 'extension/src/activation') 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()) { -- cgit v1.2.3-70-g09d2 From c8ca794c0504304e41b5d7b310939b54bbe96099 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') 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 4d5f33e8984f3a62a13fbe262fead0a8632eaf27 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') 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 98a0911d3bf071f119e25889796ecc1bd80032df 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') 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 14654a3db55dd73b0a099d4acbca6494c612d3d3 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') 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 176087be502ce6663c3b3128352a69f8c7409666 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') 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 57e504452e6d13f903c384544fd6a3836e3ddb99 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') 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 8e96e0ee4a1c251d20577769bfcb76dbc7b043a2 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') 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 9af39a67829a6770b93ffdaa6ea70af3125c7daf Mon Sep 17 00:00:00 2001 From: Nate Sesti Date: Sun, 16 Jul 2023 12:49:47 -0700 Subject: feat: :sparkles: Continue Quick Fix --- extension/package.json | 5 +++ extension/src/activation/activate.ts | 2 ++ extension/src/commands.ts | 7 +++++ extension/src/lang-server/codeActions.ts | 53 ++++++++++++++++++++++++++++++++ 4 files changed, 67 insertions(+) create mode 100644 extension/src/lang-server/codeActions.ts (limited to 'extension/src/activation') diff --git a/extension/package.json b/extension/package.json index 9fe38f7f..ccc3a679 100644 --- a/extension/package.json +++ b/extension/package.json @@ -106,6 +106,11 @@ "command": "continue.quickTextEntry", "category": "Continue", "title": "Quick Text Entry" + }, + { + "command": "continue.quickFix", + "category": "Continue", + "title": "Quick Fix" } ], "keybindings": [ diff --git a/extension/src/activation/activate.ts b/extension/src/activation/activate.ts index cd885b12..5c6ffa02 100644 --- a/extension/src/activation/activate.ts +++ b/extension/src/activation/activate.ts @@ -10,6 +10,7 @@ import { startContinuePythonServer, } from "./environmentSetup"; import fetch from "node-fetch"; +import registerQuickFixProvider from "../lang-server/codeActions"; // import { CapturedTerminal } from "../terminal/terminalEmulator"; const PACKAGE_JSON_RAW_GITHUB_URL = @@ -55,6 +56,7 @@ export async function activateExtension(context: vscode.ExtensionContext) { sendTelemetryEvent(TelemetryEvent.ExtensionActivated); registerAllCodeLensProviders(context); registerAllCommands(context); + registerQuickFixProvider(); // Initialize IDE Protocol Client const serverUrl = getContinueServerUrl(); diff --git a/extension/src/commands.ts b/extension/src/commands.ts index 888f01ed..2b7f4c0c 100644 --- a/extension/src/commands.ts +++ b/extension/src/commands.ts @@ -34,6 +34,13 @@ const commandsMap: { [command: string]: (...args: any) => any } = { "continue.rejectDiff": rejectDiffCommand, "continue.acceptAllSuggestions": acceptAllSuggestionsCommand, "continue.rejectAllSuggestions": rejectAllSuggestionsCommand, + "continue.quickFix": async (message: string, code: string, edit: boolean) => { + ideProtocolClient.sendMainUserInput( + `${ + edit ? "/edit " : "" + }${code}\n\nHow do I fix this problem in the above code?: ${message}` + ); + }, "continue.focusContinueInput": async () => { if (focusedOnContinueInput) { vscode.commands.executeCommand("workbench.action.focusActiveEditorGroup"); diff --git a/extension/src/lang-server/codeActions.ts b/extension/src/lang-server/codeActions.ts new file mode 100644 index 00000000..07cf5f4e --- /dev/null +++ b/extension/src/lang-server/codeActions.ts @@ -0,0 +1,53 @@ +import * as vscode from "vscode"; + +class ContinueQuickFixProvider implements vscode.CodeActionProvider { + public static readonly providedCodeActionKinds = [ + vscode.CodeActionKind.QuickFix, + ]; + + provideCodeActions( + document: vscode.TextDocument, + range: vscode.Range | vscode.Selection, + context: vscode.CodeActionContext, + token: vscode.CancellationToken + ): vscode.ProviderResult<(vscode.Command | vscode.CodeAction)[]> { + if (context.diagnostics.length === 0) { + return []; + } + + const createQuickFix = (edit: boolean) => { + const diagnostic = context.diagnostics[0]; + const quickFix = new vscode.CodeAction( + edit ? "Fix with Continue" : "Ask Continue", + vscode.CodeActionKind.QuickFix + ); + quickFix.isPreferred = false; + const surroundingRange = new vscode.Range( + range.start.translate(-3, 0), + range.end.translate(3, 0) + ); + quickFix.command = { + command: "continue.quickFix", + title: "Continue Quick Fix", + arguments: [ + diagnostic.message, + document.getText(surroundingRange), + edit, + ], + }; + return quickFix; + }; + return [createQuickFix(true), createQuickFix(false)]; + } +} + +export default function registerQuickFixProvider() { + // In your extension's activate function: + vscode.languages.registerCodeActionsProvider( + { language: "*" }, + new ContinueQuickFixProvider(), + { + providedCodeActionKinds: ContinueQuickFixProvider.providedCodeActionKinds, + } + ); +} -- cgit v1.2.3-70-g09d2 From 06cd33b8baad50e444f1ef78fb22e7b58294befe 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') 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 54c975f1454b353590435c262d558a71e6013865 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') 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 From b2dba8d5a4a8852fcea8bcd724e2f17d1d909a6e Mon Sep 17 00:00:00 2001 From: Nate Sesti Date: Tue, 18 Jul 2023 16:31:39 -0700 Subject: CONTRIBUTING.md --- CONTRIBUTING.md | 94 +++++++++++++++++++++ continuedev/src/continuedev/core/main.py | 6 +- extension/react-app/src/App.tsx | 8 +- .../src/hooks/AbstractContinueGUIClientProtocol.ts | 35 ++++++++ .../src/hooks/ContinueGUIClientProtocol.ts | 93 +++++++++++++++++---- .../react-app/src/hooks/useContinueGUIProtocol.ts | 95 ---------------------- extension/react-app/src/hooks/useWebsocket.ts | 2 +- extension/src/activation/activate.ts | 14 +--- extension/src/continueIdeClient.ts | 10 +++ 9 files changed, 222 insertions(+), 135 deletions(-) create mode 100644 CONTRIBUTING.md create mode 100644 extension/react-app/src/hooks/AbstractContinueGUIClientProtocol.ts delete mode 100644 extension/react-app/src/hooks/useContinueGUIProtocol.ts (limited to 'extension/src/activation') diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..7e49dc2d --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,94 @@ +# Contributing to Continue + +## Table of Contents + +- [Continue Architecture](#continue-architecture) +- [Core Concepts](#core-concepts) + - [Step](#step) +- [Continue VS Code Client](#continue-vs-code-client) +- [Continue IDE Websockets Protocol](#continue-ide-websockets-protocol) +- [Continue GUI Websockets Protocol](#continue-gui-websockets-protocol) +- [Ways to Contribute](#ways-to-contribute) + - [Report Bugs](#report-bugs) + - [Suggest Enhancements](#suggest-enhancements) + - [Updating / Improving Documentation](#updating--improving-documentation) + +## Continue Architecture + +Continue consists of 3 components, designed so that Continue can easily be extended to work in any IDE: + +1. **Continue Server** - The Continue Server is responsible for keeping state, running the autopilot loop which takes actions, and communicating between the IDE and GUI. + +2. **Continue IDE Client** - The Continue IDE Client is a plugin for the IDE which implements the Continue IDE Protocol. This allows the server to request actions to be taken within the IDE, for example if `sdk.ide.setFileOpen("main.py")` is called on the server, it will communicate over websocketes with the IDE, which will open the file `main.py`. The first IDE Client we have built is for VS Code, but we plan to build clients for other IDEs in the future. The IDE Client must 1. implement the websockets protocol, as is done [here](./extension/src/continueIdeClient.ts) for VS Code and 2. launch the Continue Server, like [here](./extension/src/activation/environmentSetup.ts), and 3. display the Continue GUI in a sidebar, like [here](./extension/src/debugPanel.ts). + +3. **Continue GUI** - The Continue GUI is a React application that gives the user control over Continue. It displays the history of Steps, shows what context is included in the current Step, and lets the users enter natural language or slash commands to initiate new Steps. The GUI communicates with the Continue Server over its own websocket connection + +It is important that the IDE Client and GUI never communicate except when the IDE Client initially sets up the GUI. This ensures that the server is the source-of-truth for state, and that we can easily extend Continue to work in other IDEs. + +![Continue Architecture](https://continue.dev/docs/assets/images/continue-architecture-146a90742e25f6524452c74fe44fa2a0.png) + +## Core Concepts + +All of Continue's logic happens inside of the server, and it is built around a few core concepts. Most of these are Pydantic Models defined in [core/main.py](./continuedev/src/continuedev/core/main.py). + +### `Step` + +Everything in Continue is a "Step". The `Step` class defines 2 methods: + +1. `async def run(self, sdk: ContinueSDK) -> Coroutine[Observation, None, None]` - This method defines what happens when the Step is run. It has access to the Continue SDK, which lets you take actions in the IDE, call LLMs, run nested Steps, and more. Optionally, a Step can return an `Observation` object, which a `Policy` can use to make decisions about what to do next. + +2. `async def describe(self, models: Models) -> Coroutine[str, None, None]` - After each Step is run, this method is called to asynchronously generate a summary title for the step. A `Models` object is passed so that you have access to LLMs to summarize for you. + +Steps are designed to be composable, so that you can easily build new Steps by combining existing ones. And because they are Pydantic models, they can instantly be used as tools useable by an LLM, for example with OpenAI's function-calling functionality (see [ChatWithFunctions](./continuedev/src/continuedev/steps/chat.py) for an example of this). + +Some of the most commonly used Steps are: + +- [`SimpleChatStep`](./continuedev/src/continuedev/steps/chat.py) - This is the default Step that is run when the user enters natural language input. It takes the user's input and runs it through the default LLM, then displays the result in the GUI. + +- [`EditHighlightedCodeStep`](./continuedev/src/continuedev/steps/core/core.py) - This is the Step run when a user highlights code, enters natural language, and presses CMD/CTRL+ENTER, or uses the slash command '/edit'. It opens a side-by-side diff editor, where updated code is streamed to fulfil the user's request. + +### `Autopilot` + +### `Observation` + +### `Policy` + +### Continue VS Code Client + +The starting point for the VS Code extension is [activate.ts](./extension/src/activation/activate.ts). The `activateExtension` function here will: + +1. Check whether the current version of the extension is up-to-date and, if not, display a notification + +2. Initialize the Continue IDE Client and establish a connection with the Continue Server + +3. Load the Continue GUI in the sidebar of the IDE and begin a new session + +### Continue IDE Websockets Protocol + +On the IDE side, this is implemented in [continueIdeClient.ts](./extension/src/continueIdeClient.ts). On the server side, this is implemented in [ide.py](./continuedev/src/continuedev/server/ide.py). You can see [ide_protocol.py](./continuedev/src/continuedev/server/ide_protocol.py) for the protocol definition. + +### Continue GUI Websockets Protocol + +On the GUI side, this is implemented in [ContinueGUIClientProtocol.ts](./extension/react-app/src/hooks/ContinueGUIClientProtocol.ts). On the server side, this is implemented in [gui.py](./continuedev/src/continuedev/server/gui.py). You can see [gui_protocol.py](./continuedev/src/continuedev/server/gui_protocol.py) or [AbstractContinueGUIClientProtocol.ts](./extension/react-app/src/hooks/AbstractContinueGUIClientProtocol.ts) for the protocol definition. + +When state is updated on the server, we currently send the entirety of the object over websockets to the GUI. This will of course have to be improved soon. The state object, `FullState`, is defined in [core/main.py](./continuedev/src/continuedev/core/main.py) and includes: + +- `history`, a record of previously run Steps. Displayed in order in the sidebar. +- `active`, whether the autopilot is currently running a step. Displayed as a loader while step is running. +- `user_input_queue`, the queue of user inputs that have not yet been processed due to waiting for previous Steps to complete. Displayed below the `active` loader until popped from the queue. +- `default_model`, the default model used for completions. Displayed as a toggleable button on the bottom of the GUI. +- `highlighted_ranges`, the ranges of code that have been selected to include as context. Displayed just above the main text input. +- `slash_commands`, the list of available slash commands. Displayed in the main text input dropdown. +- `adding_highlighted_code`, whether highlighting of new code for context is locked. Displayed as a button adjacent to `highlighted_ranges`. + +Updates are sent with `await sdk.update_ui()` when needed explicitly or `await autopilot.update_subscribers()` automatically between each Step. The GUI can listen for state updates with `ContinueGUIClientProtocol.onStateUpdate()`. + +## Ways to Contribute + +### Report Bugs + +### Suggest Enhancements + +### Updating / Improving Documentation + +Continue is continuously improving, but a feature isn't complete until it is reflected in the documentation! diff --git a/continuedev/src/continuedev/core/main.py b/continuedev/src/continuedev/core/main.py index 5931d978..50d01f8d 100644 --- a/continuedev/src/continuedev/core/main.py +++ b/continuedev/src/continuedev/core/main.py @@ -259,10 +259,8 @@ class Step(ContinueBaseModel): def dict(self, *args, **kwargs): d = super().dict(*args, **kwargs) - if self.description is not None: - d["description"] = self.description - else: - d["description"] = "" + # Make sure description is always a string + d["description"] = self.description or "" return d @validator("name", pre=True, always=True) diff --git a/extension/react-app/src/App.tsx b/extension/react-app/src/App.tsx index c9bd42e0..aa462171 100644 --- a/extension/react-app/src/App.tsx +++ b/extension/react-app/src/App.tsx @@ -2,7 +2,7 @@ import DebugPanel from "./components/DebugPanel"; import GUI from "./pages/gui"; import { createContext } from "react"; import useContinueGUIProtocol from "./hooks/useWebsocket"; -import ContinueGUIClientProtocol from "./hooks/useContinueGUIProtocol"; +import ContinueGUIClientProtocol from "./hooks/ContinueGUIClientProtocol"; export const GUIClientContext = createContext< ContinueGUIClientProtocol | undefined @@ -13,11 +13,7 @@ function App() { return ( - , title: "GUI" } - ]} - /> + , title: "GUI" }]} /> ); } diff --git a/extension/react-app/src/hooks/AbstractContinueGUIClientProtocol.ts b/extension/react-app/src/hooks/AbstractContinueGUIClientProtocol.ts new file mode 100644 index 00000000..6c0df8fc --- /dev/null +++ b/extension/react-app/src/hooks/AbstractContinueGUIClientProtocol.ts @@ -0,0 +1,35 @@ +abstract class AbstractContinueGUIClientProtocol { + abstract sendMainInput(input: string): void; + + abstract reverseToIndex(index: number): void; + + abstract sendRefinementInput(input: string, index: number): void; + + abstract sendStepUserInput(input: string, index: number): void; + + abstract onStateUpdate(state: any): void; + + abstract onAvailableSlashCommands( + callback: (commands: { name: string; description: string }[]) => void + ): void; + + abstract changeDefaultModel(model: string): void; + + abstract sendClear(): void; + + abstract retryAtIndex(index: number): void; + + abstract deleteAtIndex(index: number): void; + + abstract deleteContextAtIndices(indices: number[]): void; + + abstract setEditingAtIndices(indices: number[]): void; + + abstract setPinnedAtIndices(indices: number[]): void; + + abstract toggleAddingHighlightedCode(): void; + + abstract showLogsAtIndex(index: number): void; +} + +export default AbstractContinueGUIClientProtocol; diff --git a/extension/react-app/src/hooks/ContinueGUIClientProtocol.ts b/extension/react-app/src/hooks/ContinueGUIClientProtocol.ts index 6c0df8fc..7d6c2a71 100644 --- a/extension/react-app/src/hooks/ContinueGUIClientProtocol.ts +++ b/extension/react-app/src/hooks/ContinueGUIClientProtocol.ts @@ -1,35 +1,92 @@ -abstract class AbstractContinueGUIClientProtocol { - abstract sendMainInput(input: string): void; +import AbstractContinueGUIClientProtocol from "./AbstractContinueGUIClientProtocol"; +import { Messenger, WebsocketMessenger } from "./messenger"; +import { VscodeMessenger } from "./vscodeMessenger"; - abstract reverseToIndex(index: number): void; +class ContinueGUIClientProtocol extends AbstractContinueGUIClientProtocol { + messenger: Messenger; + // Server URL must contain the session ID param + serverUrlWithSessionId: string; - abstract sendRefinementInput(input: string, index: number): void; + constructor( + serverUrlWithSessionId: string, + useVscodeMessagePassing: boolean + ) { + super(); + this.serverUrlWithSessionId = serverUrlWithSessionId; + this.messenger = useVscodeMessagePassing + ? new VscodeMessenger(serverUrlWithSessionId) + : new WebsocketMessenger(serverUrlWithSessionId); + } - abstract sendStepUserInput(input: string, index: number): void; + sendMainInput(input: string) { + this.messenger.send("main_input", { input }); + } - abstract onStateUpdate(state: any): void; + reverseToIndex(index: number) { + this.messenger.send("reverse_to_index", { index }); + } - abstract onAvailableSlashCommands( + sendRefinementInput(input: string, index: number) { + this.messenger.send("refinement_input", { input, index }); + } + + sendStepUserInput(input: string, index: number) { + this.messenger.send("step_user_input", { input, index }); + } + + onStateUpdate(callback: (state: any) => void) { + this.messenger.onMessageType("state_update", (data: any) => { + if (data.state) { + callback(data.state); + } + }); + } + + onAvailableSlashCommands( callback: (commands: { name: string; description: string }[]) => void - ): void; + ) { + this.messenger.onMessageType("available_slash_commands", (data: any) => { + if (data.commands) { + callback(data.commands); + } + }); + } - abstract changeDefaultModel(model: string): void; + changeDefaultModel(model: string) { + this.messenger.send("change_default_model", { model }); + } - abstract sendClear(): void; + sendClear() { + this.messenger.send("clear_history", {}); + } - abstract retryAtIndex(index: number): void; + retryAtIndex(index: number) { + this.messenger.send("retry_at_index", { index }); + } - abstract deleteAtIndex(index: number): void; + deleteAtIndex(index: number) { + this.messenger.send("delete_at_index", { index }); + } - abstract deleteContextAtIndices(indices: number[]): void; + deleteContextAtIndices(indices: number[]) { + this.messenger.send("delete_context_at_indices", { indices }); + } - abstract setEditingAtIndices(indices: number[]): void; + setEditingAtIndices(indices: number[]) { + this.messenger.send("set_editing_at_indices", { indices }); + } - abstract setPinnedAtIndices(indices: number[]): void; + setPinnedAtIndices(indices: number[]) { + this.messenger.send("set_pinned_at_indices", { indices }); + } - abstract toggleAddingHighlightedCode(): void; + toggleAddingHighlightedCode(): void { + this.messenger.send("toggle_adding_highlighted_code", {}); + } - abstract showLogsAtIndex(index: number): void; + showLogsAtIndex(index: number): void { + this.messenger.send("show_logs_at_index", { index }); + } } -export default AbstractContinueGUIClientProtocol; +export default ContinueGUIClientProtocol; diff --git a/extension/react-app/src/hooks/useContinueGUIProtocol.ts b/extension/react-app/src/hooks/useContinueGUIProtocol.ts deleted file mode 100644 index fef5b2e1..00000000 --- a/extension/react-app/src/hooks/useContinueGUIProtocol.ts +++ /dev/null @@ -1,95 +0,0 @@ -import AbstractContinueGUIClientProtocol from "./ContinueGUIClientProtocol"; -// import { Messenger, WebsocketMessenger } from "../../../src/util/messenger"; -import { Messenger, WebsocketMessenger } from "./messenger"; -import { VscodeMessenger } from "./vscodeMessenger"; - -class ContinueGUIClientProtocol extends AbstractContinueGUIClientProtocol { - messenger: Messenger; - // Server URL must contain the session ID param - serverUrlWithSessionId: string; - - constructor( - serverUrlWithSessionId: string, - useVscodeMessagePassing: boolean - ) { - super(); - this.serverUrlWithSessionId = serverUrlWithSessionId; - if (useVscodeMessagePassing) { - this.messenger = new VscodeMessenger(serverUrlWithSessionId); - } else { - this.messenger = new WebsocketMessenger(serverUrlWithSessionId); - } - } - - sendMainInput(input: string) { - this.messenger.send("main_input", { input }); - } - - reverseToIndex(index: number) { - this.messenger.send("reverse_to_index", { index }); - } - - sendRefinementInput(input: string, index: number) { - this.messenger.send("refinement_input", { input, index }); - } - - sendStepUserInput(input: string, index: number) { - this.messenger.send("step_user_input", { input, index }); - } - - onStateUpdate(callback: (state: any) => void) { - this.messenger.onMessageType("state_update", (data: any) => { - if (data.state) { - callback(data.state); - } - }); - } - - onAvailableSlashCommands( - callback: (commands: { name: string; description: string }[]) => void - ) { - this.messenger.onMessageType("available_slash_commands", (data: any) => { - if (data.commands) { - callback(data.commands); - } - }); - } - - changeDefaultModel(model: string) { - this.messenger.send("change_default_model", { model }); - } - - sendClear() { - this.messenger.send("clear_history", {}); - } - - retryAtIndex(index: number) { - this.messenger.send("retry_at_index", { index }); - } - - deleteAtIndex(index: number) { - this.messenger.send("delete_at_index", { index }); - } - - deleteContextAtIndices(indices: number[]) { - this.messenger.send("delete_context_at_indices", { indices }); - } - - setEditingAtIndices(indices: number[]) { - this.messenger.send("set_editing_at_indices", { indices }); - } - - setPinnedAtIndices(indices: number[]) { - this.messenger.send("set_pinned_at_indices", { indices }); - } - - toggleAddingHighlightedCode(): void { - this.messenger.send("toggle_adding_highlighted_code", {}); - } - - showLogsAtIndex(index: number): void { - this.messenger.send("show_logs_at_index", { index }); - } -} - -export default ContinueGUIClientProtocol; diff --git a/extension/react-app/src/hooks/useWebsocket.ts b/extension/react-app/src/hooks/useWebsocket.ts index e762666f..6b36be97 100644 --- a/extension/react-app/src/hooks/useWebsocket.ts +++ b/extension/react-app/src/hooks/useWebsocket.ts @@ -1,7 +1,7 @@ import React, { useEffect, useState } from "react"; import { RootStore } from "../redux/store"; import { useSelector } from "react-redux"; -import ContinueGUIClientProtocol from "./useContinueGUIProtocol"; +import ContinueGUIClientProtocol from "./ContinueGUIClientProtocol"; import { postVscMessage } from "../vscode"; function useContinueGUIProtocol(useVscodeMessagePassing: boolean = true) { diff --git a/extension/src/activation/activate.ts b/extension/src/activation/activate.ts index 8ea08e89..a7f6c55b 100644 --- a/extension/src/activation/activate.ts +++ b/extension/src/activation/activate.ts @@ -36,8 +36,8 @@ export async function activateExtension(context: vscode.ExtensionContext) { }) .catch((e) => console.log("Error checking for extension updates: ", e)); - // Wrap the server start logic in a new Promise - const serverStartPromise = new Promise((resolve, reject) => { + // Start the server and display loader if taking > 2 seconds + await new Promise((resolve) => { let serverStarted = false; // Start the server and set serverStarted to true when done @@ -71,15 +71,6 @@ export async function activateExtension(context: vscode.ExtensionContext) { }, 2000); }); - // Await the server start promise - await serverStartPromise; - - // Register commands and providers - sendTelemetryEvent(TelemetryEvent.ExtensionActivated); - registerAllCodeLensProviders(context); - registerAllCommands(context); - registerQuickFixProvider(); - // Initialize IDE Protocol Client const serverUrl = getContinueServerUrl(); ideProtocolClient = new IdeProtocolClient( @@ -87,6 +78,7 @@ export async function activateExtension(context: vscode.ExtensionContext) { context ); + // Register Continue GUI as sidebar webview, and beging a new session { const sessionIdPromise = await ideProtocolClient.getSessionId(); const provider = new ContinueGUIWebviewViewProvider(sessionIdPromise); diff --git a/extension/src/continueIdeClient.ts b/extension/src/continueIdeClient.ts index 14a8df72..a1370a01 100644 --- a/extension/src/continueIdeClient.ts +++ b/extension/src/continueIdeClient.ts @@ -16,6 +16,10 @@ import fs = require("fs"); import { WebsocketMessenger } from "./util/messenger"; import { diffManager } from "./diffs"; import path = require("path"); +import { sendTelemetryEvent, TelemetryEvent } from "./telemetry"; +import { registerAllCodeLensProviders } from "./lang-server/codeLens"; +import { registerAllCommands } from "./commands"; +import registerQuickFixProvider from "./lang-server/codeActions"; const continueVirtualDocumentScheme = "continue"; @@ -76,6 +80,12 @@ class IdeProtocolClient { this._serverUrl = serverUrl; this._newWebsocketMessenger(); + // Register commands and providers + sendTelemetryEvent(TelemetryEvent.ExtensionActivated); + registerAllCodeLensProviders(context); + registerAllCommands(context); + registerQuickFixProvider(); + // Setup listeners for any file changes in open editors // vscode.workspace.onDidChangeTextDocument((event) => { // if (this._makingEdit === 0) { -- cgit v1.2.3-70-g09d2 From d465766da25d89be6ab71e50cbe30725caee59c5 Mon Sep 17 00:00:00 2001 From: Ty Dunn Date: Fri, 21 Jul 2023 16:27:25 -0500 Subject: python3 --> python --- extension/src/activation/environmentSetup.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'extension/src/activation') diff --git a/extension/src/activation/environmentSetup.ts b/extension/src/activation/environmentSetup.ts index c341db39..94481430 100644 --- a/extension/src/activation/environmentSetup.ts +++ b/extension/src/activation/environmentSetup.ts @@ -139,7 +139,7 @@ export async function getPythonPipCommands() { if (!versionExists) { vscode.window.showErrorMessage( - "Continue requires Python3 version 3.8 or greater. Please update your Python3 installation, reload VS Code, and try again." + "Continue requires Python version 3.8 or greater. Please update your Python installation, reload VS Code, and try again." ); throw new Error("Python3.8 or greater is not installed."); } -- cgit v1.2.3-70-g09d2 From 2a07966d2bc40d1b3cf2b8fbe950edc27aef5a58 Mon Sep 17 00:00:00 2001 From: Nate Sesti Date: Fri, 21 Jul 2023 19:55:08 -0700 Subject: remove Segment telemetry from React --- extension/src/activation/activate.ts | 1 - extension/src/activation/environmentSetup.ts | 17 +-------- extension/src/continueIdeClient.ts | 20 +++++------ extension/src/suggestions.ts | 3 -- extension/src/telemetry.ts | 53 ---------------------------- 5 files changed, 11 insertions(+), 83 deletions(-) delete mode 100644 extension/src/telemetry.ts (limited to 'extension/src/activation') diff --git a/extension/src/activation/activate.ts b/extension/src/activation/activate.ts index a7f6c55b..65f026d8 100644 --- a/extension/src/activation/activate.ts +++ b/extension/src/activation/activate.ts @@ -1,7 +1,6 @@ import * as vscode from "vscode"; import { registerAllCommands } from "../commands"; import { registerAllCodeLensProviders } from "../lang-server/codeLens"; -import { sendTelemetryEvent, TelemetryEvent } from "../telemetry"; import IdeProtocolClient from "../continueIdeClient"; import { getContinueServerUrl } from "../bridge"; import { ContinueGUIWebviewViewProvider } from "../debugPanel"; diff --git a/extension/src/activation/environmentSetup.ts b/extension/src/activation/environmentSetup.ts index 94481430..5a9345a6 100644 --- a/extension/src/activation/environmentSetup.ts +++ b/extension/src/activation/environmentSetup.ts @@ -9,7 +9,6 @@ import fetch from "node-fetch"; import * as vscode from "vscode"; 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. 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."; @@ -57,9 +56,6 @@ async function retryThenFail( vscode.window.showErrorMessage(msg); } - sendTelemetryEvent(TelemetryEvent.ExtensionSetupError, { - error: e.message, - }); throw e; } } @@ -83,12 +79,6 @@ async function runCommand(cmd: string): Promise<[string, string | undefined]> { stdout = ""; } - if (stderr) { - sendTelemetryEvent(TelemetryEvent.ExtensionSetupError, { - error: stderr, - }); - } - return [stdout, stderr]; } @@ -480,16 +470,11 @@ export async function startContinuePythonServer() { console.log("Successfully started Continue python server"); resolve(null); } else if (data.includes("ERROR") || data.includes("Traceback")) { - sendTelemetryEvent(TelemetryEvent.ExtensionSetupError, { - error: data, - }); + console.log("Error starting Continue python server: ", data); } }); child.on("error", (error: any) => { console.log(`error: ${error.message}`); - sendTelemetryEvent(TelemetryEvent.ExtensionSetupError, { - error: error.message, - }); }); // Write the current version of vscode to a file called server_version.txt diff --git a/extension/src/continueIdeClient.ts b/extension/src/continueIdeClient.ts index 3a42e773..802afc1d 100644 --- a/extension/src/continueIdeClient.ts +++ b/extension/src/continueIdeClient.ts @@ -16,7 +16,6 @@ import fs = require("fs"); import { WebsocketMessenger } from "./util/messenger"; import { diffManager } from "./diffs"; import path = require("path"); -import { sendTelemetryEvent, TelemetryEvent } from "./telemetry"; import { registerAllCodeLensProviders } from "./lang-server/codeLens"; import { registerAllCommands } from "./commands"; import registerQuickFixProvider from "./lang-server/codeActions"; @@ -81,7 +80,6 @@ class IdeProtocolClient { this._newWebsocketMessenger(); // Register commands and providers - sendTelemetryEvent(TelemetryEvent.ExtensionActivated); registerAllCodeLensProviders(context); registerAllCommands(context); registerQuickFixProvider(); @@ -171,14 +169,16 @@ class IdeProtocolClient { // Listen for changes to settings.json vscode.workspace.onDidChangeConfiguration((event) => { if (event.affectsConfiguration("continue")) { - vscode.window.showInformationMessage( - "Please reload VS Code for changes to Continue settings to take effect.", - "Reload" - ).then((selection) => { - if (selection === "Reload") { - vscode.commands.executeCommand("workbench.action.reloadWindow"); - } - }); + vscode.window + .showInformationMessage( + "Please reload VS Code for changes to Continue settings to take effect.", + "Reload" + ) + .then((selection) => { + if (selection === "Reload") { + vscode.commands.executeCommand("workbench.action.reloadWindow"); + } + }); } }); } diff --git a/extension/src/suggestions.ts b/extension/src/suggestions.ts index c2373223..5c2b8860 100644 --- a/extension/src/suggestions.ts +++ b/extension/src/suggestions.ts @@ -1,5 +1,4 @@ import * as vscode from "vscode"; -import { sendTelemetryEvent, TelemetryEvent } from "./telemetry"; import { openEditorAndRevealRange } from "./util/vscode"; import { translate } from "./util/vscode"; import { registerAllCodeLensProviders } from "./lang-server/codeLens"; @@ -244,7 +243,6 @@ function selectSuggestion( } export function acceptSuggestionCommand(key: SuggestionRanges | null = null) { - sendTelemetryEvent(TelemetryEvent.SuggestionAccepted); selectSuggestion("selected", key); } @@ -271,7 +269,6 @@ export function rejectAllSuggestionsCommand() { export async function rejectSuggestionCommand( key: SuggestionRanges | null = null ) { - sendTelemetryEvent(TelemetryEvent.SuggestionRejected); selectSuggestion("old", key); } diff --git a/extension/src/telemetry.ts b/extension/src/telemetry.ts deleted file mode 100644 index db5cb8ca..00000000 --- a/extension/src/telemetry.ts +++ /dev/null @@ -1,53 +0,0 @@ -import * as Segment from "@segment/analytics-node"; -import * as vscode from "vscode"; - -// Setup Segment -const SEGMENT_WRITE_KEY = "57yy2uYXH2bwMuy7djm9PorfFlYqbJL1"; -const analytics = new Segment.Analytics({ writeKey: SEGMENT_WRITE_KEY }); -analytics.identify({ - userId: vscode.env.machineId, - // traits: { - // name: "Michael Bolton", - // email: "mbolton@example.com", - // createdAt: new Date("2014-06-14T02:00:19.467Z"), - // }, -}); - -// Enum of telemetry events -export enum TelemetryEvent { - // Extension has been activated - ExtensionActivated = "ExtensionActivated", - // Suggestion has been accepted - SuggestionAccepted = "SuggestionAccepted", - // Suggestion has been rejected - SuggestionRejected = "SuggestionRejected", - // Queried universal prompt - UniversalPromptQuery = "UniversalPromptQuery", - // `Explain Code` button clicked - ExplainCode = "ExplainCode", - // `Generate Ideas` button clicked - GenerateIdeas = "GenerateIdeas", - // `Suggest Fix` button clicked - SuggestFix = "SuggestFix", - // `Create Test` button clicked - CreateTest = "CreateTest", - // `AutoDebug This Test` button clicked - AutoDebugThisTest = "AutoDebugThisTest", - // Command run to generate docstring - GenerateDocstring = "GenerateDocstring", - // Error setting up the extension - ExtensionSetupError = "ExtensionSetupError", -} - -export function sendTelemetryEvent( - event: TelemetryEvent, - properties?: Record -) { - if (!vscode.env.isTelemetryEnabled) return; - - analytics.track({ - event, - userId: vscode.env.machineId, - properties, - }); -} -- cgit v1.2.3-70-g09d2