From b74352371ff2ee0158b01cdbf63d269c14387d8c Mon Sep 17 00:00:00 2001 From: mrleemurray Date: Fri, 13 Feb 2026 15:00:31 +0000 Subject: [PATCH 01/40] feat: update theme setting defaults based on product quality --- .../themes/common/workbenchThemeService.ts | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/vs/workbench/services/themes/common/workbenchThemeService.ts b/src/vs/workbench/services/themes/common/workbenchThemeService.ts index a214818b29ce2..8fefa7297ca33 100644 --- a/src/vs/workbench/services/themes/common/workbenchThemeService.ts +++ b/src/vs/workbench/services/themes/common/workbenchThemeService.ts @@ -11,6 +11,7 @@ import { ConfigurationTarget } from '../../../../platform/configuration/common/c import { isBoolean, isString } from '../../../../base/common/types.js'; import { IconContribution, IconDefinition } from '../../../../platform/theme/common/iconRegistry.js'; import { ColorScheme, ThemeTypeSelector } from '../../../../platform/theme/common/theme.js'; +import product from '../../../../platform/product/common/product.js'; export const IWorkbenchThemeService = refineServiceDecorator(IThemeService); @@ -38,17 +39,19 @@ export enum ThemeSettings { SYSTEM_COLOR_THEME = 'window.systemColorTheme' } -export enum ThemeSettingDefaults { - COLOR_THEME_DARK = 'Default Dark Modern', - COLOR_THEME_LIGHT = 'Default Light Modern', - COLOR_THEME_HC_DARK = 'Default High Contrast', - COLOR_THEME_HC_LIGHT = 'Default High Contrast Light', +const isOSS = !product.quality; - COLOR_THEME_DARK_OLD = 'Default Dark+', - COLOR_THEME_LIGHT_OLD = 'Default Light+', +export namespace ThemeSettingDefaults { + export const COLOR_THEME_DARK = isOSS ? 'Experimental Dark' : 'Default Dark Modern'; + export const COLOR_THEME_LIGHT = isOSS ? 'Experimental Light' : 'Default Light Modern'; + export const COLOR_THEME_HC_DARK = 'Default High Contrast'; + export const COLOR_THEME_HC_LIGHT = 'Default High Contrast Light'; - FILE_ICON_THEME = 'vs-seti', - PRODUCT_ICON_THEME = 'Default', + export const COLOR_THEME_DARK_OLD = 'Default Dark+'; + export const COLOR_THEME_LIGHT_OLD = 'Default Light+'; + + export const FILE_ICON_THEME = 'vs-seti'; + export const PRODUCT_ICON_THEME = 'Default'; } export const COLOR_THEME_DARK_INITIAL_COLORS = { From 5cbcc58fdcdf413ea4ec7134cee37cbae816aeda Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Fri, 27 Feb 2026 01:02:30 +0000 Subject: [PATCH 02/40] Update JS-related workspace tags. --- .../electron-browser/workspaceTagsService.ts | 139 +++++++++++++++++- 1 file changed, 137 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/tags/electron-browser/workspaceTagsService.ts b/src/vs/workbench/contrib/tags/electron-browser/workspaceTagsService.ts index 12f8e73bc273c..437685d31955d 100644 --- a/src/vs/workbench/contrib/tags/electron-browser/workspaceTagsService.ts +++ b/src/vs/workbench/contrib/tags/electron-browser/workspaceTagsService.ts @@ -30,7 +30,14 @@ const MetaModulesToLookFor = [ ]; const ModulesToLookFor = [ - // Packages that suggest a node server + // Platform-type packages + '@types/vscode', + '@vscode/dts', + '@types/node', + '@types/bun', + '@types/dom', + 'bun-types', + // Packages that suggest a JS-based backend server 'express', 'sails', 'koa', @@ -42,18 +49,36 @@ const ModulesToLookFor = [ '@nestjs/core', 'strapi', 'gatsby', + 'fastify', + 'hono', // JS frameworks 'react', 'react-native', 'react-native-macos', 'react-native-windows', 'rnpm-plugin-windows', + '@types/react', '@angular/core', '@ionic', 'vue', 'tns-core-modules', '@nativescript/core', 'electron', + '@remix-run/react', + '@remix-run/express', + '@remix-run/node', + '@remix-run/dev', + '@sveltejs/kit', + 'preact', + '@preact/signals', + '@builder.io/qwik', + 'alpinejs', + 'astro', + 'htmx.org', + 'solid-js', + 'svelte', + 'lit-html', + 'vuepress', // Other interesting packages 'aws-sdk', 'aws-amplify', @@ -61,6 +86,7 @@ const ModulesToLookFor = [ 'azure-storage', 'chroma', 'deepseek-js', + 'docusaurus', 'faiss', 'firebase', '@google-cloud/common', @@ -71,6 +97,43 @@ const ModulesToLookFor = [ 'pinecone', 'praisonai', 'qdrant', + 'typescript', + '@typescript/native-preview', + 'tslib', + 'eslint', + 'oxlint', + 'oxfmt', + 'typescript-eslint', + 'prettier', + 'dprint', + '@dprint/formatter', + '@babel/cli', + '@babel/core', + '@swc/cli', + '@swc/core', + 'vite', + 'esbuild', + 'rollup', + 'rolldown', + 'nx', + 'turbo', + 'webpack', + 'parcel', + '@biomejs/biome', + '@rspack/core', + '@rspack/cli', + '@trpc/client', + '@trpc/server', + 'zod', + 'pyright', + 'ts-morph', + 'oxc-minify', + 'oxc-transform', + 'oxc-resolver', + 'vue-tsc', + 'svelte-check', + 'tsup', + 'tsdown', // Office and Sharepoint packages '@microsoft/teams-js', '@microsoft/office-js', @@ -96,13 +159,17 @@ const ModulesToLookFor = [ 'playwright-firefox', 'playwright-webkit', // Other interesting browser testing packages + 'chai', 'cypress', + 'gherkin', + 'jest', + 'mocha', 'nightwatch', 'protractor', 'puppeteer', 'selenium-webdriver', + 'vitest', 'webdriverio', - 'gherkin', // AzureSDK packages '@azure/app-configuration', '@azure/cosmos-sign', @@ -183,6 +250,7 @@ const ModulesToLookFor = [ '@azure/arm-hybridkubernetes', '@azure/arm-kubernetesconfiguration', //AI and vector db dev packages + 'ai', '@anthropic-ai/sdk', '@anthropic-ai/tokenizer', '@arizeai/openinference-instrumentation-langchain', @@ -615,6 +683,73 @@ export class WorkspaceTagsService implements IWorkspaceTagsService { "workspace.npm.tika" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, "workspace.npm.webdriverio" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, "workspace.npm.gherkin" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.@types/vscode" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.@vscode/dts" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.@types/node" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.@types/bun" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.@types/dom" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.bun-types" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.fastify" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.hono" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.@types/react" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.@remix-run/react" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.@remix-run/express" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.@remix-run/node" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.@remix-run/dev" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.@sveltejs/kit" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.preact" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.@preact/signals" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.@builder.io/qwik" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.alpinejs" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.astro" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.htmx.org" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.solid-js" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.svelte" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.lit-html" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.vuepress" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.docusaurus" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.typescript" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.@typescript/native-preview" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.tslib" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.eslint" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.oxlint" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.oxfmt" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.typescript-eslint" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.prettier" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.dprint" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.@dprint/formatter" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.@babel/cli" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.@babel/core" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.@swc/cli" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.@swc/core" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.vite" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.esbuild" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.rollup" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.rolldown" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.nx" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.turbo" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.webpack" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.parcel" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.@biomejs/biome" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.@rspack/core" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.@rspack/cli" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.@trpc/client" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.@trpc/server" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.zod" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.pyright" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.ts-morph" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.oxc-minify" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.oxc-transform" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.oxc-resolver" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.vue-tsc" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.svelte-check" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.tsup" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.tsdown" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.chai" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.jest" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.mocha" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.vitest" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.ai" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, "workspace.npm.@azure/app-configuration" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, "workspace.npm.@azure/cosmos-sign" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, "workspace.npm.@azure/cosmos-language-service" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, From f92d923fcf72351190f8cf7e42c1f0f98d14e9bc Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Fri, 27 Feb 2026 01:10:30 +0000 Subject: [PATCH 03/40] Fix package name of `@types/web`. --- .../contrib/tags/electron-browser/workspaceTagsService.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/contrib/tags/electron-browser/workspaceTagsService.ts b/src/vs/workbench/contrib/tags/electron-browser/workspaceTagsService.ts index 437685d31955d..e22f45b9dfb6a 100644 --- a/src/vs/workbench/contrib/tags/electron-browser/workspaceTagsService.ts +++ b/src/vs/workbench/contrib/tags/electron-browser/workspaceTagsService.ts @@ -30,13 +30,13 @@ const MetaModulesToLookFor = [ ]; const ModulesToLookFor = [ - // Platform-type packages + // Platform-related type definition packages '@types/vscode', '@vscode/dts', '@types/node', '@types/bun', - '@types/dom', 'bun-types', + '@types/web', // Packages that suggest a JS-based backend server 'express', 'sails', @@ -687,8 +687,8 @@ export class WorkspaceTagsService implements IWorkspaceTagsService { "workspace.npm.@vscode/dts" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, "workspace.npm.@types/node" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, "workspace.npm.@types/bun" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "workspace.npm.@types/dom" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, "workspace.npm.bun-types" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.@types/web" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, "workspace.npm.fastify" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, "workspace.npm.hono" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, "workspace.npm.@types/react" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, From ea4c0d83d78d80e39cec4f3165dbd624221f8711 Mon Sep 17 00:00:00 2001 From: Isidor Date: Fri, 27 Feb 2026 09:30:53 +0100 Subject: [PATCH 04/40] React to Courtney feedback and improve model label and hover fixes #297162 --- .../contrib/chat/browser/widget/input/chatModelPicker.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/chat/browser/widget/input/chatModelPicker.ts b/src/vs/workbench/contrib/chat/browser/widget/input/chatModelPicker.ts index 2eb6414caed91..f7426562e70f1 100644 --- a/src/vs/workbench/contrib/chat/browser/widget/input/chatModelPicker.ts +++ b/src/vs/workbench/contrib/chat/browser/widget/input/chatModelPicker.ts @@ -404,7 +404,7 @@ function createUnavailableModelItem( if (reason === 'upgrade') { description = showActionLink - ? new MarkdownString(localize('chat.modelPicker.upgradeLink', "[Upgrade your plan](command:workbench.action.chat.upgradePlan \" \")"), { isTrusted: true }) + ? new MarkdownString(localize('chat.modelPicker.upgradeLink', "[Upgrade](command:workbench.action.chat.upgradePlan \" \")"), { isTrusted: true }) : undefined; } else if (reason === 'update') { description = localize('chat.modelPicker.updateDescription', "Update VS Code"); @@ -417,7 +417,7 @@ function createUnavailableModelItem( let hoverContent: MarkdownString; if (reason === 'upgrade') { hoverContent = new MarkdownString('', { isTrusted: true, supportThemeIcons: true }); - hoverContent.appendMarkdown(localize('chat.modelPicker.upgradeHover', "[Upgrade your plan](command:workbench.action.chat.upgradePlan \" \") to use this model.")); + hoverContent.appendMarkdown(localize('chat.modelPicker.upgradeHover', "[Upgrade to Copilot Pro](command:workbench.action.chat.upgradePlan \" \") with a free 30 day trial to use this model.")); } else if (reason === 'update') { hoverContent = getUpdateHoverContent(updateStateType); } else { From 7c76c290f02f26db726d96cd56cd4d2e636666a5 Mon Sep 17 00:00:00 2001 From: Isidor Date: Fri, 27 Feb 2026 09:32:34 +0100 Subject: [PATCH 05/40] wording polish --- .../contrib/chat/browser/widget/input/chatModelPicker.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/chat/browser/widget/input/chatModelPicker.ts b/src/vs/workbench/contrib/chat/browser/widget/input/chatModelPicker.ts index f7426562e70f1..13eb42eb77edb 100644 --- a/src/vs/workbench/contrib/chat/browser/widget/input/chatModelPicker.ts +++ b/src/vs/workbench/contrib/chat/browser/widget/input/chatModelPicker.ts @@ -417,7 +417,7 @@ function createUnavailableModelItem( let hoverContent: MarkdownString; if (reason === 'upgrade') { hoverContent = new MarkdownString('', { isTrusted: true, supportThemeIcons: true }); - hoverContent.appendMarkdown(localize('chat.modelPicker.upgradeHover', "[Upgrade to Copilot Pro](command:workbench.action.chat.upgradePlan \" \") with a free 30 day trial to use this model.")); + hoverContent.appendMarkdown(localize('chat.modelPicker.upgradeHover', "[Upgrade to Copilot Pro](command:workbench.action.chat.upgradePlan \" \") with a free 30 day trial to use the best models.")); } else if (reason === 'update') { hoverContent = getUpdateHoverContent(updateStateType); } else { From 00ae6e49daddd4e2c06a488635164b7c1db54c4b Mon Sep 17 00:00:00 2001 From: Isidor Nikolic Date: Fri, 27 Feb 2026 09:37:02 +0100 Subject: [PATCH 06/40] Apply suggestion from @Copilot Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../contrib/chat/browser/widget/input/chatModelPicker.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/chat/browser/widget/input/chatModelPicker.ts b/src/vs/workbench/contrib/chat/browser/widget/input/chatModelPicker.ts index 13eb42eb77edb..87f29886ef348 100644 --- a/src/vs/workbench/contrib/chat/browser/widget/input/chatModelPicker.ts +++ b/src/vs/workbench/contrib/chat/browser/widget/input/chatModelPicker.ts @@ -417,7 +417,7 @@ function createUnavailableModelItem( let hoverContent: MarkdownString; if (reason === 'upgrade') { hoverContent = new MarkdownString('', { isTrusted: true, supportThemeIcons: true }); - hoverContent.appendMarkdown(localize('chat.modelPicker.upgradeHover', "[Upgrade to Copilot Pro](command:workbench.action.chat.upgradePlan \" \") with a free 30 day trial to use the best models.")); + hoverContent.appendMarkdown(localize('chat.modelPicker.upgradeHover', "[Upgrade to GitHub Copilot Pro](command:workbench.action.chat.upgradePlan \" \") with a free 30 day trial to use the best models.")); } else if (reason === 'update') { hoverContent = getUpdateHoverContent(updateStateType); } else { From ab978b9611ff755a16a2b2f849af09c43774e334 Mon Sep 17 00:00:00 2001 From: Isidor Date: Fri, 27 Feb 2026 09:37:44 +0100 Subject: [PATCH 07/40] thanks copilot for good feedback --- .../contrib/chat/browser/widget/input/chatModelPicker.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/chat/browser/widget/input/chatModelPicker.ts b/src/vs/workbench/contrib/chat/browser/widget/input/chatModelPicker.ts index 87f29886ef348..14e13bea97aa3 100644 --- a/src/vs/workbench/contrib/chat/browser/widget/input/chatModelPicker.ts +++ b/src/vs/workbench/contrib/chat/browser/widget/input/chatModelPicker.ts @@ -417,7 +417,7 @@ function createUnavailableModelItem( let hoverContent: MarkdownString; if (reason === 'upgrade') { hoverContent = new MarkdownString('', { isTrusted: true, supportThemeIcons: true }); - hoverContent.appendMarkdown(localize('chat.modelPicker.upgradeHover', "[Upgrade to GitHub Copilot Pro](command:workbench.action.chat.upgradePlan \" \") with a free 30 day trial to use the best models.")); + hoverContent.appendMarkdown(localize('chat.modelPicker.upgradeHover', "[Upgrade to GitHub Copilot Pro](command:workbench.action.chat.upgradePlan \" \") with a free 30-day trial to use the best models.")); } else if (reason === 'update') { hoverContent = getUpdateHoverContent(updateStateType); } else { From 673360f32a919c274b15f7e9297c8b0e650b65e0 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Fri, 27 Feb 2026 17:52:42 +0100 Subject: [PATCH 08/40] sessions - add letterpress (#298265) * sessions - add letterpress * ccr --- .../chat/browser/media/chatWelcomePart.css | 13 ++--- .../code-icon-agent-sessions-exploration.svg | 49 ----------------- .../code-icon-agent-sessions-insider.svg | 49 ----------------- .../media/code-icon-agent-sessions-stable.svg | 53 ------------------- .../media/code-icon-agent-sessions.svg | 53 ------------------- .../media/letterpress-sessions-dark.svg | 6 +++ .../media/letterpress-sessions-light.svg | 6 +++ 7 files changed, 15 insertions(+), 214 deletions(-) delete mode 100644 src/vs/sessions/contrib/chat/browser/media/code-icon-agent-sessions-exploration.svg delete mode 100644 src/vs/sessions/contrib/chat/browser/media/code-icon-agent-sessions-insider.svg delete mode 100644 src/vs/sessions/contrib/chat/browser/media/code-icon-agent-sessions-stable.svg delete mode 100644 src/vs/sessions/contrib/chat/browser/media/code-icon-agent-sessions.svg create mode 100644 src/vs/sessions/contrib/chat/browser/media/letterpress-sessions-dark.svg create mode 100644 src/vs/sessions/contrib/chat/browser/media/letterpress-sessions-light.svg diff --git a/src/vs/sessions/contrib/chat/browser/media/chatWelcomePart.css b/src/vs/sessions/contrib/chat/browser/media/chatWelcomePart.css index 6df45c10a07d0..57410a89fc0f3 100644 --- a/src/vs/sessions/contrib/chat/browser/media/chatWelcomePart.css +++ b/src/vs/sessions/contrib/chat/browser/media/chatWelcomePart.css @@ -35,7 +35,7 @@ width: 100%; max-width: 200px; aspect-ratio: 1/1; - background-image: url('../../../../../workbench/browser/parts/editor/media/letterpress-dark.svg'); + background-image: url('./letterpress-sessions-dark.svg'); background-size: contain; background-position: center; background-repeat: no-repeat; @@ -43,16 +43,9 @@ margin-bottom: 20px; } -.vs .chat-full-welcome-letterpress { - background-image: url('../../../../../workbench/browser/parts/editor/media/letterpress-light.svg'); -} - +.vs .chat-full-welcome-letterpress, .hc-light .chat-full-welcome-letterpress { - background-image: url('../../../../../workbench/browser/parts/editor/media/letterpress-hcLight.svg'); -} - -.hc-black .chat-full-welcome-letterpress { - background-image: url('../../../../../workbench/browser/parts/editor/media/letterpress-hcDark.svg'); + background-image: url('./letterpress-sessions-light.svg'); } @container (max-height: 350px) { diff --git a/src/vs/sessions/contrib/chat/browser/media/code-icon-agent-sessions-exploration.svg b/src/vs/sessions/contrib/chat/browser/media/code-icon-agent-sessions-exploration.svg deleted file mode 100644 index 81991ee80fa80..0000000000000 --- a/src/vs/sessions/contrib/chat/browser/media/code-icon-agent-sessions-exploration.svg +++ /dev/null @@ -1,49 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/vs/sessions/contrib/chat/browser/media/code-icon-agent-sessions-insider.svg b/src/vs/sessions/contrib/chat/browser/media/code-icon-agent-sessions-insider.svg deleted file mode 100644 index 55db4d45e46fb..0000000000000 --- a/src/vs/sessions/contrib/chat/browser/media/code-icon-agent-sessions-insider.svg +++ /dev/null @@ -1,49 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/vs/sessions/contrib/chat/browser/media/code-icon-agent-sessions-stable.svg b/src/vs/sessions/contrib/chat/browser/media/code-icon-agent-sessions-stable.svg deleted file mode 100644 index e26c10e038aa0..0000000000000 --- a/src/vs/sessions/contrib/chat/browser/media/code-icon-agent-sessions-stable.svg +++ /dev/null @@ -1,53 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/vs/sessions/contrib/chat/browser/media/code-icon-agent-sessions.svg b/src/vs/sessions/contrib/chat/browser/media/code-icon-agent-sessions.svg deleted file mode 100644 index e26c10e038aa0..0000000000000 --- a/src/vs/sessions/contrib/chat/browser/media/code-icon-agent-sessions.svg +++ /dev/null @@ -1,53 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/vs/sessions/contrib/chat/browser/media/letterpress-sessions-dark.svg b/src/vs/sessions/contrib/chat/browser/media/letterpress-sessions-dark.svg new file mode 100644 index 0000000000000..623629695fc17 --- /dev/null +++ b/src/vs/sessions/contrib/chat/browser/media/letterpress-sessions-dark.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/vs/sessions/contrib/chat/browser/media/letterpress-sessions-light.svg b/src/vs/sessions/contrib/chat/browser/media/letterpress-sessions-light.svg new file mode 100644 index 0000000000000..29dfd5459d13c --- /dev/null +++ b/src/vs/sessions/contrib/chat/browser/media/letterpress-sessions-light.svg @@ -0,0 +1,6 @@ + + + + + + From 655503402ade6be0a9d3b421cd0154240ece9490 Mon Sep 17 00:00:00 2001 From: Megan Rogge Date: Fri, 27 Feb 2026 10:57:58 -0600 Subject: [PATCH 09/40] fix accessibility issue, setting not respected (#298283) fixes #296720 --- .../widget/chatContentParts/chatProgressContentPart.ts | 8 ++++---- .../widget/chatContentParts/chatThinkingContentPart.ts | 5 ++++- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatProgressContentPart.ts b/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatProgressContentPart.ts index 615ae0c63dcdf..4a3ec940760e8 100644 --- a/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatProgressContentPart.ts +++ b/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatProgressContentPart.ts @@ -4,13 +4,14 @@ *--------------------------------------------------------------------------------------------*/ import { $, append } from '../../../../../../base/browser/dom.js'; +import { IRenderedMarkdown, renderAsPlaintext } from '../../../../../../base/browser/markdownRenderer.js'; import { alert } from '../../../../../../base/browser/ui/aria/aria.js'; import { Codicon } from '../../../../../../base/common/codicons.js'; import { MarkdownString, type IMarkdownString } from '../../../../../../base/common/htmlContent.js'; +import { stripIcons } from '../../../../../../base/common/iconLabels.js'; import { Disposable, DisposableStore, MutableDisposable } from '../../../../../../base/common/lifecycle.js'; import { ThemeIcon } from '../../../../../../base/common/themables.js'; import { IMarkdownRenderer } from '../../../../../../platform/markdown/browser/markdownRenderer.js'; -import { IRenderedMarkdown } from '../../../../../../base/browser/markdownRenderer.js'; import { IInstantiationService } from '../../../../../../platform/instantiation/common/instantiation.js'; import { localize } from '../../../../../../nls.js'; import { IChatProgressMessage, IChatTask, IChatTaskSerialized, IChatToolInvocation, IChatToolInvocationSerialized } from '../../../common/chatService/chatService.js'; @@ -61,10 +62,9 @@ export class ChatProgressContentPart extends Disposable implements IChatContentP return; } - if (this.showSpinner && !this.configurationService.getValue(AccessibilityWorkbenchSettingId.VerboseChatProgressUpdates)) { - // TODO@roblourens is this the right place for this? + if (this.showSpinner && this.configurationService.getValue(AccessibilityWorkbenchSettingId.VerboseChatProgressUpdates)) { // this step is in progress, communicate it to SR users - alert(progress.content.value); + alert(stripIcons(renderAsPlaintext(progress.content))); } const isLoadingIcon = icon && ThemeIcon.isEqual(icon, ThemeIcon.modify(Codicon.loading, 'spin')); // Even if callers request shimmer, only the active (spinner-visible) progress row should animate. diff --git a/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatThinkingContentPart.ts b/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatThinkingContentPart.ts index b47f7312a4c76..473db6ff51a02 100644 --- a/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatThinkingContentPart.ts +++ b/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatThinkingContentPart.ts @@ -14,6 +14,7 @@ import { ChatConfiguration, ThinkingDisplayMode } from '../../../common/constant import { ChatTreeItem } from '../../chat.js'; import { IInstantiationService } from '../../../../../../platform/instantiation/common/instantiation.js'; import { IConfigurationService } from '../../../../../../platform/configuration/common/configuration.js'; +import { AccessibilityWorkbenchSettingId } from '../../../../accessibility/browser/accessibilityConfiguration.js'; import { MarkdownString } from '../../../../../../base/common/htmlContent.js'; import { IRenderedMarkdown } from '../../../../../../base/browser/markdownRenderer.js'; import { IMarkdownRenderer } from '../../../../../../platform/markdown/browser/markdownRenderer.js'; @@ -261,7 +262,9 @@ export class ChatThinkingContentPart extends ChatCollapsibleContentPart implemen } // Alert screen reader users that thinking has started - alert(localize('chat.thinking.started', 'Thinking')); + if (this.configurationService.getValue(AccessibilityWorkbenchSettingId.VerboseChatProgressUpdates)) { + alert(localize('chat.thinking.started', 'Thinking')); + } if (configuredMode === ThinkingDisplayMode.Collapsed) { this.setExpanded(false); From c2328b1e656cfff223dfb98c4f9471422b112125 Mon Sep 17 00:00:00 2001 From: Logan Ramos Date: Fri, 27 Feb 2026 11:58:02 -0500 Subject: [PATCH 10/40] Fix cache issues caused by multiple session types (#298289) --- .../browser/widget/input/chatInputPart.ts | 33 ++++++++++--------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/src/vs/workbench/contrib/chat/browser/widget/input/chatInputPart.ts b/src/vs/workbench/contrib/chat/browser/widget/input/chatInputPart.ts index 57a0106718a43..1502fd802342e 100644 --- a/src/vs/workbench/contrib/chat/browser/widget/input/chatInputPart.ts +++ b/src/vs/workbench/contrib/chat/browser/widget/input/chatInputPart.ts @@ -613,17 +613,7 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge this.initSelectedModel(); - this._register(this.languageModelsService.onDidChangeLanguageModels((vendor) => { - // Remove vendor from cache since the models changed and what is stored is no longer valid - // TODO @lramos15 - The cache should be less confusing since we have the LM Service cache + the view cache interacting weirdly - this.storageService.store( - CachedLanguageModelsKey, - this.storageService.getObject(CachedLanguageModelsKey, StorageScope.APPLICATION, []).filter(m => !m.identifier.startsWith(vendor)), - StorageScope.APPLICATION, - StorageTarget.MACHINE - ); - - // We've changed models and the current one is no longer available. Select a new one + this._register(this.languageModelsService.onDidChangeLanguageModels(() => { const selectedModel = this._currentLanguageModel ? this.getModels().find(m => m.identifier === this._currentLanguageModel.get()?.identifier) : undefined; if (!this.currentLanguageModel || !selectedModel) { this.setCurrentLanguageModelToDefault(); @@ -1061,12 +1051,25 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge private getModels(): ILanguageModelChatMetadataAndIdentifier[] { const cachedModels = this.storageService.getObject(CachedLanguageModelsKey, StorageScope.APPLICATION, []); - let models = this.languageModelsService.getLanguageModelIds() + const liveModels = this.languageModelsService.getLanguageModelIds() .map(modelId => ({ identifier: modelId, metadata: this.languageModelsService.lookupLanguageModel(modelId)! })); - if (models.length === 0 || models.some(m => m.metadata.isDefaultForLocation[this.location]) === false) { - models = cachedModels; - } else { + + // Merge live models with cached models per-vendor. For vendors whose + // models have resolved, use the live data. For vendors that are still + // contributed but haven't resolved yet (startup race), keep their + // cached models. Vendors that are no longer contributed at all (e.g. + // extension uninstalled) are evicted from the cache. + let models: ILanguageModelChatMetadataAndIdentifier[]; + if (liveModels.length > 0) { + const liveVendors = new Set(liveModels.map(m => m.metadata.vendor)); + const contributedVendors = new Set(this.languageModelsService.getVendors().map(v => v.vendor)); + models = [ + ...liveModels, + ...cachedModels.filter(m => !liveVendors.has(m.metadata.vendor) && contributedVendors.has(m.metadata.vendor)), + ]; this.storageService.store(CachedLanguageModelsKey, models, StorageScope.APPLICATION, StorageTarget.MACHINE); + } else { + models = cachedModels; } models.sort((a, b) => a.metadata.name.localeCompare(b.metadata.name)); From 3272ea62f31b6f924bdce5dd0b5acdb47973f9d6 Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Fri, 27 Feb 2026 15:35:56 +0100 Subject: [PATCH 11/40] updates screenshot pipeline & baseline --- .github/workflows/screenshot-test.yml | 35 ++++----------------------- 1 file changed, 5 insertions(+), 30 deletions(-) diff --git a/.github/workflows/screenshot-test.yml b/.github/workflows/screenshot-test.yml index 0b082e81a24d9..411e8dd585ef3 100644 --- a/.github/workflows/screenshot-test.yml +++ b/.github/workflows/screenshot-test.yml @@ -10,8 +10,6 @@ on: permissions: contents: read - pull-requests: write - checks: write statuses: write concurrency: @@ -96,41 +94,18 @@ jobs: REPORT="test/componentFixtures/.screenshots/report/report.json" if [ -f "$REPORT" ]; then CHANGED=$(node -e "const r = require('./$REPORT'); console.log(r.summary.added + r.summary.removed + r.summary.changed)") - TITLE="📸 ${CHANGED} screenshots changed" - CONCLUSION="neutral" + TITLE="📸 ⚠️ ${CHANGED} screenshots changed" else - TITLE="📸 Screenshots match" - CONCLUSION="success" + TITLE="📸 ✅ Screenshots match" fi SHA="${{ github.event.pull_request.head.sha || github.sha }}" DETAILS_URL="https://hediet-ghartifactpreview.azurewebsites.net/${{ github.repository }}/run/${{ github.run_id }}/component-explorer/___explorer.html?report=./screenshot-report/report.json" - EXPLORER_PUSHED=false - if gh api "repos/${{ github.repository }}/check-runs" \ - --input - < Date: Fri, 27 Feb 2026 15:56:01 +0100 Subject: [PATCH 12/40] updates baseline --- .../.screenshots/baseline/aiStats/AiStatsHover/Dark.png | 4 ++-- .../chatQuestionCarousel/MultiSelectQuestion/Dark.png | 3 +++ .../chatQuestionCarousel/MultiSelectQuestion/Light.png | 3 +++ .../baseline/chatQuestionCarousel/MultipleQuestions/Dark.png | 3 +++ .../baseline/chatQuestionCarousel/MultipleQuestions/Light.png | 3 +++ .../baseline/chatQuestionCarousel/NoSkip/Dark.png | 3 +++ .../baseline/chatQuestionCarousel/NoSkip/Light.png | 3 +++ .../chatQuestionCarousel/SingleSelectQuestion/Dark.png | 3 +++ .../chatQuestionCarousel/SingleSelectQuestion/Light.png | 3 +++ .../baseline/chatQuestionCarousel/SingleTextQuestion/Dark.png | 3 +++ .../chatQuestionCarousel/SingleTextQuestion/Light.png | 3 +++ .../baseline/chatQuestionCarousel/SkippedSummary/Dark.png | 3 +++ .../baseline/chatQuestionCarousel/SkippedSummary/Light.png | 3 +++ .../baseline/chatQuestionCarousel/SubmittedSummary/Dark.png | 3 +++ .../baseline/chatQuestionCarousel/SubmittedSummary/Light.png | 3 +++ .../baseline/codeActionList/GroupedCodeActions/Dark.png | 3 +++ .../baseline/codeActionList/GroupedCodeActions/Light.png | 3 +++ .../baseline/codeActionList/SimpleQuickFixes/Dark.png | 3 +++ .../baseline/codeActionList/SimpleQuickFixes/Light.png | 3 +++ .../.screenshots/baseline/findWidget/Find/Dark.png | 3 +++ .../.screenshots/baseline/findWidget/Find/Light.png | 3 +++ .../.screenshots/baseline/findWidget/FindAndReplace/Dark.png | 3 +++ .../.screenshots/baseline/findWidget/FindAndReplace/Light.png | 3 +++ .../baseline/inlineCompletionsExtras/HintsToolbar/Dark.png | 3 +++ .../baseline/inlineCompletionsExtras/HintsToolbar/Light.png | 3 +++ .../inlineCompletionsExtras/HintsToolbarHovered/Dark.png | 3 +++ .../inlineCompletionsExtras/HintsToolbarHovered/Light.png | 3 +++ .../baseline/inlineCompletionsExtras/JumpToHint/Dark.png | 3 +++ .../baseline/inlineCompletionsExtras/JumpToHint/Light.png | 3 +++ .../inlineCompletionsExtras/LongDistanceHint/Dark.png | 3 +++ .../inlineCompletionsExtras/LongDistanceHint/Light.png | 3 +++ .../InstructionFilesWithAgentInstructions/Dark.png | 3 +++ .../InstructionFilesWithAgentInstructions/Light.png | 3 +++ .../baseline/promptFilePickers/PromptFiles/Dark.png | 3 +++ .../baseline/promptFilePickers/PromptFiles/Light.png | 3 +++ .../.screenshots/baseline/renameWidget/RenameClass/Dark.png | 3 +++ .../.screenshots/baseline/renameWidget/RenameClass/Light.png | 3 +++ .../baseline/renameWidget/RenameVariable/Dark.png | 3 +++ .../baseline/renameWidget/RenameVariable/Light.png | 3 +++ .../baseline/suggestWidget/MethodCompletions/Dark.png | 3 +++ .../baseline/suggestWidget/MethodCompletions/Light.png | 3 +++ .../.screenshots/baseline/suggestWidget/MixedKinds/Dark.png | 3 +++ .../.screenshots/baseline/suggestWidget/MixedKinds/Light.png | 3 +++ .../baseline/updateWidget/AvailableForDownload/Dark.png | 3 +++ .../baseline/updateWidget/AvailableForDownload/Light.png | 3 +++ .../baseline/updateWidget/CheckingForUpdates/Dark.png | 3 +++ .../baseline/updateWidget/CheckingForUpdates/Light.png | 3 +++ .../.screenshots/baseline/updateWidget/Downloaded/Dark.png | 3 +++ .../.screenshots/baseline/updateWidget/Downloaded/Light.png | 3 +++ .../baseline/updateWidget/Downloading0Percent/Dark.png | 3 +++ .../baseline/updateWidget/Downloading0Percent/Light.png | 3 +++ .../baseline/updateWidget/Downloading100Percent/Dark.png | 3 +++ .../baseline/updateWidget/Downloading100Percent/Light.png | 3 +++ .../baseline/updateWidget/Downloading30Percent/Dark.png | 3 +++ .../baseline/updateWidget/Downloading30Percent/Light.png | 3 +++ .../baseline/updateWidget/Downloading65Percent/Dark.png | 3 +++ .../baseline/updateWidget/Downloading65Percent/Light.png | 3 +++ .../baseline/updateWidget/DownloadingIndeterminate/Dark.png | 3 +++ .../baseline/updateWidget/DownloadingIndeterminate/Light.png | 3 +++ .../.screenshots/baseline/updateWidget/Overwriting/Dark.png | 3 +++ .../.screenshots/baseline/updateWidget/Overwriting/Light.png | 3 +++ .../.screenshots/baseline/updateWidget/Ready/Dark.png | 3 +++ .../.screenshots/baseline/updateWidget/Ready/Light.png | 3 +++ .../.screenshots/baseline/updateWidget/Updating/Dark.png | 3 +++ .../.screenshots/baseline/updateWidget/Updating/Light.png | 3 +++ 65 files changed, 194 insertions(+), 2 deletions(-) create mode 100644 test/componentFixtures/.screenshots/baseline/chatQuestionCarousel/MultiSelectQuestion/Dark.png create mode 100644 test/componentFixtures/.screenshots/baseline/chatQuestionCarousel/MultiSelectQuestion/Light.png create mode 100644 test/componentFixtures/.screenshots/baseline/chatQuestionCarousel/MultipleQuestions/Dark.png create mode 100644 test/componentFixtures/.screenshots/baseline/chatQuestionCarousel/MultipleQuestions/Light.png create mode 100644 test/componentFixtures/.screenshots/baseline/chatQuestionCarousel/NoSkip/Dark.png create mode 100644 test/componentFixtures/.screenshots/baseline/chatQuestionCarousel/NoSkip/Light.png create mode 100644 test/componentFixtures/.screenshots/baseline/chatQuestionCarousel/SingleSelectQuestion/Dark.png create mode 100644 test/componentFixtures/.screenshots/baseline/chatQuestionCarousel/SingleSelectQuestion/Light.png create mode 100644 test/componentFixtures/.screenshots/baseline/chatQuestionCarousel/SingleTextQuestion/Dark.png create mode 100644 test/componentFixtures/.screenshots/baseline/chatQuestionCarousel/SingleTextQuestion/Light.png create mode 100644 test/componentFixtures/.screenshots/baseline/chatQuestionCarousel/SkippedSummary/Dark.png create mode 100644 test/componentFixtures/.screenshots/baseline/chatQuestionCarousel/SkippedSummary/Light.png create mode 100644 test/componentFixtures/.screenshots/baseline/chatQuestionCarousel/SubmittedSummary/Dark.png create mode 100644 test/componentFixtures/.screenshots/baseline/chatQuestionCarousel/SubmittedSummary/Light.png create mode 100644 test/componentFixtures/.screenshots/baseline/codeActionList/GroupedCodeActions/Dark.png create mode 100644 test/componentFixtures/.screenshots/baseline/codeActionList/GroupedCodeActions/Light.png create mode 100644 test/componentFixtures/.screenshots/baseline/codeActionList/SimpleQuickFixes/Dark.png create mode 100644 test/componentFixtures/.screenshots/baseline/codeActionList/SimpleQuickFixes/Light.png create mode 100644 test/componentFixtures/.screenshots/baseline/findWidget/Find/Dark.png create mode 100644 test/componentFixtures/.screenshots/baseline/findWidget/Find/Light.png create mode 100644 test/componentFixtures/.screenshots/baseline/findWidget/FindAndReplace/Dark.png create mode 100644 test/componentFixtures/.screenshots/baseline/findWidget/FindAndReplace/Light.png create mode 100644 test/componentFixtures/.screenshots/baseline/inlineCompletionsExtras/HintsToolbar/Dark.png create mode 100644 test/componentFixtures/.screenshots/baseline/inlineCompletionsExtras/HintsToolbar/Light.png create mode 100644 test/componentFixtures/.screenshots/baseline/inlineCompletionsExtras/HintsToolbarHovered/Dark.png create mode 100644 test/componentFixtures/.screenshots/baseline/inlineCompletionsExtras/HintsToolbarHovered/Light.png create mode 100644 test/componentFixtures/.screenshots/baseline/inlineCompletionsExtras/JumpToHint/Dark.png create mode 100644 test/componentFixtures/.screenshots/baseline/inlineCompletionsExtras/JumpToHint/Light.png create mode 100644 test/componentFixtures/.screenshots/baseline/inlineCompletionsExtras/LongDistanceHint/Dark.png create mode 100644 test/componentFixtures/.screenshots/baseline/inlineCompletionsExtras/LongDistanceHint/Light.png create mode 100644 test/componentFixtures/.screenshots/baseline/promptFilePickers/InstructionFilesWithAgentInstructions/Dark.png create mode 100644 test/componentFixtures/.screenshots/baseline/promptFilePickers/InstructionFilesWithAgentInstructions/Light.png create mode 100644 test/componentFixtures/.screenshots/baseline/promptFilePickers/PromptFiles/Dark.png create mode 100644 test/componentFixtures/.screenshots/baseline/promptFilePickers/PromptFiles/Light.png create mode 100644 test/componentFixtures/.screenshots/baseline/renameWidget/RenameClass/Dark.png create mode 100644 test/componentFixtures/.screenshots/baseline/renameWidget/RenameClass/Light.png create mode 100644 test/componentFixtures/.screenshots/baseline/renameWidget/RenameVariable/Dark.png create mode 100644 test/componentFixtures/.screenshots/baseline/renameWidget/RenameVariable/Light.png create mode 100644 test/componentFixtures/.screenshots/baseline/suggestWidget/MethodCompletions/Dark.png create mode 100644 test/componentFixtures/.screenshots/baseline/suggestWidget/MethodCompletions/Light.png create mode 100644 test/componentFixtures/.screenshots/baseline/suggestWidget/MixedKinds/Dark.png create mode 100644 test/componentFixtures/.screenshots/baseline/suggestWidget/MixedKinds/Light.png create mode 100644 test/componentFixtures/.screenshots/baseline/updateWidget/AvailableForDownload/Dark.png create mode 100644 test/componentFixtures/.screenshots/baseline/updateWidget/AvailableForDownload/Light.png create mode 100644 test/componentFixtures/.screenshots/baseline/updateWidget/CheckingForUpdates/Dark.png create mode 100644 test/componentFixtures/.screenshots/baseline/updateWidget/CheckingForUpdates/Light.png create mode 100644 test/componentFixtures/.screenshots/baseline/updateWidget/Downloaded/Dark.png create mode 100644 test/componentFixtures/.screenshots/baseline/updateWidget/Downloaded/Light.png create mode 100644 test/componentFixtures/.screenshots/baseline/updateWidget/Downloading0Percent/Dark.png create mode 100644 test/componentFixtures/.screenshots/baseline/updateWidget/Downloading0Percent/Light.png create mode 100644 test/componentFixtures/.screenshots/baseline/updateWidget/Downloading100Percent/Dark.png create mode 100644 test/componentFixtures/.screenshots/baseline/updateWidget/Downloading100Percent/Light.png create mode 100644 test/componentFixtures/.screenshots/baseline/updateWidget/Downloading30Percent/Dark.png create mode 100644 test/componentFixtures/.screenshots/baseline/updateWidget/Downloading30Percent/Light.png create mode 100644 test/componentFixtures/.screenshots/baseline/updateWidget/Downloading65Percent/Dark.png create mode 100644 test/componentFixtures/.screenshots/baseline/updateWidget/Downloading65Percent/Light.png create mode 100644 test/componentFixtures/.screenshots/baseline/updateWidget/DownloadingIndeterminate/Dark.png create mode 100644 test/componentFixtures/.screenshots/baseline/updateWidget/DownloadingIndeterminate/Light.png create mode 100644 test/componentFixtures/.screenshots/baseline/updateWidget/Overwriting/Dark.png create mode 100644 test/componentFixtures/.screenshots/baseline/updateWidget/Overwriting/Light.png create mode 100644 test/componentFixtures/.screenshots/baseline/updateWidget/Ready/Dark.png create mode 100644 test/componentFixtures/.screenshots/baseline/updateWidget/Ready/Light.png create mode 100644 test/componentFixtures/.screenshots/baseline/updateWidget/Updating/Dark.png create mode 100644 test/componentFixtures/.screenshots/baseline/updateWidget/Updating/Light.png diff --git a/test/componentFixtures/.screenshots/baseline/aiStats/AiStatsHover/Dark.png b/test/componentFixtures/.screenshots/baseline/aiStats/AiStatsHover/Dark.png index bfe8d842cf7fe..89032243eae7f 100644 --- a/test/componentFixtures/.screenshots/baseline/aiStats/AiStatsHover/Dark.png +++ b/test/componentFixtures/.screenshots/baseline/aiStats/AiStatsHover/Dark.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b0f41bf819fed7de2b99f15776cdb0d353f9bfaa4526dbb857f12be7c1343881 -size 15185 +oid sha256:cea3d365efe7e033cfd1fb8bc408fa0853d769af9cf7fcd8c1217d7c1e7982ba +size 15184 diff --git a/test/componentFixtures/.screenshots/baseline/chatQuestionCarousel/MultiSelectQuestion/Dark.png b/test/componentFixtures/.screenshots/baseline/chatQuestionCarousel/MultiSelectQuestion/Dark.png new file mode 100644 index 0000000000000..b5f1d62d15e21 --- /dev/null +++ b/test/componentFixtures/.screenshots/baseline/chatQuestionCarousel/MultiSelectQuestion/Dark.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:05f0f518e03f8b91e2178761c977215bd2561b10b04ad69685aa054231cd81be +size 15058 diff --git a/test/componentFixtures/.screenshots/baseline/chatQuestionCarousel/MultiSelectQuestion/Light.png b/test/componentFixtures/.screenshots/baseline/chatQuestionCarousel/MultiSelectQuestion/Light.png new file mode 100644 index 0000000000000..8d17c778055ca --- /dev/null +++ b/test/componentFixtures/.screenshots/baseline/chatQuestionCarousel/MultiSelectQuestion/Light.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2c5de42c54bcd1d35f59711f2c8c9c24f747df926017f1c3a52e3703c9d69da7 +size 15326 diff --git a/test/componentFixtures/.screenshots/baseline/chatQuestionCarousel/MultipleQuestions/Dark.png b/test/componentFixtures/.screenshots/baseline/chatQuestionCarousel/MultipleQuestions/Dark.png new file mode 100644 index 0000000000000..597e7cbbc672e --- /dev/null +++ b/test/componentFixtures/.screenshots/baseline/chatQuestionCarousel/MultipleQuestions/Dark.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7510376219beff4c9bb17bccb3de3631a633bda27fe53d6418309de484167688 +size 7506 diff --git a/test/componentFixtures/.screenshots/baseline/chatQuestionCarousel/MultipleQuestions/Light.png b/test/componentFixtures/.screenshots/baseline/chatQuestionCarousel/MultipleQuestions/Light.png new file mode 100644 index 0000000000000..93470614a41e7 --- /dev/null +++ b/test/componentFixtures/.screenshots/baseline/chatQuestionCarousel/MultipleQuestions/Light.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8918a56e08760211087b9cd0c798758cb7a55c002fcce1b343d06fd9f078197f +size 7434 diff --git a/test/componentFixtures/.screenshots/baseline/chatQuestionCarousel/NoSkip/Dark.png b/test/componentFixtures/.screenshots/baseline/chatQuestionCarousel/NoSkip/Dark.png new file mode 100644 index 0000000000000..356200049e46c --- /dev/null +++ b/test/componentFixtures/.screenshots/baseline/chatQuestionCarousel/NoSkip/Dark.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a324c6cde2596228ddc260d04688bf5153860b7e7de5b41f9211b456285ee581 +size 25804 diff --git a/test/componentFixtures/.screenshots/baseline/chatQuestionCarousel/NoSkip/Light.png b/test/componentFixtures/.screenshots/baseline/chatQuestionCarousel/NoSkip/Light.png new file mode 100644 index 0000000000000..2b1bfefce81b7 --- /dev/null +++ b/test/componentFixtures/.screenshots/baseline/chatQuestionCarousel/NoSkip/Light.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0eb74e618241b7d863bf8bac7132204b332c47e44e15a9c0b12270fa31a4fb71 +size 25874 diff --git a/test/componentFixtures/.screenshots/baseline/chatQuestionCarousel/SingleSelectQuestion/Dark.png b/test/componentFixtures/.screenshots/baseline/chatQuestionCarousel/SingleSelectQuestion/Dark.png new file mode 100644 index 0000000000000..1ecda11f8e889 --- /dev/null +++ b/test/componentFixtures/.screenshots/baseline/chatQuestionCarousel/SingleSelectQuestion/Dark.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1d5ede2eec1393f07f015cd724e9bb0a84492d85b175577705e195ee948e80ab +size 26210 diff --git a/test/componentFixtures/.screenshots/baseline/chatQuestionCarousel/SingleSelectQuestion/Light.png b/test/componentFixtures/.screenshots/baseline/chatQuestionCarousel/SingleSelectQuestion/Light.png new file mode 100644 index 0000000000000..5025b7c37cdcf --- /dev/null +++ b/test/componentFixtures/.screenshots/baseline/chatQuestionCarousel/SingleSelectQuestion/Light.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:695e11e18a05b7f9d0b73612edc7f4b0288408bedbf7fc259fccb2c7fe5f7dd0 +size 26288 diff --git a/test/componentFixtures/.screenshots/baseline/chatQuestionCarousel/SingleTextQuestion/Dark.png b/test/componentFixtures/.screenshots/baseline/chatQuestionCarousel/SingleTextQuestion/Dark.png new file mode 100644 index 0000000000000..2bc00d0ba8436 --- /dev/null +++ b/test/componentFixtures/.screenshots/baseline/chatQuestionCarousel/SingleTextQuestion/Dark.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d03152872902d21cea55c0d8ba464894c9a6ec77e7a58f68360c3be26a9a62a4 +size 7302 diff --git a/test/componentFixtures/.screenshots/baseline/chatQuestionCarousel/SingleTextQuestion/Light.png b/test/componentFixtures/.screenshots/baseline/chatQuestionCarousel/SingleTextQuestion/Light.png new file mode 100644 index 0000000000000..26a90f10d7af8 --- /dev/null +++ b/test/componentFixtures/.screenshots/baseline/chatQuestionCarousel/SingleTextQuestion/Light.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d727ac8876b301c7bf81d799197b6a8b0962a95bc9eb9b269e28f6c1eb4acd88 +size 7246 diff --git a/test/componentFixtures/.screenshots/baseline/chatQuestionCarousel/SkippedSummary/Dark.png b/test/componentFixtures/.screenshots/baseline/chatQuestionCarousel/SkippedSummary/Dark.png new file mode 100644 index 0000000000000..ccf46b5de69d9 --- /dev/null +++ b/test/componentFixtures/.screenshots/baseline/chatQuestionCarousel/SkippedSummary/Dark.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a3e31fb939e811c76b4fb03a7211cc84b86794dbdce2ecf26d1d42324dc86fd4 +size 2099 diff --git a/test/componentFixtures/.screenshots/baseline/chatQuestionCarousel/SkippedSummary/Light.png b/test/componentFixtures/.screenshots/baseline/chatQuestionCarousel/SkippedSummary/Light.png new file mode 100644 index 0000000000000..29bea3c013db4 --- /dev/null +++ b/test/componentFixtures/.screenshots/baseline/chatQuestionCarousel/SkippedSummary/Light.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8d7fd7e2f20d9a7a8e2ea867e0383e88291547b5e9d2c04642a84b5087491f64 +size 2064 diff --git a/test/componentFixtures/.screenshots/baseline/chatQuestionCarousel/SubmittedSummary/Dark.png b/test/componentFixtures/.screenshots/baseline/chatQuestionCarousel/SubmittedSummary/Dark.png new file mode 100644 index 0000000000000..7b0b53c68a447 --- /dev/null +++ b/test/componentFixtures/.screenshots/baseline/chatQuestionCarousel/SubmittedSummary/Dark.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c84efc6a1c010c303da05377ae980ead28d0f7412d0ce0e49bfc66ce23c766d3 +size 20333 diff --git a/test/componentFixtures/.screenshots/baseline/chatQuestionCarousel/SubmittedSummary/Light.png b/test/componentFixtures/.screenshots/baseline/chatQuestionCarousel/SubmittedSummary/Light.png new file mode 100644 index 0000000000000..858f4e5ccd34d --- /dev/null +++ b/test/componentFixtures/.screenshots/baseline/chatQuestionCarousel/SubmittedSummary/Light.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1cf2233bec9a1ab64995e6168081da43e485d6b2388f868648613d63034160b8 +size 18278 diff --git a/test/componentFixtures/.screenshots/baseline/codeActionList/GroupedCodeActions/Dark.png b/test/componentFixtures/.screenshots/baseline/codeActionList/GroupedCodeActions/Dark.png new file mode 100644 index 0000000000000..b48c12e655ed1 --- /dev/null +++ b/test/componentFixtures/.screenshots/baseline/codeActionList/GroupedCodeActions/Dark.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b99678e6d41e30c874e0517eb6d97ccb3eaece31c489482fae81dd92904051c9 +size 14963 diff --git a/test/componentFixtures/.screenshots/baseline/codeActionList/GroupedCodeActions/Light.png b/test/componentFixtures/.screenshots/baseline/codeActionList/GroupedCodeActions/Light.png new file mode 100644 index 0000000000000..8b2121d3a7c79 --- /dev/null +++ b/test/componentFixtures/.screenshots/baseline/codeActionList/GroupedCodeActions/Light.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bfaa85a662524e06f3d8323bf9a4655822d36567ffa438db85719a79addb6cd3 +size 14439 diff --git a/test/componentFixtures/.screenshots/baseline/codeActionList/SimpleQuickFixes/Dark.png b/test/componentFixtures/.screenshots/baseline/codeActionList/SimpleQuickFixes/Dark.png new file mode 100644 index 0000000000000..f82d6f544e6cc --- /dev/null +++ b/test/componentFixtures/.screenshots/baseline/codeActionList/SimpleQuickFixes/Dark.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:38e0cc34e642669cd200ac977f5e8948c100c100457f202b20a642ca211ab959 +size 6540 diff --git a/test/componentFixtures/.screenshots/baseline/codeActionList/SimpleQuickFixes/Light.png b/test/componentFixtures/.screenshots/baseline/codeActionList/SimpleQuickFixes/Light.png new file mode 100644 index 0000000000000..ecbb1c1dc430c --- /dev/null +++ b/test/componentFixtures/.screenshots/baseline/codeActionList/SimpleQuickFixes/Light.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9dfd9431a64258c6939f06c59d9163d33b65278cfd3ace4ae3c269f1e7e12d40 +size 6111 diff --git a/test/componentFixtures/.screenshots/baseline/findWidget/Find/Dark.png b/test/componentFixtures/.screenshots/baseline/findWidget/Find/Dark.png new file mode 100644 index 0000000000000..55c823622c787 --- /dev/null +++ b/test/componentFixtures/.screenshots/baseline/findWidget/Find/Dark.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ed115cf70c25bc400d265a08db2e1d6a4d7596674d7a6ddc932ca1ad33ccaa25 +size 33367 diff --git a/test/componentFixtures/.screenshots/baseline/findWidget/Find/Light.png b/test/componentFixtures/.screenshots/baseline/findWidget/Find/Light.png new file mode 100644 index 0000000000000..9e80b63bb4819 --- /dev/null +++ b/test/componentFixtures/.screenshots/baseline/findWidget/Find/Light.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0cfebc3c9b7caa2d40cfb8db5b47ae6f5a446bb72883bdce5198ed5d296ae82f +size 32889 diff --git a/test/componentFixtures/.screenshots/baseline/findWidget/FindAndReplace/Dark.png b/test/componentFixtures/.screenshots/baseline/findWidget/FindAndReplace/Dark.png new file mode 100644 index 0000000000000..cc9b2aa43769a --- /dev/null +++ b/test/componentFixtures/.screenshots/baseline/findWidget/FindAndReplace/Dark.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5d3a4d62c5226a9ca16b2327d95337a68286107a4fb12d1d5bc43530f17f6b1d +size 33379 diff --git a/test/componentFixtures/.screenshots/baseline/findWidget/FindAndReplace/Light.png b/test/componentFixtures/.screenshots/baseline/findWidget/FindAndReplace/Light.png new file mode 100644 index 0000000000000..c8a7325251209 --- /dev/null +++ b/test/componentFixtures/.screenshots/baseline/findWidget/FindAndReplace/Light.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:522ba17bdd1d4378c0be262631d8e6bb1fd867f2999c07c06c4991cd9971a4cb +size 33114 diff --git a/test/componentFixtures/.screenshots/baseline/inlineCompletionsExtras/HintsToolbar/Dark.png b/test/componentFixtures/.screenshots/baseline/inlineCompletionsExtras/HintsToolbar/Dark.png new file mode 100644 index 0000000000000..201fc1a7bf5ae --- /dev/null +++ b/test/componentFixtures/.screenshots/baseline/inlineCompletionsExtras/HintsToolbar/Dark.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a88fb3139a351b8c46df4309f64ed71210c456d4a89aad6b087ee512e26d9e1b +size 9762 diff --git a/test/componentFixtures/.screenshots/baseline/inlineCompletionsExtras/HintsToolbar/Light.png b/test/componentFixtures/.screenshots/baseline/inlineCompletionsExtras/HintsToolbar/Light.png new file mode 100644 index 0000000000000..be9dca0e21be0 --- /dev/null +++ b/test/componentFixtures/.screenshots/baseline/inlineCompletionsExtras/HintsToolbar/Light.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d0679cbdb00bacb421b6c8c65b632211a5dd153ae4c698c7a49903e53632310f +size 9569 diff --git a/test/componentFixtures/.screenshots/baseline/inlineCompletionsExtras/HintsToolbarHovered/Dark.png b/test/componentFixtures/.screenshots/baseline/inlineCompletionsExtras/HintsToolbarHovered/Dark.png new file mode 100644 index 0000000000000..201fc1a7bf5ae --- /dev/null +++ b/test/componentFixtures/.screenshots/baseline/inlineCompletionsExtras/HintsToolbarHovered/Dark.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a88fb3139a351b8c46df4309f64ed71210c456d4a89aad6b087ee512e26d9e1b +size 9762 diff --git a/test/componentFixtures/.screenshots/baseline/inlineCompletionsExtras/HintsToolbarHovered/Light.png b/test/componentFixtures/.screenshots/baseline/inlineCompletionsExtras/HintsToolbarHovered/Light.png new file mode 100644 index 0000000000000..be9dca0e21be0 --- /dev/null +++ b/test/componentFixtures/.screenshots/baseline/inlineCompletionsExtras/HintsToolbarHovered/Light.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d0679cbdb00bacb421b6c8c65b632211a5dd153ae4c698c7a49903e53632310f +size 9569 diff --git a/test/componentFixtures/.screenshots/baseline/inlineCompletionsExtras/JumpToHint/Dark.png b/test/componentFixtures/.screenshots/baseline/inlineCompletionsExtras/JumpToHint/Dark.png new file mode 100644 index 0000000000000..37bbb987300a6 --- /dev/null +++ b/test/componentFixtures/.screenshots/baseline/inlineCompletionsExtras/JumpToHint/Dark.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4c3e7be1da3065615074aa5678fd7ca38dd7b3906573fcd555ee9e249d9d645f +size 15252 diff --git a/test/componentFixtures/.screenshots/baseline/inlineCompletionsExtras/JumpToHint/Light.png b/test/componentFixtures/.screenshots/baseline/inlineCompletionsExtras/JumpToHint/Light.png new file mode 100644 index 0000000000000..ea8fe1b7068b2 --- /dev/null +++ b/test/componentFixtures/.screenshots/baseline/inlineCompletionsExtras/JumpToHint/Light.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:054c0dcab2a00526f7fe63440a7e782618f03b9396f40e6a31b8e28e7ea59145 +size 14846 diff --git a/test/componentFixtures/.screenshots/baseline/inlineCompletionsExtras/LongDistanceHint/Dark.png b/test/componentFixtures/.screenshots/baseline/inlineCompletionsExtras/LongDistanceHint/Dark.png new file mode 100644 index 0000000000000..83d5938ca6c74 --- /dev/null +++ b/test/componentFixtures/.screenshots/baseline/inlineCompletionsExtras/LongDistanceHint/Dark.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:05deae07ae1a6a5f738d6ebd4d475ed2e7d14630977b8b64cdae9030da2885ff +size 55645 diff --git a/test/componentFixtures/.screenshots/baseline/inlineCompletionsExtras/LongDistanceHint/Light.png b/test/componentFixtures/.screenshots/baseline/inlineCompletionsExtras/LongDistanceHint/Light.png new file mode 100644 index 0000000000000..23db3df30fb8c --- /dev/null +++ b/test/componentFixtures/.screenshots/baseline/inlineCompletionsExtras/LongDistanceHint/Light.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d9d81860fc8c296f9cc718ed3e6690669eb0f7301c17ae2f15639c984d499178 +size 54993 diff --git a/test/componentFixtures/.screenshots/baseline/promptFilePickers/InstructionFilesWithAgentInstructions/Dark.png b/test/componentFixtures/.screenshots/baseline/promptFilePickers/InstructionFilesWithAgentInstructions/Dark.png new file mode 100644 index 0000000000000..dba2c92968eda --- /dev/null +++ b/test/componentFixtures/.screenshots/baseline/promptFilePickers/InstructionFilesWithAgentInstructions/Dark.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8c54a17b190dde0caa1f175b1ef025850a6ede44f03d8d124859355c309aa28a +size 27557 diff --git a/test/componentFixtures/.screenshots/baseline/promptFilePickers/InstructionFilesWithAgentInstructions/Light.png b/test/componentFixtures/.screenshots/baseline/promptFilePickers/InstructionFilesWithAgentInstructions/Light.png new file mode 100644 index 0000000000000..63742c15bcda1 --- /dev/null +++ b/test/componentFixtures/.screenshots/baseline/promptFilePickers/InstructionFilesWithAgentInstructions/Light.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:eac6ff34521293e8f1f7e70f3f1e4227cc371861763fe954cce62d49b181955b +size 26846 diff --git a/test/componentFixtures/.screenshots/baseline/promptFilePickers/PromptFiles/Dark.png b/test/componentFixtures/.screenshots/baseline/promptFilePickers/PromptFiles/Dark.png new file mode 100644 index 0000000000000..ffc64ba9aac75 --- /dev/null +++ b/test/componentFixtures/.screenshots/baseline/promptFilePickers/PromptFiles/Dark.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:099e8f6e3b7c1c33fae6a75f47e387ab7f87536953607ec0f3a7b5160e0d4d59 +size 23377 diff --git a/test/componentFixtures/.screenshots/baseline/promptFilePickers/PromptFiles/Light.png b/test/componentFixtures/.screenshots/baseline/promptFilePickers/PromptFiles/Light.png new file mode 100644 index 0000000000000..c9ced02aeb75c --- /dev/null +++ b/test/componentFixtures/.screenshots/baseline/promptFilePickers/PromptFiles/Light.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0e7def912d49d13cd496386ef22a39df862a558e5585b01bfc46fd6f5f3276d4 +size 22969 diff --git a/test/componentFixtures/.screenshots/baseline/renameWidget/RenameClass/Dark.png b/test/componentFixtures/.screenshots/baseline/renameWidget/RenameClass/Dark.png new file mode 100644 index 0000000000000..26eeb8a87511d --- /dev/null +++ b/test/componentFixtures/.screenshots/baseline/renameWidget/RenameClass/Dark.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1191cc4ad1b12b31b28e94fa6305b2c91a3ea399580f04cd93b5387c8b58b89d +size 20408 diff --git a/test/componentFixtures/.screenshots/baseline/renameWidget/RenameClass/Light.png b/test/componentFixtures/.screenshots/baseline/renameWidget/RenameClass/Light.png new file mode 100644 index 0000000000000..cd7a92aa849df --- /dev/null +++ b/test/componentFixtures/.screenshots/baseline/renameWidget/RenameClass/Light.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e18bb8e20cf85b06825dea19140a88a9fd0d9ec844db939d8550956e9049a2f2 +size 19982 diff --git a/test/componentFixtures/.screenshots/baseline/renameWidget/RenameVariable/Dark.png b/test/componentFixtures/.screenshots/baseline/renameWidget/RenameVariable/Dark.png new file mode 100644 index 0000000000000..2b11099af61cb --- /dev/null +++ b/test/componentFixtures/.screenshots/baseline/renameWidget/RenameVariable/Dark.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:cc8f9f9295ae0e9b7f2c9215e788c0a0516d7c667f30f61fbadcfafdb13bb2e6 +size 21470 diff --git a/test/componentFixtures/.screenshots/baseline/renameWidget/RenameVariable/Light.png b/test/componentFixtures/.screenshots/baseline/renameWidget/RenameVariable/Light.png new file mode 100644 index 0000000000000..909659b1b5fe1 --- /dev/null +++ b/test/componentFixtures/.screenshots/baseline/renameWidget/RenameVariable/Light.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6d8a254da836fa81f53516bbc992394aeb91f7297cba4d13a8c5485ab3d46d7e +size 20862 diff --git a/test/componentFixtures/.screenshots/baseline/suggestWidget/MethodCompletions/Dark.png b/test/componentFixtures/.screenshots/baseline/suggestWidget/MethodCompletions/Dark.png new file mode 100644 index 0000000000000..20494f462540f --- /dev/null +++ b/test/componentFixtures/.screenshots/baseline/suggestWidget/MethodCompletions/Dark.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:869d6db0575e1e0dce468df0227cd68c1725d7341c5efb5b47ab929d3717761d +size 22978 diff --git a/test/componentFixtures/.screenshots/baseline/suggestWidget/MethodCompletions/Light.png b/test/componentFixtures/.screenshots/baseline/suggestWidget/MethodCompletions/Light.png new file mode 100644 index 0000000000000..aefc052d100ea --- /dev/null +++ b/test/componentFixtures/.screenshots/baseline/suggestWidget/MethodCompletions/Light.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:cff0734d5bbb48f8900e8cff6892aab851f58206db69a4c0a49425c0981f3967 +size 22208 diff --git a/test/componentFixtures/.screenshots/baseline/suggestWidget/MixedKinds/Dark.png b/test/componentFixtures/.screenshots/baseline/suggestWidget/MixedKinds/Dark.png new file mode 100644 index 0000000000000..f44709ad5bfd2 --- /dev/null +++ b/test/componentFixtures/.screenshots/baseline/suggestWidget/MixedKinds/Dark.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b84d2c246a9594012baff0a70212b6768e6b0d784936c4f2f9d37378cf813248 +size 13541 diff --git a/test/componentFixtures/.screenshots/baseline/suggestWidget/MixedKinds/Light.png b/test/componentFixtures/.screenshots/baseline/suggestWidget/MixedKinds/Light.png new file mode 100644 index 0000000000000..2f008a94f3e4b --- /dev/null +++ b/test/componentFixtures/.screenshots/baseline/suggestWidget/MixedKinds/Light.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3c3aba099609c37eb2e58de791958665aec9fd8d2931b2208ec91515cac41b96 +size 13386 diff --git a/test/componentFixtures/.screenshots/baseline/updateWidget/AvailableForDownload/Dark.png b/test/componentFixtures/.screenshots/baseline/updateWidget/AvailableForDownload/Dark.png new file mode 100644 index 0000000000000..4024eff5bc975 --- /dev/null +++ b/test/componentFixtures/.screenshots/baseline/updateWidget/AvailableForDownload/Dark.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:63aa8f046ab23ac6bd53722db86fd254c7cd88a487f45feb68cc9a9bbd18300f +size 1209 diff --git a/test/componentFixtures/.screenshots/baseline/updateWidget/AvailableForDownload/Light.png b/test/componentFixtures/.screenshots/baseline/updateWidget/AvailableForDownload/Light.png new file mode 100644 index 0000000000000..5baee83328743 --- /dev/null +++ b/test/componentFixtures/.screenshots/baseline/updateWidget/AvailableForDownload/Light.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6d69bf362154015616fbb8c95052466061b7982f54203faea3ae89ad5afeaec3 +size 1221 diff --git a/test/componentFixtures/.screenshots/baseline/updateWidget/CheckingForUpdates/Dark.png b/test/componentFixtures/.screenshots/baseline/updateWidget/CheckingForUpdates/Dark.png new file mode 100644 index 0000000000000..1197206909f45 --- /dev/null +++ b/test/componentFixtures/.screenshots/baseline/updateWidget/CheckingForUpdates/Dark.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:43c9b8702922e8892a0cf20afc053e8ac56cdff65c02a9d47cb0183262da7bd4 +size 1908 diff --git a/test/componentFixtures/.screenshots/baseline/updateWidget/CheckingForUpdates/Light.png b/test/componentFixtures/.screenshots/baseline/updateWidget/CheckingForUpdates/Light.png new file mode 100644 index 0000000000000..11d36a2938778 --- /dev/null +++ b/test/componentFixtures/.screenshots/baseline/updateWidget/CheckingForUpdates/Light.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e0a17ec5b2f0e18be88383e491a09260654ce828236e37c11d5028e6ac326daa +size 1924 diff --git a/test/componentFixtures/.screenshots/baseline/updateWidget/Downloaded/Dark.png b/test/componentFixtures/.screenshots/baseline/updateWidget/Downloaded/Dark.png new file mode 100644 index 0000000000000..0e6b503cc23c4 --- /dev/null +++ b/test/componentFixtures/.screenshots/baseline/updateWidget/Downloaded/Dark.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6897095d4c9d17a31bce693d2ce0f800d13ec56f2e27f4c5ec303ee64c7d19c3 +size 2189 diff --git a/test/componentFixtures/.screenshots/baseline/updateWidget/Downloaded/Light.png b/test/componentFixtures/.screenshots/baseline/updateWidget/Downloaded/Light.png new file mode 100644 index 0000000000000..91af710d8796d --- /dev/null +++ b/test/componentFixtures/.screenshots/baseline/updateWidget/Downloaded/Light.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3491ca579cf94b7148f4a943dc1e1a3eb44dd444d5268963c6a15a949d13bf88 +size 2056 diff --git a/test/componentFixtures/.screenshots/baseline/updateWidget/Downloading0Percent/Dark.png b/test/componentFixtures/.screenshots/baseline/updateWidget/Downloading0Percent/Dark.png new file mode 100644 index 0000000000000..db4f67e3b5d69 --- /dev/null +++ b/test/componentFixtures/.screenshots/baseline/updateWidget/Downloading0Percent/Dark.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f3345ce1dc95c59d627fd618ddbf2f4028f0e7b13528bd3325fe6882cfb73891 +size 1781 diff --git a/test/componentFixtures/.screenshots/baseline/updateWidget/Downloading0Percent/Light.png b/test/componentFixtures/.screenshots/baseline/updateWidget/Downloading0Percent/Light.png new file mode 100644 index 0000000000000..a59cf06f88803 --- /dev/null +++ b/test/componentFixtures/.screenshots/baseline/updateWidget/Downloading0Percent/Light.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7d4921395a33a571db185f7015160a23ee6e8ba3f82281a8ab4a935e43950b44 +size 1811 diff --git a/test/componentFixtures/.screenshots/baseline/updateWidget/Downloading100Percent/Dark.png b/test/componentFixtures/.screenshots/baseline/updateWidget/Downloading100Percent/Dark.png new file mode 100644 index 0000000000000..28c4dcb54780c --- /dev/null +++ b/test/componentFixtures/.screenshots/baseline/updateWidget/Downloading100Percent/Dark.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a7bc3e108e03debccd5881474ff30f42bf5c56a43a7b4525d3d2fc16b075b56d +size 2482 diff --git a/test/componentFixtures/.screenshots/baseline/updateWidget/Downloading100Percent/Light.png b/test/componentFixtures/.screenshots/baseline/updateWidget/Downloading100Percent/Light.png new file mode 100644 index 0000000000000..118bab91cc1da --- /dev/null +++ b/test/componentFixtures/.screenshots/baseline/updateWidget/Downloading100Percent/Light.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8df766b159576a0c12683af17f7d9ed391a2bd765743494f3760d8b415380c22 +size 2252 diff --git a/test/componentFixtures/.screenshots/baseline/updateWidget/Downloading30Percent/Dark.png b/test/componentFixtures/.screenshots/baseline/updateWidget/Downloading30Percent/Dark.png new file mode 100644 index 0000000000000..9bb317db8757f --- /dev/null +++ b/test/componentFixtures/.screenshots/baseline/updateWidget/Downloading30Percent/Dark.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1c1f6f054881033c6162405b99e99ce8f049b9b20d320a74abc07793987474d9 +size 2249 diff --git a/test/componentFixtures/.screenshots/baseline/updateWidget/Downloading30Percent/Light.png b/test/componentFixtures/.screenshots/baseline/updateWidget/Downloading30Percent/Light.png new file mode 100644 index 0000000000000..c97505c005c0f --- /dev/null +++ b/test/componentFixtures/.screenshots/baseline/updateWidget/Downloading30Percent/Light.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4b6101c92d7073116c81eba73ddc08c721c2e947b4f7714887c54ffb91284d4e +size 2138 diff --git a/test/componentFixtures/.screenshots/baseline/updateWidget/Downloading65Percent/Dark.png b/test/componentFixtures/.screenshots/baseline/updateWidget/Downloading65Percent/Dark.png new file mode 100644 index 0000000000000..c1853513bec44 --- /dev/null +++ b/test/componentFixtures/.screenshots/baseline/updateWidget/Downloading65Percent/Dark.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3179d62298aff75dfc01442a4589a61d83b6ba7f14c4b8441c9a688ca655738d +size 2434 diff --git a/test/componentFixtures/.screenshots/baseline/updateWidget/Downloading65Percent/Light.png b/test/componentFixtures/.screenshots/baseline/updateWidget/Downloading65Percent/Light.png new file mode 100644 index 0000000000000..8060149471e0d --- /dev/null +++ b/test/componentFixtures/.screenshots/baseline/updateWidget/Downloading65Percent/Light.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5e9dbcbf22233e5b48617067c8993a51c6b10afd940cd499270183e8eb4430f4 +size 2217 diff --git a/test/componentFixtures/.screenshots/baseline/updateWidget/DownloadingIndeterminate/Dark.png b/test/componentFixtures/.screenshots/baseline/updateWidget/DownloadingIndeterminate/Dark.png new file mode 100644 index 0000000000000..4b0fc104ee8c5 --- /dev/null +++ b/test/componentFixtures/.screenshots/baseline/updateWidget/DownloadingIndeterminate/Dark.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:13295a45a513349c0c8ae6129301d5f2fb89549cae3b4453c6962a770b6290ec +size 3716 diff --git a/test/componentFixtures/.screenshots/baseline/updateWidget/DownloadingIndeterminate/Light.png b/test/componentFixtures/.screenshots/baseline/updateWidget/DownloadingIndeterminate/Light.png new file mode 100644 index 0000000000000..d7a897ebda5d6 --- /dev/null +++ b/test/componentFixtures/.screenshots/baseline/updateWidget/DownloadingIndeterminate/Light.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:21dbc34d1ec2776453bc176631f2a0e9a03f7fcd528369efcb40fd5c49536c92 +size 3837 diff --git a/test/componentFixtures/.screenshots/baseline/updateWidget/Overwriting/Dark.png b/test/componentFixtures/.screenshots/baseline/updateWidget/Overwriting/Dark.png new file mode 100644 index 0000000000000..db4f67e3b5d69 --- /dev/null +++ b/test/componentFixtures/.screenshots/baseline/updateWidget/Overwriting/Dark.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f3345ce1dc95c59d627fd618ddbf2f4028f0e7b13528bd3325fe6882cfb73891 +size 1781 diff --git a/test/componentFixtures/.screenshots/baseline/updateWidget/Overwriting/Light.png b/test/componentFixtures/.screenshots/baseline/updateWidget/Overwriting/Light.png new file mode 100644 index 0000000000000..a59cf06f88803 --- /dev/null +++ b/test/componentFixtures/.screenshots/baseline/updateWidget/Overwriting/Light.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7d4921395a33a571db185f7015160a23ee6e8ba3f82281a8ab4a935e43950b44 +size 1811 diff --git a/test/componentFixtures/.screenshots/baseline/updateWidget/Ready/Dark.png b/test/componentFixtures/.screenshots/baseline/updateWidget/Ready/Dark.png new file mode 100644 index 0000000000000..017a1ebcebe3a --- /dev/null +++ b/test/componentFixtures/.screenshots/baseline/updateWidget/Ready/Dark.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f97568f25aeafee2be621a345675fb29afe6c17a6655eeb2b053e09a671f2fe7 +size 2116 diff --git a/test/componentFixtures/.screenshots/baseline/updateWidget/Ready/Light.png b/test/componentFixtures/.screenshots/baseline/updateWidget/Ready/Light.png new file mode 100644 index 0000000000000..230402c3327fb --- /dev/null +++ b/test/componentFixtures/.screenshots/baseline/updateWidget/Ready/Light.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:faf0132e6298ffe9f285c4a2d6b7a0ef13c440175a22fa8febaff6b881cb4907 +size 1932 diff --git a/test/componentFixtures/.screenshots/baseline/updateWidget/Updating/Dark.png b/test/componentFixtures/.screenshots/baseline/updateWidget/Updating/Dark.png new file mode 100644 index 0000000000000..4024eff5bc975 --- /dev/null +++ b/test/componentFixtures/.screenshots/baseline/updateWidget/Updating/Dark.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:63aa8f046ab23ac6bd53722db86fd254c7cd88a487f45feb68cc9a9bbd18300f +size 1209 diff --git a/test/componentFixtures/.screenshots/baseline/updateWidget/Updating/Light.png b/test/componentFixtures/.screenshots/baseline/updateWidget/Updating/Light.png new file mode 100644 index 0000000000000..5baee83328743 --- /dev/null +++ b/test/componentFixtures/.screenshots/baseline/updateWidget/Updating/Light.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6d69bf362154015616fbb8c95052466061b7982f54203faea3ae89ad5afeaec3 +size 1221 From d228467dd3acabaec0061c9df6f89f80ebfffcc9 Mon Sep 17 00:00:00 2001 From: Kyle Cutler <67761731+kycutler@users.noreply.github.com> Date: Fri, 27 Feb 2026 09:03:35 -0800 Subject: [PATCH 13/40] Fix flickering when using browser screenshot tool (#298080) * Fix flickering when using browser screenshot tool * feedback * fix * feedback --- .../browserView/common/browserView.ts | 9 +++++ .../browserView/common/playwrightService.ts | 20 +++++------ .../browserView/electron-main/browserView.ts | 10 ++---- .../electron-main/browserViewMainService.ts | 8 ++--- .../browserView/node/playwrightService.ts | 27 ++++++-------- .../contrib/browserView/common/browserView.ts | 26 +++++++++++--- .../browserViewWorkbenchService.ts | 33 +++++++++++------ .../tools/browserToolHelpers.ts | 12 +++++++ .../tools/screenshotBrowserTool.ts | 35 ++++++++++++++----- 9 files changed, 118 insertions(+), 62 deletions(-) diff --git a/src/vs/platform/browserView/common/browserView.ts b/src/vs/platform/browserView/common/browserView.ts index 28161016f83a3..43bcb59d6c66e 100644 --- a/src/vs/platform/browserView/common/browserView.ts +++ b/src/vs/platform/browserView/common/browserView.ts @@ -34,6 +34,7 @@ export interface IBrowserViewState { lastFavicon: string | undefined; lastError: IBrowserViewLoadError | undefined; storageScope: BrowserViewStorageScope; + zoomFactor: number; } export interface IBrowserViewNavigationEvent { @@ -153,6 +154,14 @@ export interface IBrowserViewService { */ destroyBrowserView(id: string): Promise; + /** + * Get the state of an existing browser view by ID, or throw if it doesn't exist + * @param id The browser view identifier + * @return The state of the browser view for the given ID + * @throws If no browser view exists for the given ID + */ + getState(id: string): Promise; + /** * Update the bounds of a browser view * @param id The browser view identifier diff --git a/src/vs/platform/browserView/common/playwrightService.ts b/src/vs/platform/browserView/common/playwrightService.ts index b49c50b5fb388..1615924a5cfe6 100644 --- a/src/vs/platform/browserView/common/playwrightService.ts +++ b/src/vs/platform/browserView/common/playwrightService.ts @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ import { Event } from '../../../base/common/event.js'; -import { VSBuffer } from '../../../base/common/buffer.js'; import { createDecorator } from '../../instantiation/common/instantiation.js'; export const IPlaywrightService = createDecorator('playwrightService'); @@ -63,23 +62,24 @@ export interface IPlaywrightService { getSummary(pageId: string): Promise; /** - * Run a function with access to a Playwright page. + * Run a function with access to a Playwright page and return its raw result, or throw an error. * The first function argument is always the Playwright `page` object, and additional arguments can be passed after. * @param pageId The browser view ID identifying the page to operate on. * @param fnDef The function code to execute. Should contain the function definition but not its invocation, e.g. `async (page, arg1, arg2) => { ... }`. * @param args Additional arguments to pass to the function after the `page` object. - * @returns The result of the function execution, including a page summary. + * @returns The result of the function execution. */ - invokeFunction(pageId: string, fnDef: string, ...args: unknown[]): Promise<{ result: unknown; summary: string }>; + invokeFunctionRaw(pageId: string, fnDef: string, ...args: unknown[]): Promise; /** - * Takes a screenshot of the current page viewport and returns it as a VSBuffer. - * @param pageId The browser view ID identifying the page to capture. - * @param selector Optional Playwright selector to capture a specific element instead of the viewport. - * @param fullPage Whether to capture the full scrollable page instead of just the viewport. - * @returns The screenshot image data. + * Run a function with access to a Playwright page and return a result for tool output, including error handling. + * The first function argument is always the Playwright `page` object, and additional arguments can be passed after. + * @param pageId The browser view ID identifying the page to operate on. + * @param fnDef The function code to execute. Should contain the function definition but not its invocation, e.g. `async (page, arg1, arg2) => { ... }`. + * @param args Additional arguments to pass to the function after the `page` object. + * @returns The result of the function execution, including a page summary. */ - captureScreenshot(pageId: string, selector?: string, fullPage?: boolean): Promise; + invokeFunction(pageId: string, fnDef: string, ...args: unknown[]): Promise<{ result: unknown; summary: string }>; /** * Responds to a file chooser dialog on the given page. diff --git a/src/vs/platform/browserView/electron-main/browserView.ts b/src/vs/platform/browserView/electron-main/browserView.ts index 45e5d838d277c..ec0c2fb6b895b 100644 --- a/src/vs/platform/browserView/electron-main/browserView.ts +++ b/src/vs/platform/browserView/electron-main/browserView.ts @@ -359,7 +359,8 @@ export class BrowserView extends Disposable implements ICDPTarget { lastScreenshot: this._lastScreenshot, lastFavicon: this._lastFavicon, lastError: this._lastError, - storageScope: this.session.storageScope + storageScope: this.session.storageScope, + zoomFactor: webContents.getZoomFactor() }; } @@ -509,13 +510,6 @@ export class BrowserView extends Disposable implements ICDPTarget { } } - /** - * Set the zoom factor of this view - */ - async setZoomFactor(zoomFactor: number): Promise { - await this._view.webContents.setZoomFactor(zoomFactor); - } - /** * Focus this view */ diff --git a/src/vs/platform/browserView/electron-main/browserViewMainService.ts b/src/vs/platform/browserView/electron-main/browserViewMainService.ts index 7db0af2ac3451..7d95fe8d3d3f9 100644 --- a/src/vs/platform/browserView/electron-main/browserViewMainService.ts +++ b/src/vs/platform/browserView/electron-main/browserViewMainService.ts @@ -278,6 +278,10 @@ export class BrowserViewMainService extends Disposable implements IBrowserViewMa return this._getBrowserView(id).onDidClose; } + async getState(id: string): Promise { + return this._getBrowserView(id).getState(); + } + async destroyBrowserView(id: string): Promise { return this.browserViews.deleteAndDispose(id); } @@ -330,10 +334,6 @@ export class BrowserViewMainService extends Disposable implements IBrowserViewMa return this._getBrowserView(id).dispatchKeyEvent(keyEvent); } - async setZoomFactor(id: string, zoomFactor: number): Promise { - return this._getBrowserView(id).setZoomFactor(zoomFactor); - } - async focus(id: string): Promise { return this._getBrowserView(id).focus(); } diff --git a/src/vs/platform/browserView/node/playwrightService.ts b/src/vs/platform/browserView/node/playwrightService.ts index 3016e0a3659e2..0a55710ec61f2 100644 --- a/src/vs/platform/browserView/node/playwrightService.ts +++ b/src/vs/platform/browserView/node/playwrightService.ts @@ -10,7 +10,6 @@ import { ILogService } from '../../log/common/log.js'; import { IPlaywrightService } from '../common/playwrightService.js'; import { IBrowserViewGroupRemoteService } from '../node/browserViewGroupRemoteService.js'; import { IBrowserViewGroup } from '../common/browserViewGroup.js'; -import { VSBuffer } from '../../../base/common/buffer.js'; import { PlaywrightTab } from './playwrightTab.js'; // eslint-disable-next-line local/code-import-patterns @@ -125,18 +124,22 @@ export class PlaywrightService extends Disposable implements IPlaywrightService return this._pages.getSummary(pageId, true); } + async invokeFunctionRaw(pageId: string, fnDef: string, ...args: unknown[]): Promise { + await this.initialize(); + + const vm = await import('vm'); + const fn = vm.compileFunction(`return (${fnDef})(page, ...args)`, ['page', 'args'], { parsingContext: vm.createContext() }); + + return this._pages.runAgainstPage(pageId, (page) => fn(page, args)); + } + async invokeFunction(pageId: string, fnDef: string, ...args: unknown[]): Promise<{ result: unknown; summary: string }> { this.logService.info(`[PlaywrightService] Invoking function on view ${pageId}`); try { - await this.initialize(); - - const vm = await import('vm'); - const fn = vm.compileFunction(`return (${fnDef})(page, ...args)`, ['page', 'args'], { parsingContext: vm.createContext() }); - let result; try { - result = await this._pages.runAgainstPage(pageId, (page) => fn(page, args)); + result = await this.invokeFunctionRaw(pageId, fnDef, ...args); } catch (err: unknown) { result = err instanceof Error ? err.message : String(err); } @@ -155,16 +158,6 @@ export class PlaywrightService extends Disposable implements IPlaywrightService } } - async captureScreenshot(pageId: string, selector?: string, fullPage?: boolean): Promise { - await this.initialize(); - return this._pages.runAgainstPage(pageId, async page => { - const screenshotBuffer = selector - ? await page.locator(selector).screenshot({ type: 'jpeg', quality: 80 }) - : await page.screenshot({ type: 'jpeg', quality: 80, fullPage: fullPage ?? false }); - return VSBuffer.wrap(screenshotBuffer); - }); - } - async replyToFileChooser(pageId: string, files: string[]): Promise<{ summary: string }> { await this.initialize(); const summary = await this._pages.replyToFileChooser(pageId, files); diff --git a/src/vs/workbench/contrib/browserView/common/browserView.ts b/src/vs/workbench/contrib/browserView/common/browserView.ts index 76f04a67f829d..7654a648a753e 100644 --- a/src/vs/workbench/contrib/browserView/common/browserView.ts +++ b/src/vs/workbench/contrib/browserView/common/browserView.ts @@ -76,6 +76,14 @@ export interface IBrowserViewWorkbenchService { */ getOrCreateBrowserViewModel(id: string): Promise; + /** + * Get an existing browser view model for the given ID + * @param id The browser view identifier + * @returns A browser view model that proxies to the main process + * @throws If no browser view exists for the given ID + */ + getBrowserViewModel(id: string): Promise; + /** * Clear all storage data for the global browser session */ @@ -105,9 +113,9 @@ export interface IBrowserViewModel extends IDisposable { readonly isDevToolsOpen: boolean; readonly canGoForward: boolean; readonly error: IBrowserViewLoadError | undefined; - readonly storageScope: BrowserViewStorageScope; readonly sharedWithAgent: boolean; + readonly zoomFactor: number; readonly onDidChangeSharedWithAgent: Event; readonly onDidNavigate: Event; @@ -123,7 +131,7 @@ export interface IBrowserViewModel extends IDisposable { readonly onDidClose: Event; readonly onWillDispose: Event; - initialize(): Promise; + initialize(create: boolean): Promise; layout(bounds: IBrowserViewBounds): Promise; setVisible(visible: boolean): Promise; @@ -156,6 +164,7 @@ export class BrowserViewModel extends Disposable implements IBrowserViewModel { private _error: IBrowserViewLoadError | undefined = undefined; private _storageScope: BrowserViewStorageScope = BrowserViewStorageScope.Ephemeral; private _sharedWithAgent: boolean = false; + private _zoomFactor: number = 1; private readonly _onDidChangeSharedWithAgent = this._register(new Emitter()); readonly onDidChangeSharedWithAgent: Event = this._onDidChangeSharedWithAgent.event; @@ -190,6 +199,7 @@ export class BrowserViewModel extends Disposable implements IBrowserViewModel { get error(): IBrowserViewLoadError | undefined { return this._error; } get storageScope(): BrowserViewStorageScope { return this._storageScope; } get sharedWithAgent(): boolean { return this._sharedWithAgent; } + get zoomFactor(): number { return this._zoomFactor; } get onDidNavigate(): Event { return this.browserViewService.onDynamicDidNavigate(this.id); @@ -236,9 +246,11 @@ export class BrowserViewModel extends Disposable implements IBrowserViewModel { } /** - * Initialize the model with the current state from the main process + * Initialize the model with the current state from the main process. + * @param create Whether to create the browser view if it doesn't already exist. + * @throws If the browser view doesn't exist and `create` is false, or if initialization fails */ - async initialize(): Promise { + async initialize(create: boolean): Promise { const dataStorageSetting = this.configurationService.getValue( 'workbench.browser.dataStorage' ) ?? BrowserViewStorageScope.Global; @@ -253,7 +265,9 @@ export class BrowserViewModel extends Disposable implements IBrowserViewModel { const dataStorage = isWorkspaceUntrusted ? BrowserViewStorageScope.Ephemeral : dataStorageSetting; const workspaceId = this.workspaceContextService.getWorkspace().id; - const state = await this.browserViewService.getOrCreateBrowserView(this.id, dataStorage, workspaceId); + const state = create + ? await this.browserViewService.getOrCreateBrowserView(this.id, dataStorage, workspaceId) + : await this.browserViewService.getState(this.id); this._url = state.url; this._title = state.title; @@ -268,6 +282,7 @@ export class BrowserViewModel extends Disposable implements IBrowserViewModel { this._error = state.lastError; this._storageScope = state.storageScope; this._sharedWithAgent = await this.playwrightService.isPageTracked(this.id); + this._zoomFactor = state.zoomFactor; // Set up state synchronization @@ -314,6 +329,7 @@ export class BrowserViewModel extends Disposable implements IBrowserViewModel { } async layout(bounds: IBrowserViewBounds): Promise { + this._zoomFactor = bounds.zoomFactor; return this.browserViewService.layout(this.id, bounds); } diff --git a/src/vs/workbench/contrib/browserView/electron-browser/browserViewWorkbenchService.ts b/src/vs/workbench/contrib/browserView/electron-browser/browserViewWorkbenchService.ts index 68d2376c587d1..c60a295cd5a55 100644 --- a/src/vs/workbench/contrib/browserView/electron-browser/browserViewWorkbenchService.ts +++ b/src/vs/workbench/contrib/browserView/electron-browser/browserViewWorkbenchService.ts @@ -27,6 +27,23 @@ export class BrowserViewWorkbenchService implements IBrowserViewWorkbenchService } async getOrCreateBrowserViewModel(id: string): Promise { + return this._getBrowserViewModel(id, true); + } + + async getBrowserViewModel(id: string): Promise { + return this._getBrowserViewModel(id, false); + } + + async clearGlobalStorage(): Promise { + return this._browserViewService.clearGlobalStorage(); + } + + async clearWorkspaceStorage(): Promise { + const workspaceId = this.workspaceContextService.getWorkspace().id; + return this._browserViewService.clearWorkspaceStorage(workspaceId); + } + + private async _getBrowserViewModel(id: string, create: boolean): Promise { let model = this._models.get(id); if (model) { return model; @@ -36,7 +53,12 @@ export class BrowserViewWorkbenchService implements IBrowserViewWorkbenchService this._models.set(id, model); // Initialize the model with current state - await model.initialize(); + try { + await model.initialize(create); + } catch (e) { + this._models.delete(id); + throw e; + } // Clean up model when disposed Event.once(model.onWillDispose)(() => { @@ -45,13 +67,4 @@ export class BrowserViewWorkbenchService implements IBrowserViewWorkbenchService return model; } - - async clearGlobalStorage(): Promise { - return this._browserViewService.clearGlobalStorage(); - } - - async clearWorkspaceStorage(): Promise { - const workspaceId = this.workspaceContextService.getWorkspace().id; - return this._browserViewService.clearWorkspaceStorage(workspaceId); - } } diff --git a/src/vs/workbench/contrib/browserView/electron-browser/tools/browserToolHelpers.ts b/src/vs/workbench/contrib/browserView/electron-browser/tools/browserToolHelpers.ts index e6981287fe2f1..04e48f2bab5c1 100644 --- a/src/vs/workbench/contrib/browserView/electron-browser/tools/browserToolHelpers.ts +++ b/src/vs/workbench/contrib/browserView/electron-browser/tools/browserToolHelpers.ts @@ -9,6 +9,18 @@ import { IToolResult } from '../../../chat/common/tools/languageModelToolsServic // eslint-disable-next-line local/code-import-patterns import type { Page } from 'playwright-core'; +/** + * Shared helper for running a Playwright function against a page and returning its result. + */ +export async function playwrightInvokeRaw( + playwrightService: IPlaywrightService, + pageId: string, + fn: (page: Page, ...args: TArgs) => Promise, + ...args: TArgs +): Promise { + return playwrightService.invokeFunctionRaw(pageId, fn.toString(), ...args); +} + /** * Shared helper for running a Playwright function against a page and returning * a tool result. Handles success/error formatting. diff --git a/src/vs/workbench/contrib/browserView/electron-browser/tools/screenshotBrowserTool.ts b/src/vs/workbench/contrib/browserView/electron-browser/tools/screenshotBrowserTool.ts index 831ca2bf8426f..b2bb1f9a3fed7 100644 --- a/src/vs/workbench/contrib/browserView/electron-browser/tools/screenshotBrowserTool.ts +++ b/src/vs/workbench/contrib/browserView/electron-browser/tools/screenshotBrowserTool.ts @@ -8,7 +8,8 @@ import { Codicon } from '../../../../../base/common/codicons.js'; import { localize } from '../../../../../nls.js'; import { IPlaywrightService } from '../../../../../platform/browserView/common/playwrightService.js'; import { ToolDataSource, type CountTokensCallback, type IPreparedToolInvocation, type IToolData, type IToolImpl, type IToolInvocation, type IToolInvocationPreparationContext, type IToolResult, type ToolProgress } from '../../../chat/common/tools/languageModelToolsService.js'; -import { errorResult } from './browserToolHelpers.js'; +import { IBrowserViewWorkbenchService } from '../../common/browserView.js'; +import { errorResult, playwrightInvokeRaw } from './browserToolHelpers.js'; import { OpenPageToolId } from './openBrowserTool.js'; import { ReadBrowserToolData } from './readBrowserTool.js'; @@ -29,16 +30,16 @@ export const ScreenshotBrowserToolData: IToolData = { }, selector: { type: 'string', - description: 'Playwright selector of an element to capture. If omitted, captures the whole page.' + description: 'Playwright selector of an element to capture. If omitted, captures the whole viewport.' }, ref: { type: 'string', - description: 'Element reference to capture. If omitted, captures the whole page.' + description: 'Element reference to capture. If omitted, captures the whole viewport.' }, - fullPage: { + scrollIntoViewIfNeeded: { type: 'boolean', - description: 'Set to true to capture the full scrollable page instead of just the viewport. Incompatible with selector/ref.' - }, + description: 'Whether to scroll the element into view before capturing. Defaults to false.', + } }, required: ['pageId'], }, @@ -48,11 +49,12 @@ interface IScreenshotBrowserToolParams { pageId: string; selector?: string; ref?: string; - fullPage?: boolean; + scrollIntoViewIfNeeded?: boolean; } export class ScreenshotBrowserTool implements IToolImpl { constructor( + @IBrowserViewWorkbenchService private readonly browserViewWorkbenchService: IBrowserViewWorkbenchService, @IPlaywrightService private readonly playwrightService: IPlaywrightService, ) { } @@ -75,7 +77,24 @@ export class ScreenshotBrowserTool implements IToolImpl { selector = `aria-ref=${params.ref}`; } - const screenshot = await this.playwrightService.captureScreenshot(params.pageId, selector, params.fullPage); + // Note that we don't use Playwright's screenshot methods because they cause brief flashing on the page, + // and also doesn't handle zooming well. + const browserViewModel = await this.browserViewWorkbenchService.getBrowserViewModel(params.pageId); // Throws if the given pageId doesn't exist + const bounds = selector && await playwrightInvokeRaw(this.playwrightService, params.pageId, async (page, selector, scrollIntoViewIfNeeded) => { + const locator = page.locator(selector); + if (scrollIntoViewIfNeeded) { + await locator.scrollIntoViewIfNeeded(); + } + return locator.boundingBox(); + }, selector, params.scrollIntoViewIfNeeded) || undefined; + const zoomFactor = browserViewModel.zoomFactor; + if (bounds) { + bounds.x *= zoomFactor; + bounds.y *= zoomFactor; + bounds.width *= zoomFactor; + bounds.height *= zoomFactor; + } + const screenshot = await browserViewModel.captureScreenshot({ rect: bounds }); return { content: [ From 03a53d950c325e9cbf237fd144d49a81b76a81f4 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Fri, 27 Feb 2026 18:07:59 +0100 Subject: [PATCH 14/40] sessions: fix trust dialogs for worktree (#298294) --- .../contrib/workspace/browser/workspaceFolderManagement.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/vs/sessions/contrib/workspace/browser/workspaceFolderManagement.ts b/src/vs/sessions/contrib/workspace/browser/workspaceFolderManagement.ts index 020c7861d46bf..09b03f5a160f9 100644 --- a/src/vs/sessions/contrib/workspace/browser/workspaceFolderManagement.ts +++ b/src/vs/sessions/contrib/workspace/browser/workspaceFolderManagement.ts @@ -85,10 +85,6 @@ export class WorkspaceFolderManagementContribution extends Disposable implements return; } - if (!this.isUriTrusted(session.repository)) { - return; - } - if (!this.isUriTrusted(session.worktree)) { await this.workspaceTrustManagementService.setUrisTrust([session.worktree], true); } From 98ad6b67c2a79c2c1d75b99b89e48c7e2d57d6e0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 27 Feb 2026 09:09:45 -0800 Subject: [PATCH 15/40] Bump hono from 4.12.0 to 4.12.2 (#297746) Bumps [hono](https://github.com/honojs/hono) from 4.12.0 to 4.12.2. - [Release notes](https://github.com/honojs/hono/releases) - [Commits](https://github.com/honojs/hono/compare/v4.12.0...v4.12.2) --- updated-dependencies: - dependency-name: hono dependency-version: 4.12.2 dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index b10be95329b35..3ec5dd73ec4ee 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10647,9 +10647,9 @@ } }, "node_modules/hono": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/hono/-/hono-4.12.0.tgz", - "integrity": "sha512-NekXntS5M94pUfiVZ8oXXK/kkri+5WpX2/Ik+LVsl+uvw+soj4roXIsPqO+XsWrAw20mOzaXOZf3Q7PfB9A/IA==", + "version": "4.12.3", + "resolved": "https://registry.npmjs.org/hono/-/hono-4.12.3.tgz", + "integrity": "sha512-SFsVSjp8sj5UumXOOFlkZOG6XS9SJDKw0TbwFeV+AJ8xlST8kxK5Z/5EYa111UY8732lK2S/xB653ceuaoGwpg==", "dev": true, "license": "MIT", "engines": { From 5b7dafcb12d2aa0c217ba6ef8b25983672f3f706 Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Fri, 27 Feb 2026 18:16:26 +0100 Subject: [PATCH 16/40] Add vscode-extras extension with npm up-to-date feature and related configurations (#298295) --- .../vscode-extras/package-lock.json | 16 ++ .vscode/extensions/vscode-extras/package.json | 38 ++++ .../extensions/vscode-extras/src/extension.ts | 51 +++++ .../vscode-extras/src/npmUpToDateFeature.ts | 176 +++++++++++++++ .../extensions/vscode-extras/tsconfig.json | 14 ++ .../package.json | 3 + build/gulpfile.extensions.ts | 1 + build/npm/dirs.ts | 1 + build/npm/fast-install.ts | 22 ++ build/npm/installStateHash.ts | 78 +++++++ build/npm/postinstall.ts | 205 ++++++++++++------ build/npm/preinstall.ts | 8 + 12 files changed, 548 insertions(+), 65 deletions(-) create mode 100644 .vscode/extensions/vscode-extras/package-lock.json create mode 100644 .vscode/extensions/vscode-extras/package.json create mode 100644 .vscode/extensions/vscode-extras/src/extension.ts create mode 100644 .vscode/extensions/vscode-extras/src/npmUpToDateFeature.ts create mode 100644 .vscode/extensions/vscode-extras/tsconfig.json create mode 100644 build/npm/fast-install.ts create mode 100644 build/npm/installStateHash.ts diff --git a/.vscode/extensions/vscode-extras/package-lock.json b/.vscode/extensions/vscode-extras/package-lock.json new file mode 100644 index 0000000000000..3268c74682804 --- /dev/null +++ b/.vscode/extensions/vscode-extras/package-lock.json @@ -0,0 +1,16 @@ +{ + "name": "vscode-extras", + "version": "0.0.1", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "vscode-extras", + "version": "0.0.1", + "license": "MIT", + "engines": { + "vscode": "^1.88.0" + } + } + } +} diff --git a/.vscode/extensions/vscode-extras/package.json b/.vscode/extensions/vscode-extras/package.json new file mode 100644 index 0000000000000..c773d5923c322 --- /dev/null +++ b/.vscode/extensions/vscode-extras/package.json @@ -0,0 +1,38 @@ +{ + "name": "vscode-extras", + "displayName": "VS Code Extras", + "description": "Extra utility features for the VS Code selfhost workspace", + "engines": { + "vscode": "^1.88.0" + }, + "version": "0.0.1", + "publisher": "ms-vscode", + "categories": [ + "Other" + ], + "activationEvents": [ + "workspaceContains:src/vscode-dts/vscode.d.ts" + ], + "main": "./out/extension.js", + "repository": { + "type": "git", + "url": "https://github.com/microsoft/vscode.git" + }, + "license": "MIT", + "scripts": { + "compile": "gulp compile-extension:vscode-extras", + "watch": "gulp watch-extension:vscode-extras" + }, + "contributes": { + "configuration": { + "title": "VS Code Extras", + "properties": { + "vscode-extras.npmUpToDateFeature.enabled": { + "type": "boolean", + "default": true, + "description": "Show a status bar warning when npm dependencies are out of date." + } + } + } + } +} diff --git a/.vscode/extensions/vscode-extras/src/extension.ts b/.vscode/extensions/vscode-extras/src/extension.ts new file mode 100644 index 0000000000000..6ed06c0026248 --- /dev/null +++ b/.vscode/extensions/vscode-extras/src/extension.ts @@ -0,0 +1,51 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as vscode from 'vscode'; +import { NpmUpToDateFeature } from './npmUpToDateFeature'; + +export class Extension extends vscode.Disposable { + private readonly _output: vscode.LogOutputChannel; + private _npmFeature: NpmUpToDateFeature | undefined; + + constructor(context: vscode.ExtensionContext) { + const disposables: vscode.Disposable[] = []; + super(() => disposables.forEach(d => d.dispose())); + + this._output = vscode.window.createOutputChannel('VS Code Extras', { log: true }); + disposables.push(this._output); + + this._updateNpmFeature(); + + disposables.push( + vscode.workspace.onDidChangeConfiguration(e => { + if (e.affectsConfiguration('vscode-extras.npmUpToDateFeature.enabled')) { + this._updateNpmFeature(); + } + }) + ); + } + + private _updateNpmFeature(): void { + const enabled = vscode.workspace.getConfiguration('vscode-extras').get('npmUpToDateFeature.enabled', true); + if (enabled && !this._npmFeature) { + this._npmFeature = new NpmUpToDateFeature(this._output); + } else if (!enabled && this._npmFeature) { + this._npmFeature.dispose(); + this._npmFeature = undefined; + } + } +} + +let extension: Extension | undefined; + +export function activate(context: vscode.ExtensionContext) { + extension = new Extension(context); + context.subscriptions.push(extension); +} + +export function deactivate() { + extension = undefined; +} diff --git a/.vscode/extensions/vscode-extras/src/npmUpToDateFeature.ts b/.vscode/extensions/vscode-extras/src/npmUpToDateFeature.ts new file mode 100644 index 0000000000000..b3f172eca1dc6 --- /dev/null +++ b/.vscode/extensions/vscode-extras/src/npmUpToDateFeature.ts @@ -0,0 +1,176 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as cp from 'child_process'; +import * as fs from 'fs'; +import * as path from 'path'; +import * as vscode from 'vscode'; + +interface FileHashes { + readonly [relativePath: string]: string; +} + +interface PostinstallState { + readonly nodeVersion: string; + readonly fileHashes: FileHashes; +} + +interface InstallState { + readonly root: string; + readonly current: PostinstallState; + readonly saved: PostinstallState | undefined; + readonly files: readonly string[]; +} + +export class NpmUpToDateFeature extends vscode.Disposable { + private readonly _statusBarItem: vscode.StatusBarItem; + private readonly _disposables: vscode.Disposable[] = []; + private _watchers: fs.FSWatcher[] = []; + private _terminal: vscode.Terminal | undefined; + + constructor(private readonly _output: vscode.LogOutputChannel) { + const disposables: vscode.Disposable[] = []; + super(() => { + disposables.forEach(d => d.dispose()); + for (const w of this._watchers) { + w.close(); + } + }); + this._disposables = disposables; + + this._statusBarItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left, 10000); + this._statusBarItem.name = 'npm Install State'; + this._statusBarItem.text = '$(warning) node_modules is stale - run npm i'; + this._statusBarItem.tooltip = 'Dependencies are out of date. Click to run npm install.'; + this._statusBarItem.command = 'vscode-extras.runNpmInstall'; + this._statusBarItem.backgroundColor = new vscode.ThemeColor('statusBarItem.warningBackground'); + this._disposables.push(this._statusBarItem); + + this._disposables.push( + vscode.commands.registerCommand('vscode-extras.runNpmInstall', () => this._runNpmInstall()) + ); + + this._disposables.push( + vscode.window.onDidCloseTerminal(t => { + if (t === this._terminal) { + this._terminal = undefined; + this._check(); + } + }) + ); + + this._check(); + } + + private _runNpmInstall(): void { + if (this._terminal) { + this._terminal.show(); + return; + } + const workspaceRoot = vscode.workspace.workspaceFolders?.[0]?.uri; + if (!workspaceRoot) { + return; + } + this._terminal = vscode.window.createTerminal({ name: 'npm install', cwd: workspaceRoot }); + this._terminal.sendText('node build/npm/fast-install.ts --force'); + this._terminal.show(); + + this._statusBarItem.text = '$(loading~spin) npm i'; + this._statusBarItem.tooltip = 'npm install is running...'; + this._statusBarItem.backgroundColor = undefined; + this._statusBarItem.command = 'vscode-extras.runNpmInstall'; + } + + private _queryState(): InstallState | undefined { + const workspaceRoot = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath; + if (!workspaceRoot) { + return undefined; + } + try { + const script = path.join(workspaceRoot, 'build', 'npm', 'installStateHash.ts'); + const output = cp.execFileSync(process.execPath, [script], { + cwd: workspaceRoot, + timeout: 10_000, + encoding: 'utf8', + }); + const parsed = JSON.parse(output.trim()); + this._output.trace('raw output:', output.trim()); + return parsed; + } catch (e) { + this._output.error('_queryState error:', e as any); + return undefined; + } + } + + private _check(): void { + const state = this._queryState(); + this._output.trace('state:', JSON.stringify(state, null, 2)); + if (!state) { + this._output.trace('no state, hiding'); + this._statusBarItem.hide(); + return; + } + + this._setupWatcher(state); + + const changedFiles = this._getChangedFiles(state); + this._output.trace('changedFiles:', JSON.stringify(changedFiles)); + + if (changedFiles.length === 0) { + this._statusBarItem.hide(); + } else { + this._statusBarItem.text = '$(warning) node_modules is stale - run npm i'; + const tooltip = new vscode.MarkdownString(); + tooltip.appendText('Dependencies are out of date. Click to run npm install.\n\nChanged files:\n'); + for (const file of changedFiles) { + tooltip.appendText(` • ${file}\n`); + } + this._statusBarItem.tooltip = tooltip; + this._statusBarItem.backgroundColor = new vscode.ThemeColor('statusBarItem.warningBackground'); + this._statusBarItem.show(); + } + } + + private _getChangedFiles(state: InstallState): string[] { + if (!state.saved) { + return ['(no postinstall state found)']; + } + const changed: string[] = []; + if (state.saved.nodeVersion !== state.current.nodeVersion) { + changed.push(`Node.js version (${state.saved.nodeVersion} → ${state.current.nodeVersion})`); + } + const allKeys = new Set([...Object.keys(state.current.fileHashes), ...Object.keys(state.saved.fileHashes)]); + for (const key of allKeys) { + if (state.current.fileHashes[key] !== state.saved.fileHashes[key]) { + changed.push(key); + } + } + return changed; + } + + private _setupWatcher(state: InstallState): void { + for (const w of this._watchers) { + w.close(); + } + this._watchers = []; + + let debounceTimer: ReturnType | undefined; + const scheduleCheck = () => { + if (debounceTimer) { + clearTimeout(debounceTimer); + } + debounceTimer = setTimeout(() => this._check(), 500); + }; + + for (const file of state.files) { + try { + const watcher = fs.watch(file, scheduleCheck); + this._watchers.push(watcher); + } catch { + // file may not exist yet + } + } + } +} diff --git a/.vscode/extensions/vscode-extras/tsconfig.json b/.vscode/extensions/vscode-extras/tsconfig.json new file mode 100644 index 0000000000000..9133c3bbf4b87 --- /dev/null +++ b/.vscode/extensions/vscode-extras/tsconfig.json @@ -0,0 +1,14 @@ +{ + "extends": "../../../extensions/tsconfig.base.json", + "compilerOptions": { + "rootDir": "./src", + "outDir": "./out", + "types": [ + "node" + ] + }, + "include": [ + "src/**/*", + "../../../src/vscode-dts/vscode.d.ts" + ] +} diff --git a/.vscode/extensions/vscode-selfhost-test-provider/package.json b/.vscode/extensions/vscode-selfhost-test-provider/package.json index 6f0db218fb254..1a894a5405532 100644 --- a/.vscode/extensions/vscode-selfhost-test-provider/package.json +++ b/.vscode/extensions/vscode-selfhost-test-provider/package.json @@ -6,6 +6,9 @@ "testObserver", "testRelatedCode" ], + "extensionDependencies": [ + "ms-vscode.vscode-extras" + ], "engines": { "vscode": "^1.88.0" }, diff --git a/build/gulpfile.extensions.ts b/build/gulpfile.extensions.ts index a2eb47535f4dd..e8ee8fa80f477 100644 --- a/build/gulpfile.extensions.ts +++ b/build/gulpfile.extensions.ts @@ -95,6 +95,7 @@ const compilations = [ '.vscode/extensions/vscode-selfhost-test-provider/tsconfig.json', '.vscode/extensions/vscode-selfhost-import-aid/tsconfig.json', + '.vscode/extensions/vscode-extras/tsconfig.json', ]; const getBaseUrl = (out: string) => `https://main.vscode-cdn.net/sourcemaps/${commit}/${out}`; diff --git a/build/npm/dirs.ts b/build/npm/dirs.ts index 48d76e2731a6e..b56884af25c52 100644 --- a/build/npm/dirs.ts +++ b/build/npm/dirs.ts @@ -60,6 +60,7 @@ export const dirs = [ 'test/mcp', '.vscode/extensions/vscode-selfhost-import-aid', '.vscode/extensions/vscode-selfhost-test-provider', + '.vscode/extensions/vscode-extras', ]; if (existsSync(`${import.meta.dirname}/../../.build/distro/npm`)) { diff --git a/build/npm/fast-install.ts b/build/npm/fast-install.ts new file mode 100644 index 0000000000000..ff9a7d2097cf2 --- /dev/null +++ b/build/npm/fast-install.ts @@ -0,0 +1,22 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as child_process from 'child_process'; +import { root, isUpToDate, forceInstallMessage } from './installStateHash.ts'; + +if (!process.argv.includes('--force') && isUpToDate()) { + console.log(`\x1b[32mAll dependencies up to date.\x1b[0m ${forceInstallMessage}`); + process.exit(0); +} + +const npm = process.platform === 'win32' ? 'npm.cmd' : 'npm'; +const result = child_process.spawnSync(npm, ['install'], { + cwd: root, + stdio: 'inherit', + shell: true, + env: { ...process.env, VSCODE_FORCE_INSTALL: '1' }, +}); + +process.exit(result.status ?? 1); diff --git a/build/npm/installStateHash.ts b/build/npm/installStateHash.ts new file mode 100644 index 0000000000000..79c0c130f5e28 --- /dev/null +++ b/build/npm/installStateHash.ts @@ -0,0 +1,78 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as crypto from 'crypto'; +import * as fs from 'fs'; +import path from 'path'; +import { dirs } from './dirs.ts'; + +export const root = fs.realpathSync.native(path.dirname(path.dirname(import.meta.dirname))); +export const stateFile = path.join(root, 'node_modules', '.postinstall-state'); +export const forceInstallMessage = 'Run \x1b[36mnode build/npm/fast-install.ts --force\x1b[0m to force a full install.'; + +export function collectInputFiles(): string[] { + const files: string[] = []; + + for (const dir of dirs) { + const base = dir === '' ? root : path.join(root, dir); + for (const file of ['package.json', '.npmrc']) { + const filePath = path.join(base, file); + if (fs.existsSync(filePath)) { + files.push(filePath); + } + } + } + + files.push(path.join(root, '.nvmrc')); + + return files; +} + +export interface PostinstallState { + readonly nodeVersion: string; + readonly fileHashes: Record; +} + +function hashFileContent(filePath: string): string { + const hash = crypto.createHash('sha256'); + hash.update(fs.readFileSync(filePath)); + return hash.digest('hex'); +} + +export function computeState(): PostinstallState { + const fileHashes: Record = {}; + for (const filePath of collectInputFiles()) { + fileHashes[path.relative(root, filePath)] = hashFileContent(filePath); + } + return { nodeVersion: process.versions.node, fileHashes }; +} + +export function readSavedState(): PostinstallState | undefined { + try { + return JSON.parse(fs.readFileSync(stateFile, 'utf8')); + } catch { + return undefined; + } +} + +export function isUpToDate(): boolean { + const saved = readSavedState(); + if (!saved) { + return false; + } + const current = computeState(); + return saved.nodeVersion === current.nodeVersion + && JSON.stringify(saved.fileHashes) === JSON.stringify(current.fileHashes); +} + +// When run directly, output state as JSON for tooling (e.g. the vscode-extras extension). +if (import.meta.filename === process.argv[1]) { + console.log(JSON.stringify({ + root, + current: computeState(), + saved: readSavedState(), + files: [...collectInputFiles(), stateFile], + })); +} diff --git a/build/npm/postinstall.ts b/build/npm/postinstall.ts index b6a934f74b3eb..6b61bbded5c84 100644 --- a/build/npm/postinstall.ts +++ b/build/npm/postinstall.ts @@ -8,9 +8,9 @@ import path from 'path'; import * as os from 'os'; import * as child_process from 'child_process'; import { dirs } from './dirs.ts'; +import { root, stateFile, computeState, isUpToDate } from './installStateHash.ts'; const npm = process.platform === 'win32' ? 'npm.cmd' : 'npm'; -const root = path.dirname(path.dirname(import.meta.dirname)); const rootNpmrcConfigKeys = getNpmrcConfigKeys(path.join(root, '.npmrc')); function log(dir: string, message: string) { @@ -35,24 +35,45 @@ function run(command: string, args: string[], opts: child_process.SpawnSyncOptio } } -function npmInstall(dir: string, opts?: child_process.SpawnSyncOptions) { - opts = { +function spawnAsync(command: string, args: string[], opts: child_process.SpawnOptions): Promise { + return new Promise((resolve, reject) => { + const child = child_process.spawn(command, args, { ...opts, stdio: ['ignore', 'pipe', 'pipe'] }); + let output = ''; + child.stdout?.on('data', (data: Buffer) => { output += data.toString(); }); + child.stderr?.on('data', (data: Buffer) => { output += data.toString(); }); + child.on('error', reject); + child.on('close', (code) => { + if (code !== 0) { + reject(new Error(`Process exited with code: ${code}\n${output}`)); + } else { + resolve(output); + } + }); + }); +} + +async function npmInstallAsync(dir: string, opts?: child_process.SpawnOptions): Promise { + const finalOpts: child_process.SpawnOptions = { env: { ...process.env }, ...(opts ?? {}), - cwd: dir, - stdio: 'inherit', - shell: true + cwd: path.join(root, dir), + shell: true, }; const command = process.env['npm_command'] || 'install'; if (process.env['VSCODE_REMOTE_DEPENDENCIES_CONTAINER_NAME'] && /^(.build\/distro\/npm\/)?remote$/.test(dir)) { + const syncOpts: child_process.SpawnSyncOptions = { + env: finalOpts.env, + cwd: root, + stdio: 'inherit', + shell: true, + }; const userinfo = os.userInfo(); log(dir, `Installing dependencies inside container ${process.env['VSCODE_REMOTE_DEPENDENCIES_CONTAINER_NAME']}...`); - opts.cwd = root; if (process.env['npm_config_arch'] === 'arm64') { - run('sudo', ['docker', 'run', '--rm', '--privileged', 'multiarch/qemu-user-static', '--reset', '-p', 'yes'], opts); + run('sudo', ['docker', 'run', '--rm', '--privileged', 'multiarch/qemu-user-static', '--reset', '-p', 'yes'], syncOpts); } run('sudo', [ 'docker', 'run', @@ -63,11 +84,16 @@ function npmInstall(dir: string, opts?: child_process.SpawnSyncOptions) { '-w', path.resolve('/root/vscode', dir), process.env['VSCODE_REMOTE_DEPENDENCIES_CONTAINER_NAME'], 'sh', '-c', `\"chown -R root:root ${path.resolve('/root/vscode', dir)} && export PATH="/root/vscode/.build/nodejs-musl/usr/local/bin:$PATH" && npm i -g node-gyp-build && npm ci\"` - ], opts); - run('sudo', ['chown', '-R', `${userinfo.uid}:${userinfo.gid}`, `${path.resolve(root, dir)}`], opts); + ], syncOpts); + run('sudo', ['chown', '-R', `${userinfo.uid}:${userinfo.gid}`, `${path.resolve(root, dir)}`], syncOpts); } else { log(dir, 'Installing dependencies...'); - run(npm, command.split(' '), opts); + const output = await spawnAsync(npm, command.split(' '), finalOpts); + if (output.trim()) { + for (const line of output.trim().split('\n')) { + log(dir, line); + } + } } removeParcelWatcherPrebuild(dir); } @@ -156,65 +182,114 @@ function clearInheritedNpmrcConfig(dir: string, env: NodeJS.ProcessEnv): void { } } -for (const dir of dirs) { +async function runWithConcurrency(tasks: (() => Promise)[], concurrency: number): Promise { + const errors: Error[] = []; + let index = 0; - if (dir === '') { - removeParcelWatcherPrebuild(dir); - continue; // already executed in root + async function worker() { + while (index < tasks.length) { + const i = index++; + try { + await tasks[i](); + } catch (err) { + errors.push(err as Error); + } + } } - let opts: child_process.SpawnSyncOptions | undefined; + await Promise.all(Array.from({ length: Math.min(concurrency, tasks.length) }, () => worker())); - if (dir === 'build') { - opts = { - env: { - ...process.env - }, - }; - if (process.env['CC']) { opts.env!['CC'] = 'gcc'; } - if (process.env['CXX']) { opts.env!['CXX'] = 'g++'; } - if (process.env['CXXFLAGS']) { opts.env!['CXXFLAGS'] = ''; } - if (process.env['LDFLAGS']) { opts.env!['LDFLAGS'] = ''; } - - setNpmrcConfig('build', opts.env!); - npmInstall('build', opts); - continue; - } - - if (/^(.build\/distro\/npm\/)?remote$/.test(dir)) { - // node modules used by vscode server - opts = { - env: { - ...process.env - }, - }; - if (process.env['VSCODE_REMOTE_CC']) { - opts.env!['CC'] = process.env['VSCODE_REMOTE_CC']; - } else { - delete opts.env!['CC']; + if (errors.length > 0) { + for (const err of errors) { + console.error(err.message); } - if (process.env['VSCODE_REMOTE_CXX']) { - opts.env!['CXX'] = process.env['VSCODE_REMOTE_CXX']; - } else { - delete opts.env!['CXX']; + process.exit(1); + } +} + +async function main() { + if (!process.env['VSCODE_FORCE_INSTALL'] && isUpToDate()) { + log('.', 'All dependencies up to date, skipping postinstall.'); + child_process.execSync('git config pull.rebase merges'); + child_process.execSync('git config blame.ignoreRevsFile .git-blame-ignore-revs'); + return; + } + + const _state = computeState(); + + const nativeTasks: (() => Promise)[] = []; + const parallelTasks: (() => Promise)[] = []; + + for (const dir of dirs) { + if (dir === '') { + removeParcelWatcherPrebuild(dir); + continue; // already executed in root + } + + if (dir === 'build') { + nativeTasks.push(() => { + const env: NodeJS.ProcessEnv = { ...process.env }; + if (process.env['CC']) { env['CC'] = 'gcc'; } + if (process.env['CXX']) { env['CXX'] = 'g++'; } + if (process.env['CXXFLAGS']) { env['CXXFLAGS'] = ''; } + if (process.env['LDFLAGS']) { env['LDFLAGS'] = ''; } + setNpmrcConfig('build', env); + return npmInstallAsync('build', { env }); + }); + continue; + } + + if (/^(.build\/distro\/npm\/)?remote$/.test(dir)) { + const remoteDir = dir; + nativeTasks.push(() => { + const env: NodeJS.ProcessEnv = { ...process.env }; + if (process.env['VSCODE_REMOTE_CC']) { + env['CC'] = process.env['VSCODE_REMOTE_CC']; + } else { + delete env['CC']; + } + if (process.env['VSCODE_REMOTE_CXX']) { + env['CXX'] = process.env['VSCODE_REMOTE_CXX']; + } else { + delete env['CXX']; + } + if (process.env['CXXFLAGS']) { delete env['CXXFLAGS']; } + if (process.env['CFLAGS']) { delete env['CFLAGS']; } + if (process.env['LDFLAGS']) { delete env['LDFLAGS']; } + if (process.env['VSCODE_REMOTE_CXXFLAGS']) { env['CXXFLAGS'] = process.env['VSCODE_REMOTE_CXXFLAGS']; } + if (process.env['VSCODE_REMOTE_LDFLAGS']) { env['LDFLAGS'] = process.env['VSCODE_REMOTE_LDFLAGS']; } + if (process.env['VSCODE_REMOTE_NODE_GYP']) { env['npm_config_node_gyp'] = process.env['VSCODE_REMOTE_NODE_GYP']; } + setNpmrcConfig('remote', env); + return npmInstallAsync(remoteDir, { env }); + }); + continue; } - if (process.env['CXXFLAGS']) { delete opts.env!['CXXFLAGS']; } - if (process.env['CFLAGS']) { delete opts.env!['CFLAGS']; } - if (process.env['LDFLAGS']) { delete opts.env!['LDFLAGS']; } - if (process.env['VSCODE_REMOTE_CXXFLAGS']) { opts.env!['CXXFLAGS'] = process.env['VSCODE_REMOTE_CXXFLAGS']; } - if (process.env['VSCODE_REMOTE_LDFLAGS']) { opts.env!['LDFLAGS'] = process.env['VSCODE_REMOTE_LDFLAGS']; } - if (process.env['VSCODE_REMOTE_NODE_GYP']) { opts.env!['npm_config_node_gyp'] = process.env['VSCODE_REMOTE_NODE_GYP']; } - - setNpmrcConfig('remote', opts.env!); - npmInstall(dir, opts); - continue; - } - - // For directories that don't define their own .npmrc, clear inherited config - const env = { ...process.env }; - clearInheritedNpmrcConfig(dir, env); - npmInstall(dir, { env }); + + const taskDir = dir; + parallelTasks.push(() => { + const env = { ...process.env }; + clearInheritedNpmrcConfig(taskDir, env); + return npmInstallAsync(taskDir, { env }); + }); + } + + // Native dirs (build, remote) run sequentially to avoid node-gyp conflicts + for (const task of nativeTasks) { + await task(); + } + + // JS-only dirs run in parallel + const concurrency = Math.min(os.cpus().length, 8); + log('.', `Running ${parallelTasks.length} npm installs with concurrency ${concurrency}...`); + await runWithConcurrency(parallelTasks, concurrency); + + child_process.execSync('git config pull.rebase merges'); + child_process.execSync('git config blame.ignoreRevsFile .git-blame-ignore-revs'); + + fs.writeFileSync(stateFile, JSON.stringify(_state)); } -child_process.execSync('git config pull.rebase merges'); -child_process.execSync('git config blame.ignoreRevsFile .git-blame-ignore-revs'); +main().catch(err => { + console.error(err); + process.exit(1); +}); diff --git a/build/npm/preinstall.ts b/build/npm/preinstall.ts index 3476fcabb5009..dd53ff4467123 100644 --- a/build/npm/preinstall.ts +++ b/build/npm/preinstall.ts @@ -6,6 +6,7 @@ import path from 'path'; import * as fs from 'fs'; import * as child_process from 'child_process'; import * as os from 'os'; +import { isUpToDate, forceInstallMessage } from './installStateHash.ts'; if (!process.env['VSCODE_SKIP_NODE_VERSION_CHECK']) { // Get the running Node.js version @@ -41,6 +42,13 @@ if (process.env.npm_execpath?.includes('yarn')) { throw new Error(); } +// Fast path: if nothing changed since last successful install, skip everything. +// This makes `npm i` near-instant when dependencies haven't changed. +if (!process.env['VSCODE_FORCE_INSTALL'] && isUpToDate()) { + console.log(`\x1b[32mAll dependencies up to date.\x1b[0m ${forceInstallMessage}`); + process.exit(0); +} + if (process.platform === 'win32') { if (!hasSupportedVisualStudioVersion()) { console.error('\x1b[1;31m*** Invalid C/C++ Compiler Toolchain. Please check https://github.com/microsoft/vscode/wiki/How-to-Contribute#prerequisites.\x1b[0;0m'); From b01bfca9a01af8b470cf2a162f5729adc1c0d673 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 27 Feb 2026 17:33:51 +0000 Subject: [PATCH 17/40] Bump koa from 3.1.1 to 3.1.2 (#298127) Bumps [koa](https://github.com/koajs/koa) from 3.1.1 to 3.1.2. - [Release notes](https://github.com/koajs/koa/releases) - [Changelog](https://github.com/koajs/koa/blob/master/History.md) - [Commits](https://github.com/koajs/koa/compare/v3.1.1...v3.1.2) --- updated-dependencies: - dependency-name: koa dependency-version: 3.1.2 dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 58 ++++++++++------------------------------------- 1 file changed, 12 insertions(+), 46 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3ec5dd73ec4ee..ef5b2106cd61e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5901,39 +5901,19 @@ } }, "node_modules/content-disposition": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.1.tgz", + "integrity": "sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==", "dev": true, "license": "MIT", - "dependencies": { - "safe-buffer": "5.2.1" - }, "engines": { - "node": ">= 0.6" + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/content-disposition/node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, "node_modules/content-type": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", @@ -7657,20 +7637,6 @@ "node": ">= 0.6" } }, - "node_modules/express/node_modules/content-disposition": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.1.tgz", - "integrity": "sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, "node_modules/express/node_modules/fresh": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", @@ -11928,14 +11894,14 @@ } }, "node_modules/koa": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/koa/-/koa-3.1.1.tgz", - "integrity": "sha512-KDDuvpfqSK0ZKEO2gCPedNjl5wYpfj+HNiuVRlbhd1A88S3M0ySkdf2V/EJ4NWt5dwh5PXCdcenrKK2IQJAxsg==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/koa/-/koa-3.1.2.tgz", + "integrity": "sha512-2LOQnFKu3m0VxpE+5sb5+BRTSKrXmNxGgxVRiKwD9s5KQB1zID/FRXhtzeV7RT1L2GVpdEEAfVuclFOMGl1ikA==", "dev": true, "license": "MIT", "dependencies": { "accepts": "^1.3.8", - "content-disposition": "~0.5.4", + "content-disposition": "~1.0.1", "content-type": "^1.0.5", "cookies": "~0.9.1", "delegates": "^1.0.0", From e2344f9b6bebc69887b1d2397f217b4d2353921b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 27 Feb 2026 17:36:27 +0000 Subject: [PATCH 18/40] Bump minimatch from 9.0.6 to 9.0.9 in /test/sanity (#298126) Bumps [minimatch](https://github.com/isaacs/minimatch) from 9.0.6 to 9.0.9. - [Changelog](https://github.com/isaacs/minimatch/blob/main/changelog.md) - [Commits](https://github.com/isaacs/minimatch/compare/v9.0.6...v9.0.9) --- updated-dependencies: - dependency-name: minimatch dependency-version: 9.0.9 dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- test/sanity/package-lock.json | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/test/sanity/package-lock.json b/test/sanity/package-lock.json index 6113958376736..79d178a5f5cbf 100644 --- a/test/sanity/package-lock.json +++ b/test/sanity/package-lock.json @@ -107,24 +107,18 @@ "license": "Python-2.0" }, "node_modules/balanced-match": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", - "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", - "license": "MIT", - "engines": { - "node": "18 || 20 || >=22" - } + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT" }, "node_modules/brace-expansion": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.3.tgz", - "integrity": "sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", "license": "MIT", "dependencies": { - "balanced-match": "^4.0.2" - }, - "engines": { - "node": "18 || 20 || >=22" + "balanced-match": "^1.0.0" } }, "node_modules/browser-stdout": { @@ -654,12 +648,12 @@ } }, "node_modules/minimatch": { - "version": "9.0.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.6.tgz", - "integrity": "sha512-kQAVowdR33euIqeA0+VZTDqU+qo1IeVY+hrKYtZMio3Pg0P0vuh/kwRylLUddJhB6pf3q/botcOvRtx4IN1wqQ==", + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", "license": "ISC", "dependencies": { - "brace-expansion": "^5.0.2" + "brace-expansion": "^2.0.2" }, "engines": { "node": ">=16 || 14 >=14.17" From df40d0e36393ece2879739573126d20618a13280 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 27 Feb 2026 17:59:58 +0000 Subject: [PATCH 19/40] Bump minimatch from 3.1.2 to 3.1.3 in /extensions/markdown-language-features (#297527) Bump minimatch in /extensions/markdown-language-features Bumps [minimatch](https://github.com/isaacs/minimatch) from 3.1.2 to 3.1.3. - [Changelog](https://github.com/isaacs/minimatch/blob/main/changelog.md) - [Commits](https://github.com/isaacs/minimatch/compare/v3.1.2...v3.1.3) --- updated-dependencies: - dependency-name: minimatch dependency-version: 3.1.3 dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- extensions/markdown-language-features/package-lock.json | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/extensions/markdown-language-features/package-lock.json b/extensions/markdown-language-features/package-lock.json index b7180c307306d..fbde1da49b92d 100644 --- a/extensions/markdown-language-features/package-lock.json +++ b/extensions/markdown-language-features/package-lock.json @@ -513,9 +513,10 @@ "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==" }, "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" }, From 1bd9cbc08adbb387ee67a77644e5c174df6a1b2e Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Fri, 27 Feb 2026 19:00:50 +0100 Subject: [PATCH 20/40] sessions: change workbench state to worksapce and do not send workspace data to ext host (#298301) --- .../contrib/snippet/test/browser/snippetVariables.test.ts | 1 + src/vs/editor/standalone/browser/standaloneServices.ts | 4 ++++ src/vs/platform/workspace/common/workspace.ts | 5 +++++ .../services/workspace/browser/workspaceContextService.ts | 6 +++++- src/vs/workbench/api/browser/mainThreadWorkspace.ts | 4 ++-- .../services/configuration/browser/configurationService.ts | 4 ++++ src/vs/workbench/test/common/workbenchTestServices.ts | 4 ++++ 7 files changed, 25 insertions(+), 3 deletions(-) diff --git a/src/vs/editor/contrib/snippet/test/browser/snippetVariables.test.ts b/src/vs/editor/contrib/snippet/test/browser/snippetVariables.test.ts index 93ec32ae65e28..89c480c64c4e1 100644 --- a/src/vs/editor/contrib/snippet/test/browser/snippetVariables.test.ts +++ b/src/vs/editor/contrib/snippet/test/browser/snippetVariables.test.ts @@ -371,6 +371,7 @@ suite('Snippet Variables Resolver', function () { getCompleteWorkspace = this._throw; getWorkspace(): IWorkspace { return workspace; } getWorkbenchState = this._throw; + hasWorkspaceData = this._throw; getWorkspaceFolder = this._throw; isCurrentWorkspace = this._throw; isInsideWorkspace = this._throw; diff --git a/src/vs/editor/standalone/browser/standaloneServices.ts b/src/vs/editor/standalone/browser/standaloneServices.ts index fb5b0122e9181..e12a15076e4f9 100644 --- a/src/vs/editor/standalone/browser/standaloneServices.ts +++ b/src/vs/editor/standalone/browser/standaloneServices.ts @@ -852,6 +852,10 @@ class StandaloneWorkspaceContextService implements IWorkspaceContextService { return WorkbenchState.EMPTY; } + public hasWorkspaceData(): boolean { + return this.getWorkbenchState() !== WorkbenchState.EMPTY; + } + public getWorkspaceFolder(resource: URI): IWorkspaceFolder | null { return resource && resource.scheme === StandaloneWorkspaceContextService.SCHEME ? this.workspace.folders[0] : null; } diff --git a/src/vs/platform/workspace/common/workspace.ts b/src/vs/platform/workspace/common/workspace.ts index a0459d077e6ea..691e1a3bf2e89 100644 --- a/src/vs/platform/workspace/common/workspace.ts +++ b/src/vs/platform/workspace/common/workspace.ts @@ -74,6 +74,11 @@ export interface IWorkspaceContextService { * Returns if the provided resource is inside the workspace or not. */ isInsideWorkspace(resource: URI): boolean; + + /** + * Return `true` if the current workspace has data (e.g. folders or a workspace configuration) that can be sent to the extension host, otherwise `false`. + */ + hasWorkspaceData(): boolean; } export interface IResolvedWorkspace extends IWorkspaceIdentifier, IBaseWorkspace { diff --git a/src/vs/sessions/services/workspace/browser/workspaceContextService.ts b/src/vs/sessions/services/workspace/browser/workspaceContextService.ts index b9ec9f571f9c5..58b4dfb588923 100644 --- a/src/vs/sessions/services/workspace/browser/workspaceContextService.ts +++ b/src/vs/sessions/services/workspace/browser/workspaceContextService.ts @@ -49,7 +49,11 @@ export class SessionsWorkspaceContextService extends Disposable implements IWork } getWorkbenchState(): WorkbenchState { - return WorkbenchState.EMPTY; + return WorkbenchState.WORKSPACE; + } + + hasWorkspaceData(): boolean { + return false; } getWorkspaceFolder(resource: URI): IWorkspaceFolder | null { diff --git a/src/vs/workbench/api/browser/mainThreadWorkspace.ts b/src/vs/workbench/api/browser/mainThreadWorkspace.ts index 02a2e749a1cf0..b756baf6d6aef 100644 --- a/src/vs/workbench/api/browser/mainThreadWorkspace.ts +++ b/src/vs/workbench/api/browser/mainThreadWorkspace.ts @@ -16,7 +16,7 @@ import { ILabelService } from '../../../platform/label/common/label.js'; import { INotificationService } from '../../../platform/notification/common/notification.js'; import { AuthInfo, Credentials, IRequestService } from '../../../platform/request/common/request.js'; import { WorkspaceTrustRequestOptions, IWorkspaceTrustManagementService, IWorkspaceTrustRequestService, ResourceTrustRequestOptions } from '../../../platform/workspace/common/workspaceTrust.js'; -import { IWorkspace, IWorkspaceContextService, WorkbenchState, isUntitledWorkspace, WorkspaceFolder } from '../../../platform/workspace/common/workspace.js'; +import { IWorkspace, IWorkspaceContextService, isUntitledWorkspace, WorkspaceFolder } from '../../../platform/workspace/common/workspace.js'; import { extHostNamedCustomer, IExtHostContext } from '../../services/extensions/common/extHostCustomers.js'; import { checkGlobFileExists } from '../../services/extensions/common/workspaceContains.js'; import { IFileQueryBuilderOptions, ITextQueryBuilderOptions, QueryBuilder } from '../../services/search/common/queryBuilder.js'; @@ -130,7 +130,7 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape { } private getWorkspaceData(workspace: IWorkspace): IWorkspaceData | null { - if (this._contextService.getWorkbenchState() === WorkbenchState.EMPTY) { + if (!this._contextService.hasWorkspaceData()) { return null; } return { diff --git a/src/vs/workbench/services/configuration/browser/configurationService.ts b/src/vs/workbench/services/configuration/browser/configurationService.ts index b6b3e48dcd3e1..d9491186439c9 100644 --- a/src/vs/workbench/services/configuration/browser/configurationService.ts +++ b/src/vs/workbench/services/configuration/browser/configurationService.ts @@ -194,6 +194,10 @@ export class WorkspaceService extends Disposable implements IWorkbenchConfigurat return WorkbenchState.EMPTY; } + public hasWorkspaceData(): boolean { + return this.getWorkbenchState() !== WorkbenchState.EMPTY; + } + public getWorkspaceFolder(resource: URI): IWorkspaceFolder | null { return this.workspace.getFolder(resource); } diff --git a/src/vs/workbench/test/common/workbenchTestServices.ts b/src/vs/workbench/test/common/workbenchTestServices.ts index e625aa79e5bbd..3a60b99ae9161 100644 --- a/src/vs/workbench/test/common/workbenchTestServices.ts +++ b/src/vs/workbench/test/common/workbenchTestServices.ts @@ -120,6 +120,10 @@ export class TestContextService implements IWorkspaceContextService { return WorkbenchState.EMPTY; } + hasWorkspaceData(): boolean { + return this.getWorkbenchState() !== WorkbenchState.EMPTY; + } + getCompleteWorkspace(): Promise { return Promise.resolve(this.getWorkspace()); } From d013e8cdaaa3816f69eb59fc81e967c421bd8d6c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 27 Feb 2026 18:01:18 +0000 Subject: [PATCH 21/40] Bump minimatch from 5.1.6 to 5.1.7 in /extensions/npm (#297523) Bumps [minimatch](https://github.com/isaacs/minimatch) from 5.1.6 to 5.1.7. - [Changelog](https://github.com/isaacs/minimatch/blob/main/changelog.md) - [Commits](https://github.com/isaacs/minimatch/compare/v5.1.6...v5.1.7) --- updated-dependencies: - dependency-name: minimatch dependency-version: 5.1.7 dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- extensions/npm/package-lock.json | 9 +++++---- extensions/npm/package.json | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/extensions/npm/package-lock.json b/extensions/npm/package-lock.json index 694e98b5e1213..d3bf11daf09c5 100644 --- a/extensions/npm/package-lock.json +++ b/extensions/npm/package-lock.json @@ -12,7 +12,7 @@ "find-up": "^5.0.0", "find-yarn-workspace-root": "^2.0.0", "jsonc-parser": "^3.2.0", - "minimatch": "^5.1.6", + "minimatch": "^5.1.8", "request-light": "^0.7.0", "vscode-uri": "^3.0.8", "which": "^4.0.0", @@ -209,9 +209,10 @@ } }, "node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "version": "5.1.8", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.8.tgz", + "integrity": "sha512-7RN35vit8DeBclkofOVmBY0eDAZZQd1HzmukRdSyz95CRh8FT54eqnbj0krQr3mrHR6sfRyYkyhwBWjoV5uqlQ==", + "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" }, diff --git a/extensions/npm/package.json b/extensions/npm/package.json index bba6a23b8ac99..7db2ec0e2d547 100644 --- a/extensions/npm/package.json +++ b/extensions/npm/package.json @@ -30,7 +30,7 @@ "find-up": "^5.0.0", "find-yarn-workspace-root": "^2.0.0", "jsonc-parser": "^3.2.0", - "minimatch": "^5.1.6", + "minimatch": "^5.1.8", "request-light": "^0.7.0", "which": "^4.0.0", "which-pm": "^2.1.1", From 5428850858b0ad079c832c04570f14d745d35155 Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Fri, 27 Feb 2026 19:04:49 +0100 Subject: [PATCH 22/40] fixes screenshot status (#298303) --- .github/workflows/screenshot-test.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/screenshot-test.yml b/.github/workflows/screenshot-test.yml index 411e8dd585ef3..decfcf2a6f84d 100644 --- a/.github/workflows/screenshot-test.yml +++ b/.github/workflows/screenshot-test.yml @@ -94,9 +94,9 @@ jobs: REPORT="test/componentFixtures/.screenshots/report/report.json" if [ -f "$REPORT" ]; then CHANGED=$(node -e "const r = require('./$REPORT'); console.log(r.summary.added + r.summary.removed + r.summary.changed)") - TITLE="📸 ⚠️ ${CHANGED} screenshots changed" + TITLE="⚠ ${CHANGED} screenshots changed" else - TITLE="📸 ✅ Screenshots match" + TITLE="✅ Screenshots match" fi SHA="${{ github.event.pull_request.head.sha || github.sha }}" From 0005b2dcc9169487c0480f31aa2227487114e68d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 27 Feb 2026 18:24:26 +0000 Subject: [PATCH 23/40] Bump minimatch from 10.2.2 to 10.2.4 in /extensions/json-language-features (#298307) Bump minimatch in /extensions/json-language-features Bumps [minimatch](https://github.com/isaacs/minimatch) from 10.2.2 to 10.2.4. - [Changelog](https://github.com/isaacs/minimatch/blob/main/changelog.md) - [Commits](https://github.com/isaacs/minimatch/compare/v10.2.2...v10.2.4) --- updated-dependencies: - dependency-name: minimatch dependency-version: 10.2.4 dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- extensions/json-language-features/package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/extensions/json-language-features/package-lock.json b/extensions/json-language-features/package-lock.json index e5e1b9c133204..9ceade066818b 100644 --- a/extensions/json-language-features/package-lock.json +++ b/extensions/json-language-features/package-lock.json @@ -190,9 +190,9 @@ } }, "node_modules/minimatch": { - "version": "10.2.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.2.tgz", - "integrity": "sha512-+G4CpNBxa5MprY+04MbgOw1v7So6n5JY166pFi9KfYwT78fxScCeSNQSNzp6dpPSW2rONOps6Ocam1wFhCgoVw==", + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", + "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", "license": "BlueOak-1.0.0", "dependencies": { "brace-expansion": "^5.0.2" From 182ee88b485b1531d7c34ccdf1b6c7dcfe7b4a32 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 27 Feb 2026 18:31:14 +0000 Subject: [PATCH 24/40] Bump minimatch from 10.2.2 to 10.2.4 in /extensions/css-language-features (#298308) Bump minimatch in /extensions/css-language-features Bumps [minimatch](https://github.com/isaacs/minimatch) from 10.2.2 to 10.2.4. - [Changelog](https://github.com/isaacs/minimatch/blob/main/changelog.md) - [Commits](https://github.com/isaacs/minimatch/compare/v10.2.2...v10.2.4) --- updated-dependencies: - dependency-name: minimatch dependency-version: 10.2.4 dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- extensions/css-language-features/package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/extensions/css-language-features/package-lock.json b/extensions/css-language-features/package-lock.json index 231eda54dba77..e5cf7c26d199e 100644 --- a/extensions/css-language-features/package-lock.json +++ b/extensions/css-language-features/package-lock.json @@ -51,9 +51,9 @@ } }, "node_modules/minimatch": { - "version": "10.2.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.2.tgz", - "integrity": "sha512-+G4CpNBxa5MprY+04MbgOw1v7So6n5JY166pFi9KfYwT78fxScCeSNQSNzp6dpPSW2rONOps6Ocam1wFhCgoVw==", + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", + "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", "license": "BlueOak-1.0.0", "dependencies": { "brace-expansion": "^5.0.2" From 0bf24b7b5ee3b85d2ca4d002cd99994b40e020e5 Mon Sep 17 00:00:00 2001 From: Osvaldo Ortega Date: Fri, 27 Feb 2026 10:35:02 -0800 Subject: [PATCH 25/40] Enhance git sync command to include worktree URI for better context --- src/vs/sessions/contrib/chat/browser/syncIndicator.ts | 4 ++-- .../sessions/contrib/gitSync/browser/gitSync.contribution.ts | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/vs/sessions/contrib/chat/browser/syncIndicator.ts b/src/vs/sessions/contrib/chat/browser/syncIndicator.ts index 3480f68166b2a..e07089daee537 100644 --- a/src/vs/sessions/contrib/chat/browser/syncIndicator.ts +++ b/src/vs/sessions/contrib/chat/browser/syncIndicator.ts @@ -81,13 +81,13 @@ export class SyncIndicator extends Disposable { this._renderDisposables.add(dom.addDisposableListener(button, dom.EventType.CLICK, (e) => { dom.EventHelper.stop(e, true); - this.commandService.executeCommand(GIT_SYNC_COMMAND); + this.commandService.executeCommand(GIT_SYNC_COMMAND, this._repository?.rootUri); })); this._renderDisposables.add(dom.addDisposableListener(button, dom.EventType.KEY_DOWN, (e) => { if (e.key === 'Enter' || e.key === ' ') { dom.EventHelper.stop(e, true); - this.commandService.executeCommand(GIT_SYNC_COMMAND); + this.commandService.executeCommand(GIT_SYNC_COMMAND, this._repository?.rootUri); } })); diff --git a/src/vs/sessions/contrib/gitSync/browser/gitSync.contribution.ts b/src/vs/sessions/contrib/gitSync/browser/gitSync.contribution.ts index 57f7e8a23ccbe..65869c6cb8b5b 100644 --- a/src/vs/sessions/contrib/gitSync/browser/gitSync.contribution.ts +++ b/src/vs/sessions/contrib/gitSync/browser/gitSync.contribution.ts @@ -112,7 +112,9 @@ function registerSyncAction(behind: number, ahead: number): IDisposable { override async run(accessor: ServicesAccessor): Promise { const commandService = accessor.get(ICommandService); - await commandService.executeCommand('git.sync'); + const sessionManagementService = accessor.get(ISessionsManagementService); + const worktreeUri = sessionManagementService.getActiveSession()?.worktree; + await commandService.executeCommand('git.sync', worktreeUri); } } return registerAction2(SynchronizeChangesAction); From 14a4e40646a4c040b4d3930e8ece7aa9cb728a2c Mon Sep 17 00:00:00 2001 From: Osvaldo Ortega Date: Fri, 27 Feb 2026 10:41:18 -0800 Subject: [PATCH 26/40] Add debug logging for repository and worktree URI in git sync commands --- extensions/git/src/commands.ts | 1 + src/vs/sessions/contrib/chat/browser/syncIndicator.ts | 1 + .../sessions/contrib/gitSync/browser/gitSync.contribution.ts | 5 ++++- 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/extensions/git/src/commands.ts b/extensions/git/src/commands.ts index 5c93d8f7a1ffb..51eaa2c8220f9 100644 --- a/extensions/git/src/commands.ts +++ b/extensions/git/src/commands.ts @@ -5424,6 +5424,7 @@ export class CommandCenter { } else { // try to guess the repository based on the first argument const repository = this.model.getRepository(args[0]); + console.log(`[git.createCommand] id=${id}, args[0]=${args[0]}, resolved repository=${repository?.root}, openRepos=${this.model.repositories.map(r => r.root).join(', ')}`); let repositoryPromise: Promise; if (repository) { diff --git a/src/vs/sessions/contrib/chat/browser/syncIndicator.ts b/src/vs/sessions/contrib/chat/browser/syncIndicator.ts index e07089daee537..dfcaf28f2e9fb 100644 --- a/src/vs/sessions/contrib/chat/browser/syncIndicator.ts +++ b/src/vs/sessions/contrib/chat/browser/syncIndicator.ts @@ -81,6 +81,7 @@ export class SyncIndicator extends Disposable { this._renderDisposables.add(dom.addDisposableListener(button, dom.EventType.CLICK, (e) => { dom.EventHelper.stop(e, true); + console.log('[SyncIndicator] click, repository rootUri:', this._repository?.rootUri?.toString()); this.commandService.executeCommand(GIT_SYNC_COMMAND, this._repository?.rootUri); })); diff --git a/src/vs/sessions/contrib/gitSync/browser/gitSync.contribution.ts b/src/vs/sessions/contrib/gitSync/browser/gitSync.contribution.ts index 65869c6cb8b5b..8fe95976b804d 100644 --- a/src/vs/sessions/contrib/gitSync/browser/gitSync.contribution.ts +++ b/src/vs/sessions/contrib/gitSync/browser/gitSync.contribution.ts @@ -113,7 +113,10 @@ function registerSyncAction(behind: number, ahead: number): IDisposable { override async run(accessor: ServicesAccessor): Promise { const commandService = accessor.get(ICommandService); const sessionManagementService = accessor.get(ISessionsManagementService); - const worktreeUri = sessionManagementService.getActiveSession()?.worktree; + const activeSession = sessionManagementService.getActiveSession(); + const worktreeUri = activeSession?.worktree; + console.log('[GitSync] activeSession:', activeSession); + console.log('[GitSync] worktreeUri:', worktreeUri?.toString()); await commandService.executeCommand('git.sync', worktreeUri); } } From 9aea26f17cdcb8325c7cd250ff53422a25e79544 Mon Sep 17 00:00:00 2001 From: Osvaldo Ortega Date: Fri, 27 Feb 2026 10:54:06 -0800 Subject: [PATCH 27/40] Remove debug logging for repository and worktree URI in sync commands --- extensions/git/src/commands.ts | 1 - src/vs/sessions/contrib/chat/browser/syncIndicator.ts | 1 - .../sessions/contrib/gitSync/browser/gitSync.contribution.ts | 5 +---- 3 files changed, 1 insertion(+), 6 deletions(-) diff --git a/extensions/git/src/commands.ts b/extensions/git/src/commands.ts index 51eaa2c8220f9..5c93d8f7a1ffb 100644 --- a/extensions/git/src/commands.ts +++ b/extensions/git/src/commands.ts @@ -5424,7 +5424,6 @@ export class CommandCenter { } else { // try to guess the repository based on the first argument const repository = this.model.getRepository(args[0]); - console.log(`[git.createCommand] id=${id}, args[0]=${args[0]}, resolved repository=${repository?.root}, openRepos=${this.model.repositories.map(r => r.root).join(', ')}`); let repositoryPromise: Promise; if (repository) { diff --git a/src/vs/sessions/contrib/chat/browser/syncIndicator.ts b/src/vs/sessions/contrib/chat/browser/syncIndicator.ts index dfcaf28f2e9fb..e07089daee537 100644 --- a/src/vs/sessions/contrib/chat/browser/syncIndicator.ts +++ b/src/vs/sessions/contrib/chat/browser/syncIndicator.ts @@ -81,7 +81,6 @@ export class SyncIndicator extends Disposable { this._renderDisposables.add(dom.addDisposableListener(button, dom.EventType.CLICK, (e) => { dom.EventHelper.stop(e, true); - console.log('[SyncIndicator] click, repository rootUri:', this._repository?.rootUri?.toString()); this.commandService.executeCommand(GIT_SYNC_COMMAND, this._repository?.rootUri); })); diff --git a/src/vs/sessions/contrib/gitSync/browser/gitSync.contribution.ts b/src/vs/sessions/contrib/gitSync/browser/gitSync.contribution.ts index 8fe95976b804d..65869c6cb8b5b 100644 --- a/src/vs/sessions/contrib/gitSync/browser/gitSync.contribution.ts +++ b/src/vs/sessions/contrib/gitSync/browser/gitSync.contribution.ts @@ -113,10 +113,7 @@ function registerSyncAction(behind: number, ahead: number): IDisposable { override async run(accessor: ServicesAccessor): Promise { const commandService = accessor.get(ICommandService); const sessionManagementService = accessor.get(ISessionsManagementService); - const activeSession = sessionManagementService.getActiveSession(); - const worktreeUri = activeSession?.worktree; - console.log('[GitSync] activeSession:', activeSession); - console.log('[GitSync] worktreeUri:', worktreeUri?.toString()); + const worktreeUri = sessionManagementService.getActiveSession()?.worktree; await commandService.executeCommand('git.sync', worktreeUri); } } From 1b5e0460cca578fc03a75afd344cd3365368850b Mon Sep 17 00:00:00 2001 From: David Dossett <25163139+daviddossett@users.noreply.github.com> Date: Fri, 27 Feb 2026 11:20:29 -0800 Subject: [PATCH 28/40] Improve contrast for chat welcome disclaimer text (#298327) Use description foreground for chat welcome disclaimer --- .../contrib/chat/browser/widget/media/chatViewWelcome.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/chat/browser/widget/media/chatViewWelcome.css b/src/vs/workbench/contrib/chat/browser/widget/media/chatViewWelcome.css index 9a5cff033fa59..8a6e91f1861b9 100644 --- a/src/vs/workbench/contrib/chat/browser/widget/media/chatViewWelcome.css +++ b/src/vs/workbench/contrib/chat/browser/widget/media/chatViewWelcome.css @@ -157,7 +157,7 @@ div.chat-welcome-view { } & > .chat-welcome-view-disclaimer { - color: var(--vscode-input-placeholderForeground); + color: var(--vscode-descriptionForeground); text-align: center; margin: 0; max-width: 256px; From e6bed073db15c6b928e610a11e7ef631c0222a4c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 27 Feb 2026 19:47:50 +0000 Subject: [PATCH 29/40] Bump fast-xml-parser from 5.3.6 to 5.4.1 in /build (#298316) Bumps [fast-xml-parser](https://github.com/NaturalIntelligence/fast-xml-parser) from 5.3.6 to 5.4.1. - [Release notes](https://github.com/NaturalIntelligence/fast-xml-parser/releases) - [Changelog](https://github.com/NaturalIntelligence/fast-xml-parser/blob/master/CHANGELOG.md) - [Commits](https://github.com/NaturalIntelligence/fast-xml-parser/compare/v5.3.6...v5.4.1) --- updated-dependencies: - dependency-name: fast-xml-parser dependency-version: 5.4.1 dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Raymond Zhao <7199958+rzhao271@users.noreply.github.com> --- build/package-lock.json | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/build/package-lock.json b/build/package-lock.json index b78c4c8389ac5..b7890ceb3d420 100644 --- a/build/package-lock.json +++ b/build/package-lock.json @@ -3493,10 +3493,23 @@ ], "license": "BSD-3-Clause" }, + "node_modules/fast-xml-builder": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fast-xml-builder/-/fast-xml-builder-1.0.0.tgz", + "integrity": "sha512-fpZuDogrAgnyt9oDDz+5DBz0zgPdPZz6D4IR7iESxRXElrlGTRkHJ9eEt+SACRJwT0FNFrt71DFQIUFBJfX/uQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT" + }, "node_modules/fast-xml-parser": { - "version": "5.3.6", - "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.3.6.tgz", - "integrity": "sha512-QNI3sAvSvaOiaMl8FYU4trnEzCwiRr8XMWgAHzlrWpTSj+QaCSvOf1h82OEP1s4hiAXhnbXSyFWCf4ldZzZRVA==", + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.4.1.tgz", + "integrity": "sha512-BQ30U1mKkvXQXXkAGcuyUA/GA26oEB7NzOtsxCDtyu62sjGw5QraKFhx2Em3WQNjPw9PG6MQ9yuIIgkSDfGu5A==", "dev": true, "funding": [ { @@ -3506,6 +3519,7 @@ ], "license": "MIT", "dependencies": { + "fast-xml-builder": "^1.0.0", "strnum": "^2.1.2" }, "bin": { From 4a32ff310eb1b41af648fd18ffc254edc0cebca0 Mon Sep 17 00:00:00 2001 From: Megan Rogge Date: Fri, 27 Feb 2026 13:55:24 -0600 Subject: [PATCH 30/40] fix issue w tip toolbar (#298333) fixes #297273 --- .../browser/widget/chatContentParts/media/chatTipContent.css | 1 - 1 file changed, 1 deletion(-) diff --git a/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/media/chatTipContent.css b/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/media/chatTipContent.css index dba68be9b33e4..66dbbe1f82865 100644 --- a/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/media/chatTipContent.css +++ b/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/media/chatTipContent.css @@ -17,7 +17,6 @@ background-color: var(--vscode-editorWidget-background); border: 1px solid var(--vscode-chat-requestBorder); border-radius: var(--vscode-cornerRadius-medium); - z-index: 100; transition: opacity 0.1s ease-in-out; } From 0b6ee2bca942bf1bfd0d12596db207402821260a Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Fri, 27 Feb 2026 11:59:24 -0800 Subject: [PATCH 31/40] chat: expose toolResultError as boolean flag (#298320) * chat: expose toolResultError as boolean flag Converts toolResultError to support both string and boolean types, allowing it to be used as a simple error flag when the specific error message is not needed. The conversion to boolean is safe because the only usage is in a truthy check. - Updates IToolResult interface to accept string | boolean for toolResultError - Adds conversion logic in extHostTypeConverters for boolean mapping - Passes the error flag through the main thread language model tools Refs https://github.com/microsoft/vscode/issues/298226 (Commit message generated by Copilot) * fix --- src/vs/workbench/api/browser/mainThreadLanguageModelTools.ts | 3 ++- src/vs/workbench/api/common/extHostTypeConverters.ts | 4 ++++ .../contrib/chat/common/tools/languageModelToolsService.ts | 2 +- .../chat/test/browser/tools/languageModelToolsService.test.ts | 2 +- 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/api/browser/mainThreadLanguageModelTools.ts b/src/vs/workbench/api/browser/mainThreadLanguageModelTools.ts index 5059c608dae22..69a3859726970 100644 --- a/src/vs/workbench/api/browser/mainThreadLanguageModelTools.ts +++ b/src/vs/workbench/api/browser/mainThreadLanguageModelTools.ts @@ -66,7 +66,8 @@ export class MainThreadLanguageModelTools extends Disposable implements MainThre // Only return content and metadata to EH const out: Dto = { content: result.content, - toolMetadata: result.toolMetadata + toolMetadata: result.toolMetadata, + toolResultError: result.toolResultError, }; return toolResultHasBuffers(result) ? new SerializableObjectWithBuffers(out) : out; } diff --git a/src/vs/workbench/api/common/extHostTypeConverters.ts b/src/vs/workbench/api/common/extHostTypeConverters.ts index d565aa7634c67..476ccdf8443db 100644 --- a/src/vs/workbench/api/common/extHostTypeConverters.ts +++ b/src/vs/workbench/api/common/extHostTypeConverters.ts @@ -3873,6 +3873,9 @@ export namespace LanguageModelToolResult { if (result.toolMetadata !== undefined) { toolResult.toolMetadata = result.toolMetadata; } + if (result.toolResultError) { + toolResult.hasError = !!result.toolResultError; + } return toolResult; } @@ -3938,6 +3941,7 @@ export namespace LanguageModelToolResult { toolResultMessage: MarkdownString.fromStrict(result.toolResultMessage), toolResultDetails: detailsDto, toolMetadata: result.toolMetadata, + toolResultError: result.hasError, }; return hasBuffers ? new SerializableObjectWithBuffers(dto) : dto; diff --git a/src/vs/workbench/contrib/chat/common/tools/languageModelToolsService.ts b/src/vs/workbench/contrib/chat/common/tools/languageModelToolsService.ts index d14a93696e08e..fe83345a4a2af 100644 --- a/src/vs/workbench/contrib/chat/common/tools/languageModelToolsService.ts +++ b/src/vs/workbench/contrib/chat/common/tools/languageModelToolsService.ts @@ -265,7 +265,7 @@ export interface IToolResult { content: (IToolResultPromptTsxPart | IToolResultTextPart | IToolResultDataPart)[]; toolResultMessage?: string | IMarkdownString; toolResultDetails?: Array | IToolResultInputOutputDetails | IToolResultOutputDetails; - toolResultError?: string; + toolResultError?: string | boolean; toolMetadata?: unknown; /** Whether to ask the user to confirm these tool results. Overrides {@link IToolConfirmationMessages.confirmResults}. */ confirmResults?: boolean; diff --git a/src/vs/workbench/contrib/chat/test/browser/tools/languageModelToolsService.test.ts b/src/vs/workbench/contrib/chat/test/browser/tools/languageModelToolsService.test.ts index f642745892e92..f8ee29ce85fbf 100644 --- a/src/vs/workbench/contrib/chat/test/browser/tools/languageModelToolsService.test.ts +++ b/src/vs/workbench/contrib/chat/test/browser/tools/languageModelToolsService.test.ts @@ -3905,7 +3905,7 @@ suite('LanguageModelToolsService', () => { // Verify error result returned assert.ok(result.toolResultError); - assert.ok(result.toolResultError.includes('Destructive operations require approval')); + assert.ok((result.toolResultError as string).includes('Destructive operations require approval')); assert.strictEqual(result.content[0].kind, 'text'); assert.ok((result.content[0] as IToolResultTextPart).value.includes('Tool execution denied')); From 0e26d29ff526c10d2c909bdd5c30e4396a2ceaec Mon Sep 17 00:00:00 2001 From: David Dossett <25163139+daviddossett@users.noreply.github.com> Date: Fri, 27 Feb 2026 12:29:57 -0800 Subject: [PATCH 32/40] exp-enable chat.implicitContext.enabled (#298317) * chat: mark implicitContext.enabled as experiment-configurable * chat: tag implicitContext.enabled as experimental --- src/vs/workbench/contrib/chat/browser/chat.contribution.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/vs/workbench/contrib/chat/browser/chat.contribution.ts b/src/vs/workbench/contrib/chat/browser/chat.contribution.ts index d50fc45f037c1..f03c6e33b820f 100644 --- a/src/vs/workbench/contrib/chat/browser/chat.contribution.ts +++ b/src/vs/workbench/contrib/chat/browser/chat.contribution.ts @@ -265,6 +265,10 @@ configurationRegistry.registerConfiguration({ }, default: { 'panel': 'always', + }, + tags: ['experimental'], + experiment: { + mode: 'startup' } }, 'chat.implicitContext.suggestedContext': { From 12137e81005e133d2c04fa5f104c8c5479c2e6e6 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Fri, 27 Feb 2026 22:03:28 +0100 Subject: [PATCH 33/40] chat - restore default click behaviour on title action (#298340) * chat - restore default click behaviour on title action * ccr --- .../chat/browser/actions/chatActions.ts | 34 ++++--------------- .../contrib/chat/browser/chat.contribution.ts | 16 +-------- .../contrib/chat/common/constants.ts | 6 ---- 3 files changed, 7 insertions(+), 49 deletions(-) diff --git a/src/vs/workbench/contrib/chat/browser/actions/chatActions.ts b/src/vs/workbench/contrib/chat/browser/actions/chatActions.ts index d1232f91828ff..b6ea731238562 100644 --- a/src/vs/workbench/contrib/chat/browser/actions/chatActions.ts +++ b/src/vs/workbench/contrib/chat/browser/actions/chatActions.ts @@ -55,7 +55,7 @@ import { ElicitationState, IChatService, IChatToolInvocation } from '../../commo import { ISCMHistoryItemChangeRangeVariableEntry, ISCMHistoryItemChangeVariableEntry } from '../../common/attachments/chatVariableEntries.js'; import { IChatRequestViewModel, IChatResponseViewModel, isRequestVM } from '../../common/model/chatViewModel.js'; import { IChatWidgetHistoryService } from '../../common/widget/chatWidgetHistoryService.js'; -import { AgentsControlClickBehavior, ChatAgentLocation, ChatConfiguration, ChatModeKind } from '../../common/constants.js'; +import { ChatAgentLocation, ChatConfiguration, ChatModeKind } from '../../common/constants.js'; import { ILanguageModelChatSelector, ILanguageModelsService } from '../../common/languageModels.js'; import { CopilotUsageExtensionFeatureId } from '../../common/languageModelStats.js'; import { ILanguageModelToolsConfirmationService } from '../../common/tools/languageModelToolsConfirmationService.js'; @@ -600,36 +600,14 @@ export function registerChatActions() { const viewsService = accessor.get(IViewsService); const viewDescriptorService = accessor.get(IViewDescriptorService); const widgetService = accessor.get(IChatWidgetService); - const configurationService = accessor.get(IConfigurationService); const chatLocation = viewDescriptorService.getViewLocationById(ChatViewId); const chatVisible = viewsService.isViewVisible(ChatViewId); - const clickBehavior = configurationService.getValue(ChatConfiguration.AgentsControlClickBehavior); - switch (clickBehavior) { - case AgentsControlClickBehavior.Cycle: - if (chatVisible) { - if ( - chatLocation === ViewContainerLocation.AuxiliaryBar && - !layoutService.isAuxiliaryBarMaximized() - ) { - layoutService.setAuxiliaryBarMaximized(true); - (await widgetService.revealWidget())?.focusInput(); - } else { - this.updatePartVisibility(layoutService, chatLocation, false); - } - } else { - this.updatePartVisibility(layoutService, chatLocation, true); - (await widgetService.revealWidget())?.focusInput(); - } - break; - default: - if (chatVisible) { - this.updatePartVisibility(layoutService, chatLocation, false); - } else { - this.updatePartVisibility(layoutService, chatLocation, true); - (await widgetService.revealWidget())?.focusInput(); - } - break; + if (chatVisible) { + this.updatePartVisibility(layoutService, chatLocation, false); + } else { + this.updatePartVisibility(layoutService, chatLocation, true); + (await widgetService.revealWidget())?.focusInput(); } } diff --git a/src/vs/workbench/contrib/chat/browser/chat.contribution.ts b/src/vs/workbench/contrib/chat/browser/chat.contribution.ts index f03c6e33b820f..aad03e3583ae4 100644 --- a/src/vs/workbench/contrib/chat/browser/chat.contribution.ts +++ b/src/vs/workbench/contrib/chat/browser/chat.contribution.ts @@ -44,7 +44,7 @@ import { ChatTodoListService, IChatTodoListService } from '../common/tools/chatT import { ChatTransferService, IChatTransferService } from '../common/model/chatTransferService.js'; import { IChatVariablesService } from '../common/attachments/chatVariables.js'; import { ChatWidgetHistoryService, IChatWidgetHistoryService } from '../common/widget/chatWidgetHistoryService.js'; -import { AgentsControlClickBehavior, ChatConfiguration, ChatNotificationMode } from '../common/constants.js'; +import { ChatConfiguration, ChatNotificationMode } from '../common/constants.js'; import { ILanguageModelIgnoredFilesService, LanguageModelIgnoredFilesService } from '../common/ignoredFiles.js'; import { ILanguageModelsService, LanguageModelsService } from '../common/languageModels.js'; import { ILanguageModelStatsService, LanguageModelStatsService } from '../common/languageModelStats.js'; @@ -218,20 +218,6 @@ configurationRegistry.registerConfiguration({ description: nls.localize('interactiveSession.editor.lineHeight', "Controls the line height in pixels in chat codeblocks. Use 0 to compute the line height from the font size."), default: 0 }, - [ChatConfiguration.AgentsControlClickBehavior]: { - type: 'string', - enum: [AgentsControlClickBehavior.Default, AgentsControlClickBehavior.Cycle], - enumDescriptions: [ - nls.localize('chat.agentsControl.clickBehavior.default', "Clicking chat icon toggles chat visibility."), - nls.localize('chat.agentsControl.clickBehavior.cycle', "Clicking chat icon cycles through: show chat, maximize chat, hide chat. This requires chat to be contained in the secondary sidebar."), - ], - markdownDescription: nls.localize('chat.agentsControl.clickBehavior', "Controls the behavior when clicking on the chat icon in the command center."), - default: AgentsControlClickBehavior.Default, // TODO@bpasero figure out the default - tags: ['experimental'], - experiment: { - mode: 'auto' - } - }, [ChatConfiguration.AgentStatusEnabled]: { type: 'boolean', markdownDescription: nls.localize('chat.agentsControl.enabled', "Controls whether the 'Agent Status' indicator is shown in the title bar command center. Enabling this setting will automatically enable {0}. The unread/in-progress session indicators require {1} to be enabled.", '`#window.commandCenter#`', '`#chat.viewSessions.enabled#`'), diff --git a/src/vs/workbench/contrib/chat/common/constants.ts b/src/vs/workbench/contrib/chat/common/constants.ts index d7ce75b61bd31..57b1391e68f21 100644 --- a/src/vs/workbench/contrib/chat/common/constants.ts +++ b/src/vs/workbench/contrib/chat/common/constants.ts @@ -52,7 +52,6 @@ export enum ChatConfiguration { ShowCodeBlockProgressAnimation = 'chat.agent.codeBlockProgress', RestoreLastPanelSession = 'chat.restoreLastPanelSession', ExitAfterDelegation = 'chat.exitAfterDelegation', - AgentsControlClickBehavior = 'chat.agentsControl.clickBehavior', ExplainChangesEnabled = 'chat.editing.explainChanges.enabled', GrowthNotificationEnabled = 'chat.growthNotification.enabled', ChatCustomizationMenuEnabled = 'chat.customizationsMenu.enabled', @@ -101,11 +100,6 @@ export enum ChatNotificationMode { Always = 'always', } -export enum AgentsControlClickBehavior { - Default = 'default', - Cycle = 'cycle', -} - export type RawChatParticipantLocation = 'panel' | 'terminal' | 'notebook' | 'editing-session'; export enum ChatAgentLocation { From 6cfe4cc77b1907009d5ac924b8382c23111522a9 Mon Sep 17 00:00:00 2001 From: Justin Chen <54879025+justschen@users.noreply.github.com> Date: Fri, 27 Feb 2026 13:14:26 -0800 Subject: [PATCH 34/40] fix stray checkmarks, consistent opacity, and icon not showing up (#298346) --- .../chatSubagentContentPart.ts | 23 +++++++++++++++++++ .../media/chatConfirmationWidget.css | 1 + .../media/chatThinkingContent.css | 3 ++- .../chat/browser/widget/chatListRenderer.ts | 9 ++++++++ .../chat/browser/widget/media/chat.css | 12 +++++++++- 5 files changed, 46 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatSubagentContentPart.ts b/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatSubagentContentPart.ts index 969d7b506a0d0..7a4f6d0a12919 100644 --- a/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatSubagentContentPart.ts +++ b/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatSubagentContentPart.ts @@ -379,6 +379,29 @@ export class ChatSubagentContentPart extends ChatCollapsibleContentPart implemen const labelElement = this._collapseButton.labelElement; + if (!this.isActive) { + labelElement.textContent = ''; + this.titleShimmerSpan = undefined; + + if (this.titleDetailRendered) { + this.titleDetailRendered.dispose(); + this.titleDetailRendered = undefined; + } + this.titleDetailContainer = undefined; + + const prefixSpan = $('span'); + prefixSpan.textContent = `${prefix}:`; + labelElement.appendChild(prefixSpan); + + const descSpan = $('span.chat-thinking-title-detail-text'); + descSpan.textContent = ` ${this.description}`; + labelElement.appendChild(descSpan); + + this._collapseButton.element.ariaLabel = shimmerText; + this._collapseButton.element.ariaExpanded = String(this.isExpanded()); + return; + } + // Ensure the persistent shimmer span exists if (!this.titleShimmerSpan || !this.titleShimmerSpan.parentElement) { labelElement.textContent = ''; diff --git a/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/media/chatConfirmationWidget.css b/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/media/chatConfirmationWidget.css index c96e09ae84995..cd5343e662e84 100644 --- a/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/media/chatConfirmationWidget.css +++ b/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/media/chatConfirmationWidget.css @@ -104,6 +104,7 @@ .chat-confirmation-widget-title small { font-size: 1em; + opacity: 0.7; &::before { content: ' \2013 '; diff --git a/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/media/chatThinkingContent.css b/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/media/chatThinkingContent.css index 31acb4c321b58..f6732a06bb70e 100644 --- a/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/media/chatThinkingContent.css +++ b/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/media/chatThinkingContent.css @@ -142,7 +142,8 @@ } /* todo: ideally not !important, but the competing css has 14 specificity */ - .codicon:not(.chat-thinking-icon){ + .codicon.codicon-check, + .codicon.codicon-loading { display: none !important; } diff --git a/src/vs/workbench/contrib/chat/browser/widget/chatListRenderer.ts b/src/vs/workbench/contrib/chat/browser/widget/chatListRenderer.ts index 1cf8b39f364e6..5130b606b9832 100644 --- a/src/vs/workbench/contrib/chat/browser/widget/chatListRenderer.ts +++ b/src/vs/workbench/contrib/chat/browser/widget/chatListRenderer.ts @@ -110,6 +110,7 @@ import { ChatPendingDragController } from './chatPendingDragAndDrop.js'; import { HookType } from '../../common/promptSyntax/hookSchema.js'; import { ChatQuestionCarouselAutoReply } from './chatQuestionCarouselAutoReply.js'; import { IWorkbenchEnvironmentService } from '../../../../services/environment/common/environmentService.js'; +import { AccessibilityWorkbenchSettingId } from '../../../accessibility/browser/accessibilityConfiguration.js'; const $ = dom.$; @@ -912,6 +913,14 @@ export class ChatListItemRenderer extends Disposable implements ITreeRenderer templateData.detail.classList.toggle('show-checkmarks', !!this.configService.getValue(AccessibilityWorkbenchSettingId.ShowChatCheckmarks)); + updateCheckmarks(); + templateData.elementDisposables.add(this.configService.onDidChangeConfiguration(e => { + if (e.affectsConfiguration(AccessibilityWorkbenchSettingId.ShowChatCheckmarks)) { + updateCheckmarks(); + } + })); } } diff --git a/src/vs/workbench/contrib/chat/browser/widget/media/chat.css b/src/vs/workbench/contrib/chat/browser/widget/media/chat.css index b714445a27378..7b56f08edf556 100644 --- a/src/vs/workbench/contrib/chat/browser/widget/media/chat.css +++ b/src/vs/workbench/contrib/chat/browser/widget/media/chat.css @@ -2726,15 +2726,25 @@ have to be updated for changes to the rules above, or to support more deeply nes } .interactive-request .header.partially-disabled .detail-container { - margin-left: 4px; + margin-left: 0px; } .interactive-item-container .header .detail .codicon-check { margin-right: 7px; vertical-align: middle; font-size: 11px; + display: none; } + .interactive-item-container .header.partially-disabled .detail.show-checkmarks { + margin-left: 4px; + + .codicon-check { + display: inline; + } + } + + .request-hover { position: absolute; overflow: hidden; From 20c89b059879bd56c2e2dbd93bde634899d73065 Mon Sep 17 00:00:00 2001 From: David Dossett <25163139+daviddossett@users.noreply.github.com> Date: Fri, 27 Feb 2026 13:25:49 -0800 Subject: [PATCH 35/40] Polish model picker filter input (#298321) Hide focus outline on model picker filter input --- .../contrib/chat/browser/widget/input/chatModelPicker.ts | 5 +++++ .../workbench/contrib/chat/browser/widget/media/chat.css | 7 +++++++ 2 files changed, 12 insertions(+) diff --git a/src/vs/workbench/contrib/chat/browser/widget/input/chatModelPicker.ts b/src/vs/workbench/contrib/chat/browser/widget/input/chatModelPicker.ts index 9b50df71c0135..e5c907aed38d1 100644 --- a/src/vs/workbench/contrib/chat/browser/widget/input/chatModelPicker.ts +++ b/src/vs/workbench/contrib/chat/browser/widget/input/chatModelPicker.ts @@ -596,6 +596,11 @@ export class ModelPickerWidget extends Disposable { getModelPickerAccessibilityProvider(), listOptions ); + + const activeElement = dom.getActiveElement(); + if (dom.isHTMLInputElement(activeElement) && activeElement.classList.contains('action-list-filter-input')) { + activeElement.classList.add('chat-model-picker-filter-input'); + } } private _updateBadge(): void { diff --git a/src/vs/workbench/contrib/chat/browser/widget/media/chat.css b/src/vs/workbench/contrib/chat/browser/widget/media/chat.css index 7b56f08edf556..47b58886cdebd 100644 --- a/src/vs/workbench/contrib/chat/browser/widget/media/chat.css +++ b/src/vs/workbench/contrib/chat/browser/widget/media/chat.css @@ -1436,6 +1436,13 @@ have to be updated for changes to the rules above, or to support more deeply nes color: var(--vscode-textLink-activeForeground); } +.action-widget .action-list-filter-input.chat-model-picker-filter-input, +.action-widget .action-list-filter-input.chat-model-picker-filter-input:focus { + outline: none; + box-shadow: none; + border-color: transparent; +} + .interactive-session .chat-input-toolbars .codicon-debug-stop { color: var(--vscode-icon-foreground) !important; } From 6c24652ced91d5bf9c07c0a67512a40e9799feab Mon Sep 17 00:00:00 2001 From: David Dossett <25163139+daviddossett@users.noreply.github.com> Date: Fri, 27 Feb 2026 13:26:00 -0800 Subject: [PATCH 36/40] Refine steering/stop button state behavior (#298124) * chat: refine steering/stop-send input button states * chat: simplify steering and stop button state logic * Chat: keep Cancel visible for pending tool UI --- .../contrib/chat/browser/actions/chatExecuteActions.ts | 10 +++++++++- .../contrib/chat/browser/actions/chatQueueActions.ts | 5 ++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/chat/browser/actions/chatExecuteActions.ts b/src/vs/workbench/contrib/chat/browser/actions/chatExecuteActions.ts index 9701a79f06436..292cf32d80d7a 100644 --- a/src/vs/workbench/contrib/chat/browser/actions/chatExecuteActions.ts +++ b/src/vs/workbench/contrib/chat/browser/actions/chatExecuteActions.ts @@ -185,6 +185,14 @@ const requestInProgressOrPendingToolCall = ContextKeyExpr.or( ChatContextKeys.Editing.hasToolConfirmation, ChatContextKeys.Editing.hasQuestionCarousel, ); +const requestInProgressWithoutInput = ContextKeyExpr.and( + ChatContextKeys.requestInProgress, + ChatContextKeys.inputHasText.negate(), +); +const pendingToolCall = ContextKeyExpr.or( + ChatContextKeys.Editing.hasToolConfirmation, + ChatContextKeys.Editing.hasQuestionCarousel, +); const whenNotInProgress = ChatContextKeys.requestInProgress.negate(); export class ChatSubmitAction extends SubmitAction { @@ -838,7 +846,7 @@ export class CancelAction extends Action2 { menu: [{ id: MenuId.ChatExecute, when: ContextKeyExpr.and( - requestInProgressOrPendingToolCall, + ContextKeyExpr.or(requestInProgressWithoutInput, pendingToolCall), ChatContextKeys.remoteJobCreating.negate(), ChatContextKeys.currentlyEditing.negate(), ), diff --git a/src/vs/workbench/contrib/chat/browser/actions/chatQueueActions.ts b/src/vs/workbench/contrib/chat/browser/actions/chatQueueActions.ts index 2db5e67e5d3c3..6606748d653f4 100644 --- a/src/vs/workbench/contrib/chat/browser/actions/chatQueueActions.ts +++ b/src/vs/workbench/contrib/chat/browser/actions/chatQueueActions.ts @@ -280,7 +280,10 @@ export function registerChatQueueActions(): void { submenu: MenuId.ChatExecuteQueue, title: localize2('chat.queueSubmenu', "Queue"), icon: Codicon.listOrdered, - when: queuingActionsPresent, + when: ContextKeyExpr.and( + queuingActionsPresent, + ChatContextKeys.inputHasText, + ), group: 'navigation', order: 4, }); From ca4a24a25b243995e8c732db588426304e2ce9fd Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Fri, 27 Feb 2026 13:40:30 -0800 Subject: [PATCH 37/40] sessions: be overly verbose about errors that happen during serialization (#298350) Not sure the error is in here, but if it is, this should help. --- .../chat/common/model/chatSessionStore.ts | 33 +++++++++++- .../chat/common/model/objectMutationLog.ts | 52 +++++++++++++++++-- 2 files changed, 81 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/contrib/chat/common/model/chatSessionStore.ts b/src/vs/workbench/contrib/chat/common/model/chatSessionStore.ts index cecb075bd83f8..28253d0586ebb 100644 --- a/src/vs/workbench/contrib/chat/common/model/chatSessionStore.ts +++ b/src/vs/workbench/contrib/chat/common/model/chatSessionStore.ts @@ -13,9 +13,11 @@ import { joinPath } from '../../../../../base/common/resources.js'; import { URI } from '../../../../../base/common/uri.js'; import { localize } from '../../../../../nls.js'; import { IConfigurationService } from '../../../../../platform/configuration/common/configuration.js'; +import { IDialogService } from '../../../../../platform/dialogs/common/dialogs.js'; import { IEnvironmentService } from '../../../../../platform/environment/common/environment.js'; import { FileOperationResult, IFileService, toFileOperationResult } from '../../../../../platform/files/common/files.js'; import { ILogService } from '../../../../../platform/log/common/log.js'; +import { IOpenerService } from '../../../../../platform/opener/common/opener.js'; import { IStorageService, StorageScope, StorageTarget } from '../../../../../platform/storage/common/storage.js'; import { ITelemetryService } from '../../../../../platform/telemetry/common/telemetry.js'; import { IUserDataProfilesService } from '../../../../../platform/userDataProfile/common/userDataProfile.js'; @@ -57,6 +59,8 @@ export class ChatSessionStore extends Disposable { @IUserDataProfilesService private readonly userDataProfilesService: IUserDataProfilesService, @IConfigurationService private readonly configurationService: IConfigurationService, @IWorkspaceEditingService private readonly workspaceEditingService: IWorkspaceEditingService, + @IDialogService private readonly dialogService: IDialogService, + @IOpenerService private readonly openerService: IOpenerService, ) { super(); @@ -339,6 +343,8 @@ export class ChatSessionStore extends Disposable { } } + private _didReportIssue = false; + private async writeSession(session: ChatModel | ISerializableChatData): Promise { try { const index = this.internalGetIndex(); @@ -349,7 +355,32 @@ export class ChatSessionStore extends Disposable { session.dataSerializer = new ChatSessionOperationLog(); } - const { op, data } = session.dataSerializer.write(session); + let op: 'append' | 'replace'; + let data: VSBuffer; + try { + ({ op, data } = session.dataSerializer.write(session)); + } catch (e) { + // This is a big of an ugly prompt, but there is _something_ going on with + // missing sessions. Unfortunately it's hard to root cause because users would + // not notice an error until they reload the window, at which point any error + // is gone. Throw a very verbose dialog here so we can get some quality + // bug reports, if the issue is indeed in the serialized. + // todo@connor4312: remove after a little bit + if (!this._didReportIssue) { + this._didReportIssue = true; + this.dialogService.prompt({ + custom: true, // so text is copyable + title: localize('chatSessionStore.serializationError', 'Error saving chat session'), + message: localize('chatSessionStore.writeError', 'Error serializing chat session for storage. The session will be lost if the window is closed. Please report this issue to the VS Code team:\n\n{0}', e.stack || toErrorMessage(e)), + buttons: [ + { label: localize('reportIssue', 'Report Issue'), run: () => this.openerService.open('https://github.com/microsoft/vscode/issues/new?template=bug_report.md') } + ] + }); + } + + throw e; + } + if (data.byteLength > 0) { await this.fileService.writeFile(storageLocation.log, data, { append: op === 'append' }); } diff --git a/src/vs/workbench/contrib/chat/common/model/objectMutationLog.ts b/src/vs/workbench/contrib/chat/common/model/objectMutationLog.ts index 01ce16ae67a9b..1e134a69a6d54 100644 --- a/src/vs/workbench/contrib/chat/common/model/objectMutationLog.ts +++ b/src/vs/workbench/contrib/chat/common/model/objectMutationLog.ts @@ -7,6 +7,34 @@ import { assertNever } from '../../../../../base/common/assert.js'; import { VSBuffer } from '../../../../../base/common/buffer.js'; import { isUndefinedOrNull } from '../../../../../base/common/types.js'; +/** + * Updates an error's message and stack trace with a prefix. In V8 the stack + * string starts with "ErrorName: message\n at …", so we rebuild the header + * after mutating the message. + */ +function prefixError(e: Error, prefix: string): void { + e.message = prefix + e.message; + if (e.stack) { + const nlIdx = e.stack.indexOf('\n'); + e.stack = nlIdx !== -1 + ? `${e.name}: ${e.message}${e.stack.slice(nlIdx)}` + : `${e.name}: ${e.message}`; + } +} + +/** + * Prepends a path segment to an error as it unwinds through nested extract + * calls. Each level adds its segment so the final message reads e.g. + * `.responses[2].content: Cannot read property 'x' of undefined`. + */ +function rethrowWithPathSegment(e: unknown, segment: string | number): never { + if (e instanceof Error) { + const part = typeof segment === 'number' ? `[${segment}]` : `.${segment}`; + const needsSep = !e.message.startsWith('[') && !e.message.startsWith('.'); + prefixError(e, part + (needsSep ? ': ' : '')); + } + throw e; +} /** IMPORTANT: `Key` comes first. Then we should sort in order of least->most expensive to diff */ const enum TransformKind { @@ -96,7 +124,13 @@ export function array(schema: TransformObject | TransformValue return { kind: TransformKind.Array, itemSchema: schema, - extract: from => from?.map(item => schema.extract(item)), + extract: from => from?.map((item, i) => { + try { + return schema.extract(item); + } catch (e) { + rethrowWithPathSegment(e, i); + } + }), }; } @@ -124,7 +158,11 @@ export function object(schema: Schema, options?: Obje const result: Record = Object.create(null); for (const [key, transform] of entries) { - result[key] = transform.extract(from); + try { + result[key] = transform.extract(from); + } catch (e) { + rethrowWithPathSegment(e, key); + } } return result as R; }, @@ -278,7 +316,15 @@ export class ObjectMutationLog { // Generate diff entries const entries: Entry[] = []; const path: ObjectPath = []; - this._diff(this._transform, path, this._previous, currentValue, entries); + try { + this._diff(this._transform, path, this._previous, currentValue, entries); + } catch (e) { + if (e instanceof Error) { + const pathStr = path.map(s => typeof s === 'number' ? `[${s}]` : `.${s}`).join('') || ''; + prefixError(e, `error diffing at ${pathStr}: `); + } + throw e; + } if (entries.length === 0) { // No changes From d17f65c2c6c6556ad0e6c7c387d11d96339a11b9 Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Fri, 27 Feb 2026 13:42:37 -0800 Subject: [PATCH 38/40] plugins: add a /plugins command to open the plugins view (#298351) Common entrypoint from other tools. Similar to /skills --- .../contrib/chat/browser/actions/chatPluginActions.ts | 2 +- .../contrib/chat/browser/chatSlashCommands.ts | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/chat/browser/actions/chatPluginActions.ts b/src/vs/workbench/contrib/chat/browser/actions/chatPluginActions.ts index 3a5f9993b0f71..c4186a2adca5f 100644 --- a/src/vs/workbench/contrib/chat/browser/actions/chatPluginActions.ts +++ b/src/vs/workbench/contrib/chat/browser/actions/chatPluginActions.ts @@ -10,7 +10,7 @@ import { ChatContextKeys } from '../../common/actions/chatContextKeys.js'; import { CHAT_CATEGORY, CHAT_CONFIG_MENU_ID } from './chatActions.js'; import { IExtensionsWorkbenchService } from '../../../extensions/common/extensions.js'; -class ManagePluginsAction extends Action2 { +export class ManagePluginsAction extends Action2 { static readonly ID = 'workbench.action.chat.managePlugins'; constructor() { diff --git a/src/vs/workbench/contrib/chat/browser/chatSlashCommands.ts b/src/vs/workbench/contrib/chat/browser/chatSlashCommands.ts index 9acdbe8df1642..16c998243669a 100644 --- a/src/vs/workbench/contrib/chat/browser/chatSlashCommands.ts +++ b/src/vs/workbench/contrib/chat/browser/chatSlashCommands.ts @@ -19,6 +19,7 @@ import { IChatService } from '../common/chatService/chatService.js'; import { ChatAgentLocation, ChatConfiguration, ChatModeKind } from '../common/constants.js'; import { ACTION_ID_NEW_CHAT } from './actions/chatActions.js'; import { ChatSubmitAction, OpenModePickerAction, OpenModelPickerAction } from './actions/chatExecuteActions.js'; +import { ManagePluginsAction } from './actions/chatPluginActions.js'; import { ConfigureToolsAction } from './actions/chatToolActions.js'; import { IAgentSessionsService } from './agentSessions/agentSessionsService.js'; import { CONFIGURE_INSTRUCTIONS_ACTION_ID } from './promptSyntax/attachInstructionsAction.js'; @@ -87,6 +88,16 @@ export class ChatSlashCommandsContribution extends Disposable { }, async () => { await commandService.executeCommand(ConfigureToolsAction.ID); })); + this._store.add(slashCommandService.registerSlashCommand({ + command: 'plugins', + detail: nls.localize('plugins', "Manage plugins"), + sortText: 'z3_plugins', + executeImmediately: true, + silent: true, + locations: [ChatAgentLocation.Chat] + }, async () => { + await commandService.executeCommand(ManagePluginsAction.ID); + })); this._store.add(slashCommandService.registerSlashCommand({ command: 'debug', detail: nls.localize('debug', "Show Chat Debug View"), From ac857d4c00759ffd2794e5e5ca4712717750fd83 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Fri, 27 Feb 2026 21:43:43 +0000 Subject: [PATCH 39/40] Fix: Honor deprecated `infer: false` in custom agent visibility (#297003) * Initial plan * fix: honor deprecated infer:false in custom agent visibility Co-authored-by: aeschli <6461412+aeschli@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: aeschli <6461412+aeschli@users.noreply.github.com> --- .../service/promptsServiceImpl.ts | 2 +- .../service/promptsService.test.ts | 54 +++++++++++++++++++ 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/service/promptsServiceImpl.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/service/promptsServiceImpl.ts index 7394858cd2ab6..6c566c8bbdc06 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/service/promptsServiceImpl.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/service/promptsServiceImpl.ts @@ -711,7 +711,7 @@ export class PromptsService extends Disposable implements IPromptsService { } const visibility = { userInvocable: ast.header.userInvocable !== false, - agentInvocable: ast.header.infer === true || ast.header.disableModelInvocation !== true, + agentInvocable: ast.header.infer !== undefined ? ast.header.infer === true : ast.header.disableModelInvocation !== true, } satisfies ICustomAgentVisibility; let model = ast.header.model; diff --git a/src/vs/workbench/contrib/chat/test/common/promptSyntax/service/promptsService.test.ts b/src/vs/workbench/contrib/chat/test/common/promptSyntax/service/promptsService.test.ts index dc2fb6d67b9c7..59673c29689fd 100644 --- a/src/vs/workbench/contrib/chat/test/common/promptSyntax/service/promptsService.test.ts +++ b/src/vs/workbench/contrib/chat/test/common/promptSyntax/service/promptsService.test.ts @@ -1338,6 +1338,60 @@ suite('PromptsService', () => { ); }); + test('header with infer: false sets agentInvocable to false', async () => { + const rootFolderName = 'custom-agents-infer-false'; + const rootFolder = `/${rootFolderName}`; + const rootFolderUri = URI.file(rootFolder); + + workspaceContextService.setWorkspace(testWorkspace(rootFolderUri)); + + await mockFiles(fileService, [ + { + path: `${rootFolder}/.github/agents/agent-infer-false.agent.md`, + contents: [ + '---', + 'description: \'Agent with infer: false.\'', + 'infer: false', + '---', + 'I should not be invocable by the model.', + ] + }, + { + path: `${rootFolder}/.github/agents/agent-infer-true.agent.md`, + contents: [ + '---', + 'description: \'Agent with infer: true.\'', + 'infer: true', + '---', + 'I should be invocable by the model.', + ] + }, + { + path: `${rootFolder}/.github/agents/agent-no-infer.agent.md`, + contents: [ + '---', + 'description: \'Agent without infer.\'', + '---', + 'I should default to being invocable by the model.', + ] + } + ]); + + const result = (await service.getCustomAgents(CancellationToken.None)).map(agent => ({ ...agent, uri: URI.from(agent.uri) })); + + const inferFalseAgent = result.find(a => a.name === 'agent-infer-false'); + assert.ok(inferFalseAgent, 'Should find agent with infer: false'); + assert.strictEqual(inferFalseAgent.visibility.agentInvocable, false, 'infer: false should set agentInvocable to false'); + + const inferTrueAgent = result.find(a => a.name === 'agent-infer-true'); + assert.ok(inferTrueAgent, 'Should find agent with infer: true'); + assert.strictEqual(inferTrueAgent.visibility.agentInvocable, true, 'infer: true should set agentInvocable to true'); + + const noInferAgent = result.find(a => a.name === 'agent-no-infer'); + assert.ok(noInferAgent, 'Should find agent without infer'); + assert.strictEqual(noInferAgent.visibility.agentInvocable, true, 'missing infer should default agentInvocable to true'); + }); + test('agents from user data folder', async () => { const rootFolderName = 'custom-agents-user-data'; const rootFolder = `/${rootFolderName}`; From f8edf625b8b5b7fd9717c31ec834c8e8a062f885 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Fri, 27 Feb 2026 22:46:44 +0100 Subject: [PATCH 40/40] distro (#298343) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 92aade626d160..d7f05095ed7c5 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "code-oss-dev", "version": "1.110.0", - "distro": "8445dd0629deae101785f6b8e406ab3784a42fa6", + "distro": "31b6675a65c3b72a5a20fdc648050340585879c3", "author": { "name": "Microsoft Corporation" },