Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
690a115
Initial plan
Copilot Jan 2, 2026
34bfee0
Add core infrastructure for chat image slideshow editor
Copilot Jan 2, 2026
574c4be
Add README documentation for chat image slideshow feature
Copilot Jan 2, 2026
f5a49ba
Refactor CSS for chat image slideshow editor for improved readability…
rebornix Jan 2, 2026
0d097e1
Refactor chat image slideshow editor and service for improved structu…
rebornix Jan 2, 2026
163bc13
Merge remote-tracking branch 'origin/main' into copilot/start-image-d…
rebornix Jan 7, 2026
6f47400
feat(chat): enhance image extraction from tool invocations for slides…
rebornix Jan 7, 2026
0a4097e
Remove unnecessary comments from chatImageSlideshow files
Copilot Jan 22, 2026
bf216b4
Remove JSDoc comments from interfaces and classes
Copilot Jan 23, 2026
e01a900
Initial plan
Copilot Mar 10, 2026
3681826
Fix terminal OverviewRulerRenderer crash on disposal
Copilot Mar 10, 2026
0d94646
Merge origin/main into copilot/start-image-display-implementation
rebornix Mar 11, 2026
aeef983
Revert decorationAddon.ts change, prepare for telemetry redaction fix
Copilot Mar 11, 2026
a3af286
Fix telemetry path redaction to preserve node_modules paths in full a…
Copilot Mar 11, 2026
1f7105d
Address PR feedback: merge node_modules regexes, reorder logic, resto…
Copilot Mar 11, 2026
7a090df
Re-remove webpack (again again)
mjbvz Mar 11, 2026
cc5c2fd
Browser Zoom (#299161)
jruales Mar 11, 2026
121ed5f
Simplify `chat.autoReply`: skip questions instead of LLM-answering th…
digitarald Mar 12, 2026
d582a15
Allow vscode-sessions strings in the main bundle (#300944)
TylerLeonhardt Mar 12, 2026
8432b8b
plugins: support openplugin format (#300948)
connor4312 Mar 12, 2026
422d296
Support terminal creation on web worker extension host when there's r…
jeanp413 Mar 12, 2026
b8b027b
/yolo -> switches to bypass mode, /autopilot switches to autopilot (#…
justschen Mar 12, 2026
99c4016
when thinking is collapsed, make sure to show full tool info (#300952)
justschen Mar 12, 2026
3ce4949
Merge pull request #300559 from microsoft/copilot/fix-uncaught-typeer…
bryanchen-d Mar 12, 2026
bb5835f
support for chat customizations in parent repo folders (#300916)
aeschli Mar 12, 2026
cfff60f
Merge pull request #300860 from mjbvz/dev/mjbvz/heavy-swallow
mjbvz Mar 12, 2026
ac668ca
Distro Bump (#300964)
TylerLeonhardt Mar 12, 2026
346c218
Refactor image carousel: simplify architecture, fix review feedback
rebornix Mar 12, 2026
70b2564
feat: implement image carousel actions and keyboard navigation
rebornix Mar 12, 2026
c3d7346
feat: add image carousel project to i18n resources
rebornix Mar 12, 2026
68b4b79
show working progress more consistently (#300986)
justschen Mar 12, 2026
850a393
Apply suggestions from code review
rebornix Mar 12, 2026
b79bcf7
Merge pull request #300983 from microsoft/rebornix/hollow-tarantula-i…
rebornix Mar 12, 2026
8ca4fb2
Fix: comment typo in authIssuers proposal (#300899)
12LuA Mar 12, 2026
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
12 changes: 0 additions & 12 deletions build/gulpfile.extensions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -309,13 +309,6 @@ async function buildWebExtensions(isWatch: boolean): Promise<void> {
{ ignore: ['**/node_modules'] }
);

// Find all webpack configs, excluding those that will be esbuilt
const esbuildExtensionDirs = new Set(esbuildConfigLocations.map(p => path.dirname(p)));
const webpackConfigLocations = (await nodeUtil.promisify(glob)(
path.join(extensionsPath, '**', 'extension-browser.webpack.config.js'),
{ ignore: ['**/node_modules'] }
)).filter(configPath => !esbuildExtensionDirs.has(path.dirname(configPath)));

const promises: Promise<unknown>[] = [];

// Esbuild for extensions
Expand All @@ -330,10 +323,5 @@ async function buildWebExtensions(isWatch: boolean): Promise<void> {
);
}

// Run webpack for remaining extensions
if (webpackConfigLocations.length > 0) {
promises.push(ext.webpackExtensions('packaging web extension', isWatch, webpackConfigLocations.map(configPath => ({ configPath }))));
}

await Promise.all(promises);
}
208 changes: 4 additions & 204 deletions build/lib/extensions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,8 @@ import fancyLog from 'fancy-log';
import ansiColors from 'ansi-colors';
import buffer from 'gulp-buffer';
import * as jsoncParser from 'jsonc-parser';
import webpack from 'webpack';
import { getProductionDependencies } from './dependencies.ts';
import { type IExtensionDefinition, getExtensionStream } from './builtInExtensions.ts';
import { getVersion } from './getVersion.ts';
import { fetchUrls, fetchGithub } from './fetch.ts';
import { createTsgoStream, spawnTsgo } from './tsgo.ts';
import vzip from 'gulp-vinyl-zip';
Expand All @@ -32,8 +30,8 @@ import { createRequire } from 'module';
const require = createRequire(import.meta.url);

const root = path.dirname(path.dirname(import.meta.dirname));
const commit = getVersion(root);
const sourceMappingURLBase = `https://main.vscode-cdn.net/sourcemaps/${commit}`;
// const commit = getVersion(root);
// const sourceMappingURLBase = `https://main.vscode-cdn.net/sourcemaps/${commit}`;

function minifyExtensionResources(input: Stream): Stream {
const jsonFilter = filter(['**/*.json', '**/*.code-snippets'], { restore: true });
Expand Down Expand Up @@ -65,32 +63,24 @@ function updateExtensionPackageJSON(input: Stream, update: (data: any) => any):
.pipe(packageJsonFilter.restore);
}

function fromLocal(extensionPath: string, forWeb: boolean, disableMangle: boolean): Stream {
function fromLocal(extensionPath: string, forWeb: boolean, _disableMangle: boolean): Stream {

const esbuildConfigFileName = forWeb
? 'esbuild.browser.mts'
: 'esbuild.mts';

const webpackConfigFileName = forWeb
? `extension-browser.webpack.config.js`
: `extension.webpack.config.js`;

const hasEsbuild = fs.existsSync(path.join(extensionPath, esbuildConfigFileName));
const hasWebpack = fs.existsSync(path.join(extensionPath, webpackConfigFileName));

let input: Stream;
let isBundled = false;

if (hasEsbuild) {
// Unlike webpack, esbuild only does bundling so we still want to run a separate type check step
// Esbuild only does bundling so we still want to run a separate type check step
input = es.merge(
fromLocalEsbuild(extensionPath, esbuildConfigFileName),
...getBuildRootsForExtension(extensionPath).map(root => typeCheckExtensionStream(root, forWeb)),
);
isBundled = true;
} else if (hasWebpack) {
input = fromLocalWebpack(extensionPath, webpackConfigFileName, disableMangle);
isBundled = true;
} else {
input = fromLocalNormal(extensionPath);
}
Expand Down Expand Up @@ -122,132 +112,6 @@ export function typeCheckExtensionStream(extensionPath: string, forWeb: boolean)
return createTsgoStream(tsconfigPath, { taskName: 'typechecking extension (tsgo)', noEmit: true });
}

function fromLocalWebpack(extensionPath: string, webpackConfigFileName: string, disableMangle: boolean): Stream {
const vsce = require('@vscode/vsce') as typeof import('@vscode/vsce');
const webpack = require('webpack');
const webpackGulp = require('webpack-stream');
const result = es.through();

const packagedDependencies: string[] = [];
const stripOutSourceMaps: string[] = [];
const packageJsonConfig = require(path.join(extensionPath, 'package.json'));
if (packageJsonConfig.dependencies) {
const webpackConfig = require(path.join(extensionPath, webpackConfigFileName));
const webpackRootConfig = webpackConfig.default;
for (const key in webpackRootConfig.externals) {
if (key in packageJsonConfig.dependencies) {
packagedDependencies.push(key);
}
}

if (webpackConfig.StripOutSourceMaps) {
for (const filePath of webpackConfig.StripOutSourceMaps) {
stripOutSourceMaps.push(filePath);
}
}
}

// TODO: add prune support based on packagedDependencies to vsce.PackageManager.Npm similar
// to vsce.PackageManager.Yarn.
// A static analysis showed there are no webpack externals that are dependencies of the current
// local extensions so we can use the vsce.PackageManager.None config to ignore dependencies list
// as a temporary workaround.
vsce.listFiles({ cwd: extensionPath, packageManager: vsce.PackageManager.None, packagedDependencies }).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)
}));

// check for a webpack configuration files, then invoke webpack
// and merge its output with the files stream.
const webpackConfigLocations = (glob.sync(
path.join(extensionPath, '**', webpackConfigFileName),
{ ignore: ['**/node_modules'] }
) as string[]);
const webpackStreams = webpackConfigLocations.flatMap(webpackConfigPath => {

const webpackDone = (err: Error | undefined, stats: any) => {
fancyLog(`Bundled extension: ${ansiColors.yellow(path.join(path.basename(extensionPath), path.relative(extensionPath, webpackConfigPath)))}...`);
if (err) {
result.emit('error', err);
}
const { compilation } = stats;
if (compilation.errors.length > 0) {
result.emit('error', compilation.errors.join('\n'));
}
if (compilation.warnings.length > 0) {
result.emit('error', compilation.warnings.join('\n'));
}
};

const exportedConfig = require(webpackConfigPath).default;
return (Array.isArray(exportedConfig) ? exportedConfig : [exportedConfig]).map(config => {
const webpackConfig = {
...config,
...{ mode: 'production' }
};
if (disableMangle) {
if (Array.isArray(config.module.rules)) {
for (const rule of config.module.rules) {
if (Array.isArray(rule.use)) {
for (const use of rule.use) {
if (String(use.loader).endsWith('mangle-loader.js')) {
use.options.disabled = true;
}
}
}
}
}
}
const relativeOutputPath = path.relative(extensionPath, webpackConfig.output.path);

return webpackGulp(webpackConfig, webpack, webpackDone)
.pipe(es.through(function (data) {
data.stat = data.stat || {};
data.base = extensionPath;
this.emit('data', data);
}))
.pipe(es.through(function (data: File) {
// source map handling:
// * rewrite sourceMappingURL
// * save to disk so that upload-task picks this up
if (path.extname(data.basename) === '.js') {
if (stripOutSourceMaps.indexOf(data.relative) >= 0) { // remove source map
const contents = (data.contents as Buffer).toString('utf8');
data.contents = Buffer.from(contents.replace(/\n\/\/# sourceMappingURL=(.*)$/gm, ''), 'utf8');
} else {
const contents = (data.contents as Buffer).toString('utf8');
data.contents = Buffer.from(contents.replace(/\n\/\/# sourceMappingURL=(.*)$/gm, function (_m, g1) {
return `\n//# sourceMappingURL=${sourceMappingURLBase}/extensions/${path.basename(extensionPath)}/${relativeOutputPath}/${g1}`;
}), 'utf8');
}
}

this.emit('data', data);
}));
});
});

es.merge(...webpackStreams, es.readArray(files))
// .pipe(es.through(function (data) {
// // debug
// console.log('out', data.path, data.contents.length);
// this.emit('data', data);
// }))
.pipe(result);

}).catch(err => {
console.error(extensionPath);
console.error(packagedDependencies);
result.emit('error', err);
});

return result.pipe(createStatsStream(path.basename(extensionPath)));
}

function fromLocalNormal(extensionPath: string): Stream {
const vsce = require('@vscode/vsce') as typeof import('@vscode/vsce');
Expand Down Expand Up @@ -649,70 +513,6 @@ export function translatePackageJSON(packageJSON: string, packageNLSPath: string

const extensionsPath = path.join(root, 'extensions');

export async function webpackExtensions(taskName: string, isWatch: boolean, webpackConfigLocations: { configPath: string; outputRoot?: string }[]) {
const webpack = require('webpack') as typeof import('webpack');

const webpackConfigs: webpack.Configuration[] = [];

for (const { configPath, outputRoot } of webpackConfigLocations) {
const configOrFnOrArray = require(configPath).default;
function addConfig(configOrFnOrArray: webpack.Configuration | ((env: unknown, args: unknown) => webpack.Configuration) | webpack.Configuration[]) {
for (const configOrFn of Array.isArray(configOrFnOrArray) ? configOrFnOrArray : [configOrFnOrArray]) {
const config = typeof configOrFn === 'function' ? configOrFn({}, {}) : configOrFn;
if (outputRoot) {
config.output!.path = path.join(outputRoot, path.relative(path.dirname(configPath), config.output!.path!));
}
webpackConfigs.push(config);
}
}
addConfig(configOrFnOrArray);
}

function reporter(fullStats: any) {
if (Array.isArray(fullStats.children)) {
for (const stats of fullStats.children) {
const outputPath = stats.outputPath;
if (outputPath) {
const relativePath = path.relative(extensionsPath, outputPath).replace(/\\/g, '/');
const match = relativePath.match(/[^\/]+(\/server|\/client)?/);
fancyLog(`Finished ${ansiColors.green(taskName)} ${ansiColors.cyan(match![0])} with ${stats.errors.length} errors.`);
}
if (Array.isArray(stats.errors)) {
stats.errors.forEach((error: any) => {
fancyLog.error(error);
});
}
if (Array.isArray(stats.warnings)) {
stats.warnings.forEach((warning: any) => {
fancyLog.warn(warning);
});
}
}
}
}
return new Promise<void>((resolve, reject) => {
if (isWatch) {
webpack(webpackConfigs).watch({}, (err, stats) => {
if (err) {
reject();
} else {
reporter(stats?.toJson());
}
});
} else {
webpack(webpackConfigs).run((err, stats) => {
if (err) {
fancyLog.error(err);
reject();
} else {
reporter(stats?.toJson());
resolve();
}
});
}
});
}

export async function esbuildExtensions(taskName: string, isWatch: boolean, scripts: { script: string; outputRoot?: string }[]): Promise<void> {
function reporter(stdError: string, script: string) {
const matches = (stdError || '').match(/\> (.+): error: (.+)?/g);
Expand Down
4 changes: 4 additions & 0 deletions build/lib/i18n.resources.json
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,10 @@
"name": "vs/workbench/contrib/inlineChat",
"project": "vscode-workbench"
},
{
"name": "vs/workbench/contrib/imageCarousel",
"project": "vscode-workbench"
},
{
"name": "vs/workbench/contrib/chat",
"project": "vscode-workbench"
Expand Down
3 changes: 1 addition & 2 deletions build/lib/i18n.ts
Original file line number Diff line number Diff line change
Expand Up @@ -743,9 +743,8 @@ export function prepareI18nPackFiles(resultingTranslationPaths: TranslationPath[
if (EXTERNAL_EXTENSIONS.find(e => e === resource)) {
project = extensionsProject;
}
// TODO(tyleonha): Support localization for the Sessions app (https://github.com/microsoft/vscode-internalbacklog/issues/7045)
// vscode-setup has its own import path via prepareIslFiles
if (project === sessionsProject || project === setupProject) {
if (project === setupProject) {
return;
}
const contents = xlf.contents!.toString();
Expand Down
66 changes: 0 additions & 66 deletions extensions/mangle-loader.js

This file was deleted.

Loading
Loading