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 ci/build/build-vscode.sh
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ EOF
) > product.json


VSCODE_QUALITY=stable npm run gulp compile-copilot-extension-build
VSCODE_QUALITY=stable npm run gulp compile-copilot-extension-full-build

npm run gulp core-ci
npm run gulp "vscode-reh-web-$VSCODE_TARGET${MINIFY:+-min}-ci"
Expand Down
163 changes: 163 additions & 0 deletions patches/copilot.diff
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
Index: code-server/lib/vscode/build/gulpfile.extensions.ts
===================================================================
--- code-server.orig/lib/vscode/build/gulpfile.extensions.ts
+++ code-server/lib/vscode/build/gulpfile.extensions.ts
@@ -287,6 +287,29 @@ export const compileCopilotExtensionBuil
gulp.task(compileCopilotExtensionBuildTask);

/**
+ * Compiles the built-in copilot extension with proper `.vscodeignore` filtering
+ * and materializes native dependency shims (`node-pty`, `ripgrep`).
+ * Produces output equivalent to what CI ships from the pre-built VSIX.
+ *
+ * The result is placed in `.build/extensions/copilot/` and can be copied
+ * directly into a VS Code Insiders installation at:
+ * `<insiders>/resources/app/extensions/copilot/`
+ */
+export const compileCopilotExtensionFullBuildTask = task.define('compile-copilot-extension-full-build', task.series(
+ // Step 1: Clean previous copilot build output
+ task.define('clean-copilot-build', util.rimraf('.build/extensions/copilot')),
+ // Step 2: Build and package with proper `.vscodeignore` filtering
+ task.define('package-copilot-extension-full', () => ext.packageCopilotExtensionFullStream().pipe(gulp.dest('.build'))),
+ // Step 3: Materialize native dependency shims (`node-pty`, `ripgrep`)
+ task.define('copilot-extension-native-shims', () => {
+ const copilotExtDir = path.join(root, '.build', 'extensions', 'copilot');
+ ext.prepareCopilotExtensionNativeShims(copilotExtDir);
+ return Promise.resolve();
+ })
+));
+gulp.task(compileCopilotExtensionFullBuildTask);
+
+/**
* Compiles the extensions for the build.
* This is essentially a helper task that combines {@link cleanExtensionsBuildTask}, {@link compileNonNativeExtensionsBuildTask} and {@link compileNativeExtensionsBuildTask}
*/
Index: code-server/lib/vscode/build/lib/extensions.ts
===================================================================
--- code-server.orig/lib/vscode/build/lib/extensions.ts
+++ code-server/lib/vscode/build/lib/extensions.ts
@@ -24,6 +24,7 @@ import { getProductionDependencies } fro
import { type IExtensionDefinition, getExtensionStream } from './builtInExtensions.ts';
import { fetchUrls, fetchGithub } from './fetch.ts';
import { createTsgoStream, spawnTsgo } from './tsgo.ts';
+import { prepareBuiltInCopilotExtensionShims } from './copilot.ts';
import vzip from 'gulp-vinyl-zip';

import { createRequire } from 'module';
@@ -482,6 +483,116 @@ export function packageCopilotExtensionS
).pipe(util2.setExecutableBit(['**/*.sh']));
}

+/**
+ * Package the built-in copilot extension as a properly filtered VSIX-equivalent.
+ * Unlike {@link packageCopilotExtensionStream}, this uses vsce.listFiles with
+ * PackageManager.Npm so that .vscodeignore is respected for dependency filtering,
+ * producing output equivalent to what CI ships from the pre-built VSIX.
+ */
+export function packageCopilotExtensionFullStream(): Stream {
+ const vsce = require('@vscode/vsce') as typeof import('@vscode/vsce');
+ const extensionPath = path.join(root, 'extensions', 'copilot');
+ if (!fs.existsSync(extensionPath)) {
+ return es.readArray([]);
+ }
+
+ const esbuildConfigFileName = '.esbuild.ts';
+ const esbuildScript = path.join(extensionPath, esbuildConfigFileName);
+ if (!fs.existsSync(esbuildScript)) {
+ throw new Error(`Copilot esbuild script not found at ${esbuildScript}`);
+ }
+
+ const result = es.through();
+
+ // Step 1: Run esbuild to compile the extension
+ new Promise<void>((resolve, reject) => {
+ const proc = cp.execFile(process.argv[0], [esbuildScript], { cwd: extensionPath }, (error, _stdout, stderr) => {
+ if (error) {
+ return reject(error);
+ }
+ const matches = (stderr || '').match(/\> (.+): error: (.+)?/g);
+ fancyLog(`Bundled extension: ${ansiColors.yellow(path.join('copilot', esbuildConfigFileName))} with ${matches ? matches.length : 0} errors.`);
+ for (const match of matches || []) {
+ fancyLog.error(match);
+ }
+ return resolve();
+ });
+ proc.stdout!.on('data', (data) => {
+ fancyLog(`${ansiColors.green('esbuilding copilot')}: ${data.toString('utf8')}`);
+ });
+ }).then(() => {
+ // Step 2: Use `vsce.listFiles` with Npm package manager so `.vscodeignore`
+ // is applied to both source files AND `node_modules` dependencies.
+ // This is the key difference from `packageCopilotExtensionStream` which
+ // uses `PackageManager.None` and then blindly merges all production deps.
+ return vsce.listFiles({ cwd: extensionPath, packageManager: vsce.PackageManager.Npm });
+ }).then(fileNames => {
+ const files = fileNames
+ .map(fileName => path.join(extensionPath, fileName))
+ .map(filePath => new File({
+ path: filePath,
+ stat: fs.statSync(filePath),
+ base: extensionPath,
+ contents: fs.createReadStream(filePath)
+ }));
+
+ es.readArray(files).pipe(result);
+ }).catch(err => {
+ console.error('Failed to package copilot extension:', err);
+ result.emit('error', err);
+ });
+
+ // Apply the same package.json cleanup as bundled extensions get
+ const cleaned = updateExtensionPackageJSON(
+ result.pipe(rename(p => p.dirname = `extensions/copilot/${p.dirname}`)),
+ (data: any) => {
+ delete data.scripts;
+ delete data.dependencies;
+ delete data.devDependencies;
+ if (data.main) {
+ data.main = data.main.replace('/out/', '/dist/');
+ }
+ return data;
+ }
+ );
+
+ return minifyExtensionResources(cleaned)
+ .pipe(util2.setExecutableBit(['**/*.sh']));
+}
+
+/**
+ * Materializes native dependency shims (`node-pty`, `ripgrep`) into the copilot
+ * extension output at {@link outputDir}. Uses the root `node_modules` as the
+ * source for native binaries, targeting the current platform/arch.
+ *
+ * This is the equivalent of what {@link copyCopilotNativeDepsTask} in
+ * `gulpfile.vscode.ts` does during a full product build, but scoped to
+ * just the standalone copilot extension output.
+ *
+ * Failures are logged as warnings rather than throwing, since the copilot
+ * extension can still create shims at runtime if they are missing.
+ */
+export function prepareCopilotExtensionNativeShims(outputDir: string): void {
+ const platform = process.platform;
+ const arch = process.arch;
+ const appNodeModulesDir = path.join(root, 'node_modules');
+
+ if (!fs.existsSync(outputDir)) {
+ fancyLog.warn('[prepareCopilotExtensionNativeShims] Copilot extension not found at', outputDir, '- skipping shims');
+ return;
+ }
+
+ try {
+ prepareBuiltInCopilotExtensionShims(platform, arch, outputDir, appNodeModulesDir);
+ fancyLog(`[prepareCopilotExtensionNativeShims] Materialized native shims for ${platform}-${arch}`);
+ } catch (err) {
+ // Downgrade to a warning for local builds since the extension
+ // can still function without shims (it creates them at runtime).
+ fancyLog.warn(`[prepareCopilotExtensionNativeShims] Failed to materialize shims: ${err}`);
+ fancyLog.warn('[prepareCopilotExtensionNativeShims] The extension will still work but will create shims at runtime.');
+ }
+}
+
export function packageMarketplaceExtensionsStream(forWeb: boolean): Stream {
const marketplaceExtensionsDescriptions = [
...builtInExtensions.filter(({ name }) => (forWeb ? !marketplaceWebExtensionsExclude.has(name) : true)),
1 change: 1 addition & 0 deletions patches/series
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,4 @@ clipboard.diff
display-language.diff
trusted-domains.diff
signature-verification.diff
copilot.diff
Loading