Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion binary/utils/bundle-binary.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const { TARGET_TO_LANCEDB } = require("../utils/targets");
const fs = require("fs");
const {
downloadSqlite,
} = require("../../extensions/vscode/scripts/download-copy-sqlite-esbuild");
} = require("../../extensions/vscode/scripts/download-copy-sqlite");
const { fork } = require("child_process");

async function downloadNodeSqlite(target, targetDir) {
Expand Down
139 changes: 43 additions & 96 deletions core/config/load.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import {
ModelRole,
} from "@continuedev/config-yaml";
import * as JSONC from "comment-json";
import * as tar from "tar";

import {
BrowserSerializedContinueConfig,
Expand Down Expand Up @@ -696,102 +695,43 @@ function escapeSpacesInPath(p: string): string {
return p.replace(/ /g, "\\ ");
}

async function handleEsbuildInstallation(ide: IDE, ideType: IdeType) {
// JetBrains is currently the only IDE that we've reached the plugin size limit and
// therefore need to install esbuild manually to reduce the size
if (ideType !== "jetbrains") {
return;
}

const globalContext = new GlobalContext();
if (globalContext.get("hasDismissedConfigTsNoticeJetBrains")) {
return;
}

const esbuildPath = getEsbuildBinaryPath();

if (fs.existsSync(esbuildPath)) {
return;
}

console.debug("No esbuild binary detected");

const shouldInstall = await promptEsbuildInstallation(ide);

if (shouldInstall) {
await downloadAndInstallEsbuild(ide);
}
}

async function promptEsbuildInstallation(ide: IDE): Promise<boolean> {
const installMsg = "Install esbuild";
const dismissMsg = "Dismiss";

const res = await ide.showToast(
"warning",
"You're using a custom 'config.ts' file, which requires 'esbuild' to be installed. Would you like to install it now?",
dismissMsg,
installMsg,
);

if (res === dismissMsg) {
const globalContext = new GlobalContext();
globalContext.update("hasDismissedConfigTsNoticeJetBrains", true);
return false;
}

return res === installMsg;
}

/**
* The download logic is adapted from here: https://esbuild.github.io/getting-started/#download-a-build
*/
async function downloadAndInstallEsbuild(ide: IDE) {
const esbuildPath = getEsbuildBinaryPath();
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "esbuild-"));
async function handleEsbuildInstallation(
ide: IDE,
_ideType: IdeType,
): Promise<boolean> {
// Only check when config.ts is going to be used; never auto-install.
const installCmd = "npm i [email protected] --prefix ~/.continue";

// Try to detect a user-installed esbuild (normal resolution)
try {
const target = `${os.platform()}-${os.arch()}`;
const version = "0.19.11";
const url = `https://registry.npmjs.org/@esbuild/${target}/-/${target}-${version}.tgz`;
const tgzPath = path.join(tempDir, `esbuild-${version}.tgz`);

console.debug(`Downloading esbuild from: ${url}`);
execSync(`curl -fo "${tgzPath}" "${url}"`);

console.debug(`Extracting tgz file to: ${tempDir}`);
await tar.x({
file: tgzPath,
cwd: tempDir,
strip: 2, // Remove the top two levels of directories
});

// Ensure the destination directory exists
const destDir = path.dirname(esbuildPath);
if (!fs.existsSync(destDir)) {
fs.mkdirSync(destDir, { recursive: true });
}

// Move the file
const extractedBinaryPath = path.join(tempDir, "esbuild");
fs.renameSync(extractedBinaryPath, esbuildPath);

// Ensure the binary is executable (not needed on Windows)
if (os.platform() !== "win32") {
fs.chmodSync(esbuildPath, 0o755);
await import("esbuild");
return true; // available
} catch {
// Try resolving from ~/.continue/node_modules as a courtesy
try {
const userEsbuild = path.join(
os.homedir(),
".continue",
"node_modules",
"esbuild",
);
const candidate = require.resolve("esbuild", { paths: [userEsbuild] });
// eslint-disable-next-line @typescript-eslint/no-var-requires
require(candidate);
return true; // available via ~/.continue
} catch {
// Not available → show friendly instructions and opt out of building
await ide.showToast(
"error",
[
"config.ts has been deprecated and esbuild is no longer automatically installed by Continue.",
"To use config.ts, install esbuild manually:",
"",
` ${installCmd}`,
].join("\n"),
);
return false;
}

// Clean up
fs.unlinkSync(tgzPath);
fs.rmSync(tempDir, { recursive: true });

await ide.showToast(
"info",
`'esbuild' successfully installed to ${esbuildPath}`,
);
} catch (error) {
console.error("Error downloading or saving esbuild binary:", error);
throw error;
}
}

Expand Down Expand Up @@ -866,8 +806,15 @@ async function buildConfigTsandReadConfigJs(ide: IDE, ideType: IdeType) {
return;
}

await handleEsbuildInstallation(ide, ideType);
await tryBuildConfigTs();
// Only bother with esbuild if config.ts is actually customized
if (currentContent.trim() !== DEFAULT_CONFIG_TS_CONTENTS.trim()) {
const ok = await handleEsbuildInstallation(ide, ideType);
if (!ok) {
// esbuild not available → we already showed a friendly message; skip building
return;
}
await tryBuildConfigTs();
}
Comment on lines +809 to +817
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the goal from @sestinj 's feedback was just to provide the deprecation message to user's that have modified their config.ts , not to attempt to use their locally installed esbuild.

The general goal here is rip out all the config.ts logic but give a heads up to those affected.

Could we modify this to instead just show the toast with that in mind?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@RomneyDa @Patrick-Erichsen @sestinj : The current code is based on feedback from Dallin in my now closed PR:
#7895 (review)

Spoke with the team further about this and we're thinking let's remove esbuild module installation while still supporting config.ts by assuming users already have esbuild installed and showing them an error with instructions if they don't e.g. config.ts has been deprecated and esbuild is no longer automatically installed by Continue. To use config.ts, you can run npm i [email protected] in ~/.continue`. Sorry for the partial bait and switch on this

As you requested I kept all the config.ts related logic, still letting the end user use config.ts if they have installed esbuild themselves. This PR leaves a deprecation message and the next logical step would be to remove all code pertaining to config.ts.

This PR supersedes my two earlier attempts:
#7790: Upgrade esbuild to less vulnerable version
#7895: Remove esbuild + config.ts support

Copy link
Collaborator

@RomneyDa RomneyDa Oct 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@joffeoja chatted with @Patrick-Erichsen, sounds like we'll move forward with this

Copy link
Contributor Author

@joffeoja joffeoja Oct 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@RomneyDa @Patrick-Erichsen Sounds good. Do I have to do anything more on my part?


return readConfigJs();
}
Expand Down
6 changes: 5 additions & 1 deletion extensions/vscode/.vscodeignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,8 @@ e2e

server/exe/**
!out/node_modules/**
!node_modules/@vscode/ripgrep/bin/rg
!node_modules/@vscode/ripgrep/bin/rg

# Do not ship esbuild in VSIX
out/node_modules/esbuild/**
out/node_modules/@esbuild/**
1 change: 0 additions & 1 deletion extensions/vscode/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion extensions/vscode/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -737,7 +737,6 @@
"dbinfoz": "^0.14.0",
"diff": "^7.0.0",
"downshift": "^7.6.0",
"esbuild": "0.17.19",
"express": "^4.18.2",
"fkill": "^8.1.0",
"follow-redirects": "^1.15.4",
Expand Down
19 changes: 0 additions & 19 deletions extensions/vscode/scripts/prepackage-cross-platform.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,7 @@ const {
buildGui,
copyOnnxRuntimeFromNodeModules,
copyTreeSitterWasms,
copyTreeSitterTagQryFiles,
copyNodeModules,
downloadEsbuildBinary,
downloadRipgrepBinary,
copySqliteBinary,
installNodeModuleInTempDirAndCopyToCurrent,
Expand Down Expand Up @@ -90,9 +88,6 @@ async function package(target, os, arch, exe) {
// Copy tree-sitter-wasm files
await copyTreeSitterWasms();

// Copy tree-sitter tag query files
await copyTreeSitterTagQryFiles();

// Install and copy over native modules
// *** onnxruntime-node ***
await copyOnnxRuntimeFromNodeModules(target);
Expand All @@ -116,12 +111,6 @@ async function package(target, os, arch, exe) {
lancePackageToInstall,
"@lancedb",
);
// *** esbuild ***
// await installNodeModuleInTempDirAndCopyToCurrent(
// "[email protected]",
// "@esbuild",
// );
await downloadEsbuildBinary(target);

// *** sqlite ***
await downloadSqliteBinary(target);
Expand Down Expand Up @@ -187,19 +176,11 @@ async function package(target, os, arch, exe) {

// out/node_modules (to be accessed by extension.js)
`out/node_modules/@vscode/ripgrep/bin/rg${exe}`,
`out/node_modules/@esbuild/${
target === "win32-arm64"
? "esbuild.exe"
: target === "win32-x64"
? "win32-x64/esbuild.exe"
: `${target}/bin/esbuild`
}`,
`out/node_modules/@lancedb/vectordb-${
os === "win32"
? "win32-x64-msvc"
: `${target}${os === "linux" ? "-gnu" : ""}`
}/index.node`,
`out/node_modules/esbuild/lib/main.js`,
]);
}

Expand Down
26 changes: 2 additions & 24 deletions extensions/vscode/scripts/prepackage.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const {
autodetectPlatformAndArch,
} = require("../../../scripts/util/index");

const { copySqlite, copyEsbuild } = require("./download-copy-sqlite-esbuild");
const { copySqlite } = require("./download-copy-sqlite");
const { generateAndCopyConfigYamlSchema } = require("./generate-copy-config");
const { installAndCopyNodeModules } = require("./install-copy-nodemodule");
const { npmInstall } = require("./npm-install");
Expand Down Expand Up @@ -303,14 +303,9 @@ void (async () => {
);

await Promise.all([
copyEsbuild(target),
copySqlite(target),
installAndCopyNodeModules(packageToInstall, "@lancedb"),
]);
} else {
// Download esbuild from npm in tmp and copy over
console.log("[info] npm installing esbuild binary");
await installAndCopyNodeModules("[email protected]", "@esbuild");
}
}

Expand Down Expand Up @@ -349,13 +344,7 @@ void (async () => {
});

// Copy node_modules for pre-built binaries
const NODE_MODULES_TO_COPY = [
"esbuild",
"@esbuild",
"@lancedb",
"@vscode/ripgrep",
"workerpool",
];
const NODE_MODULES_TO_COPY = ["@lancedb", "@vscode/ripgrep", "workerpool"];

fs.mkdirSync("out/node_modules", { recursive: true });

Expand All @@ -382,9 +371,6 @@ void (async () => {
),
);

// delete esbuild/bin because platform-specific @esbuild is downloaded
fs.rmSync(`out/node_modules/esbuild/bin`, { recursive: true });

console.log(`[info] Copied ${NODE_MODULES_TO_COPY.join(", ")}`);

// Copy over any worker files
Expand Down Expand Up @@ -442,15 +428,7 @@ void (async () => {

// out/node_modules (to be accessed by extension.js)
`out/node_modules/@vscode/ripgrep/bin/rg${exe}`,
`out/node_modules/@esbuild/${
target === "win32-arm64"
? "esbuild.exe"
: target === "win32-x64"
? "win32-x64/esbuild.exe"
: `${target}/bin/esbuild`
}`,
`out/node_modules/@lancedb/vectordb-${target}${isWinTarget ? "-msvc" : ""}${isLinuxTarget ? "-gnu" : ""}/index.node`,
`out/node_modules/esbuild/lib/main.js`,
]);

console.log(
Expand Down
Loading
Loading