@@ -10,7 +10,6 @@ import {
1010 ModelRole ,
1111} from "@continuedev/config-yaml" ;
1212import * as JSONC from "comment-json" ;
13- import * as tar from "tar" ;
1413
1514import {
1615 BrowserSerializedContinueConfig ,
@@ -696,102 +695,43 @@ function escapeSpacesInPath(p: string): string {
696695 return p . replace ( / / g, "\\ " ) ;
697696}
698697
699- async function handleEsbuildInstallation ( ide : IDE , ideType : IdeType ) {
700- // JetBrains is currently the only IDE that we've reached the plugin size limit and
701- // therefore need to install esbuild manually to reduce the size
702- if ( ideType !== "jetbrains" ) {
703- return ;
704- }
705-
706- const globalContext = new GlobalContext ( ) ;
707- if ( globalContext . get ( "hasDismissedConfigTsNoticeJetBrains" ) ) {
708- return ;
709- }
710-
711- const esbuildPath = getEsbuildBinaryPath ( ) ;
712-
713- if ( fs . existsSync ( esbuildPath ) ) {
714- return ;
715- }
716-
717- console . debug ( "No esbuild binary detected" ) ;
718-
719- const shouldInstall = await promptEsbuildInstallation ( ide ) ;
720-
721- if ( shouldInstall ) {
722- await downloadAndInstallEsbuild ( ide ) ;
723- }
724- }
725-
726- async function promptEsbuildInstallation ( ide : IDE ) : Promise < boolean > {
727- const installMsg = "Install esbuild" ;
728- const dismissMsg = "Dismiss" ;
729-
730- const res = await ide . showToast (
731- "warning" ,
732- "You're using a custom 'config.ts' file, which requires 'esbuild' to be installed. Would you like to install it now?" ,
733- dismissMsg ,
734- installMsg ,
735- ) ;
736-
737- if ( res === dismissMsg ) {
738- const globalContext = new GlobalContext ( ) ;
739- globalContext . update ( "hasDismissedConfigTsNoticeJetBrains" , true ) ;
740- return false ;
741- }
742-
743- return res === installMsg ;
744- }
745-
746- /**
747- * The download logic is adapted from here: https://esbuild.github.io/getting-started/#download-a-build
748- */
749- async function downloadAndInstallEsbuild ( ide : IDE ) {
750- const esbuildPath = getEsbuildBinaryPath ( ) ;
751- const tempDir = fs . mkdtempSync ( path . join ( os . tmpdir ( ) , "esbuild-" ) ) ;
698+ async function handleEsbuildInstallation (
699+ ide : IDE ,
700+ _ideType : IdeType ,
701+ ) : Promise < boolean > {
702+ // Only check when config.ts is going to be used; never auto-install.
703+ const installCmd = "npm i [email protected] --prefix ~/.continue" ; 752704
705+ // Try to detect a user-installed esbuild (normal resolution)
753706 try {
754- const target = `${ os . platform ( ) } -${ os . arch ( ) } ` ;
755- const version = "0.19.11" ;
756- const url = `https://registry.npmjs.org/@esbuild/${ target } /-/${ target } -${ version } .tgz` ;
757- const tgzPath = path . join ( tempDir , `esbuild-${ version } .tgz` ) ;
758-
759- console . debug ( `Downloading esbuild from: ${ url } ` ) ;
760- execSync ( `curl -fo "${ tgzPath } " "${ url } "` ) ;
761-
762- console . debug ( `Extracting tgz file to: ${ tempDir } ` ) ;
763- await tar . x ( {
764- file : tgzPath ,
765- cwd : tempDir ,
766- strip : 2 , // Remove the top two levels of directories
767- } ) ;
768-
769- // Ensure the destination directory exists
770- const destDir = path . dirname ( esbuildPath ) ;
771- if ( ! fs . existsSync ( destDir ) ) {
772- fs . mkdirSync ( destDir , { recursive : true } ) ;
773- }
774-
775- // Move the file
776- const extractedBinaryPath = path . join ( tempDir , "esbuild" ) ;
777- fs . renameSync ( extractedBinaryPath , esbuildPath ) ;
778-
779- // Ensure the binary is executable (not needed on Windows)
780- if ( os . platform ( ) !== "win32" ) {
781- fs . chmodSync ( esbuildPath , 0o755 ) ;
707+ await import ( "esbuild" ) ;
708+ return true ; // available
709+ } catch {
710+ // Try resolving from ~/.continue/node_modules as a courtesy
711+ try {
712+ const userEsbuild = path . join (
713+ os . homedir ( ) ,
714+ ".continue" ,
715+ "node_modules" ,
716+ "esbuild" ,
717+ ) ;
718+ const candidate = require . resolve ( "esbuild" , { paths : [ userEsbuild ] } ) ;
719+ // eslint-disable-next-line @typescript-eslint/no-var-requires
720+ require ( candidate ) ;
721+ return true ; // available via ~/.continue
722+ } catch {
723+ // Not available → show friendly instructions and opt out of building
724+ await ide . showToast (
725+ "error" ,
726+ [
727+ "config.ts has been deprecated and esbuild is no longer automatically installed by Continue." ,
728+ "To use config.ts, install esbuild manually:" ,
729+ "" ,
730+ ` ${ installCmd } ` ,
731+ ] . join ( "\n" ) ,
732+ ) ;
733+ return false ;
782734 }
783-
784- // Clean up
785- fs . unlinkSync ( tgzPath ) ;
786- fs . rmSync ( tempDir , { recursive : true } ) ;
787-
788- await ide . showToast (
789- "info" ,
790- `'esbuild' successfully installed to ${ esbuildPath } ` ,
791- ) ;
792- } catch ( error ) {
793- console . error ( "Error downloading or saving esbuild binary:" , error ) ;
794- throw error ;
795735 }
796736}
797737
@@ -866,8 +806,15 @@ async function buildConfigTsandReadConfigJs(ide: IDE, ideType: IdeType) {
866806 return ;
867807 }
868808
869- await handleEsbuildInstallation ( ide , ideType ) ;
870- await tryBuildConfigTs ( ) ;
809+ // Only bother with esbuild if config.ts is actually customized
810+ if ( currentContent . trim ( ) !== DEFAULT_CONFIG_TS_CONTENTS . trim ( ) ) {
811+ const ok = await handleEsbuildInstallation ( ide , ideType ) ;
812+ if ( ! ok ) {
813+ // esbuild not available → we already showed a friendly message; skip building
814+ return ;
815+ }
816+ await tryBuildConfigTs ( ) ;
817+ }
871818
872819 return readConfigJs ( ) ;
873820}
0 commit comments