From 9ffbee79e0efcc078bb141d12eaef1cc2e6a4d1d Mon Sep 17 00:00:00 2001 From: BeniBenj Date: Wed, 5 Nov 2025 13:04:33 +0100 Subject: [PATCH] unification improvements --- .../configuration/common/configurationRegistry.ts | 8 ++++---- .../workbench/api/common/configurationExtensionPoint.ts | 6 +++--- .../contrib/relauncher/browser/relauncher.contribution.ts | 8 +++++++- .../services/configuration/browser/configuration.ts | 6 ------ .../browser/extensionEnablementService.ts | 4 +--- 5 files changed, 15 insertions(+), 17 deletions(-) diff --git a/src/vs/platform/configuration/common/configurationRegistry.ts b/src/vs/platform/configuration/common/configurationRegistry.ts index 3a6670a5b1f..cdcbf0ae3f6 100644 --- a/src/vs/platform/configuration/common/configurationRegistry.ts +++ b/src/vs/platform/configuration/common/configurationRegistry.ts @@ -674,7 +674,7 @@ class ConfigurationRegistry extends Disposable implements IConfigurationRegistry order: configuration.order, extensionInfo: configuration.extensionInfo }; - if (validate && validateProperty(key, property)) { + if (validate && validateProperty(key, property, extensionInfo?.id)) { delete properties[key]; continue; } @@ -940,14 +940,14 @@ export function getDefaultValue(type: string | string[] | undefined) { const configurationRegistry = new ConfigurationRegistry(); Registry.add(Extensions.Configuration, configurationRegistry); -export function validateProperty(property: string, schema: IRegisteredConfigurationPropertySchema): string | null { +export function validateProperty(property: string, schema: IRegisteredConfigurationPropertySchema, extensionId?: string): string | null { if (!property.trim()) { return nls.localize('config.property.empty', "Cannot register an empty property"); } if (OVERRIDE_PROPERTY_REGEX.test(property)) { return nls.localize('config.property.languageDefault', "Cannot register '{0}'. This matches property pattern '\\\\[.*\\\\]$' for describing language specific editor settings. Use 'configurationDefaults' contribution.", property); } - if (configurationRegistry.getConfigurationProperties()[property] !== undefined && !CODE_UNIFICATION_DUPLICATE_SETTINGS.has(property)) { + if (configurationRegistry.getConfigurationProperties()[property] !== undefined && (!extensionId || !EXTENSION_UNIFICATION_EXTENSION_IDS.has(extensionId.toLowerCase()))) { return nls.localize('config.property.duplicate', "Cannot register '{0}'. This property is already registered.", property); } if (schema.policy?.name && configurationRegistry.getPolicyConfigurations().get(schema.policy?.name) !== undefined) { @@ -1001,4 +1001,4 @@ export function parseScope(scope: string): ConfigurationScope { } // Used for extension unification. Should be removed when complete. -export const CODE_UNIFICATION_DUPLICATE_SETTINGS: Set = new Set([product.defaultChatAgent?.completionsEnablementSetting].filter(Boolean) as string[]); +export const EXTENSION_UNIFICATION_EXTENSION_IDS: Set = new Set(product.defaultChatAgent ? [product.defaultChatAgent.extensionId, product.defaultChatAgent.chatExtensionId].map(id => id.toLowerCase()) : []); diff --git a/src/vs/workbench/api/common/configurationExtensionPoint.ts b/src/vs/workbench/api/common/configurationExtensionPoint.ts index 95b65159679..53177fb9eba 100644 --- a/src/vs/workbench/api/common/configurationExtensionPoint.ts +++ b/src/vs/workbench/api/common/configurationExtensionPoint.ts @@ -8,7 +8,7 @@ import * as objects from '../../../base/common/objects.js'; import { Registry } from '../../../platform/registry/common/platform.js'; import { IJSONSchema } from '../../../base/common/jsonSchema.js'; import { ExtensionsRegistry, IExtensionPointUser } from '../../services/extensions/common/extensionsRegistry.js'; -import { IConfigurationNode, IConfigurationRegistry, Extensions, validateProperty, ConfigurationScope, OVERRIDE_PROPERTY_REGEX, IConfigurationDefaults, configurationDefaultsSchemaId, IConfigurationDelta, getDefaultValue, getAllConfigurationProperties, parseScope, CODE_UNIFICATION_DUPLICATE_SETTINGS } from '../../../platform/configuration/common/configurationRegistry.js'; +import { IConfigurationNode, IConfigurationRegistry, Extensions, validateProperty, ConfigurationScope, OVERRIDE_PROPERTY_REGEX, IConfigurationDefaults, configurationDefaultsSchemaId, IConfigurationDelta, getDefaultValue, getAllConfigurationProperties, parseScope, EXTENSION_UNIFICATION_EXTENSION_IDS } from '../../../platform/configuration/common/configurationRegistry.js'; import { IJSONContributionRegistry, Extensions as JSONExtensions } from '../../../platform/jsonschemas/common/jsonContributionRegistry.js'; import { workspaceSettingsSchemaId, launchSchemaId, tasksSchemaId, mcpSchemaId } from '../../services/configuration/common/configuration.js'; import { isObject, isUndefined } from '../../../base/common/types.js'; @@ -268,13 +268,13 @@ configurationExtPoint.setHandler((extensions, { added, removed }) => { } for (const key in properties) { const propertyConfiguration = properties[key]; - const message = validateProperty(key, propertyConfiguration); + const message = validateProperty(key, propertyConfiguration, extension.description.identifier.value); if (message) { delete properties[key]; extension.collector.warn(message); continue; } - if (seenProperties.has(key) && !CODE_UNIFICATION_DUPLICATE_SETTINGS.has(key)) { + if (seenProperties.has(key) && !EXTENSION_UNIFICATION_EXTENSION_IDS.has(extension.description.identifier.value.toLowerCase())) { delete properties[key]; extension.collector.warn(nls.localize('config.property.duplicate', "Cannot register '{0}'. This property is already registered.", key)); continue; diff --git a/src/vs/workbench/contrib/relauncher/browser/relauncher.contribution.ts b/src/vs/workbench/contrib/relauncher/browser/relauncher.contribution.ts index 793443c6503..45c92003ce7 100644 --- a/src/vs/workbench/contrib/relauncher/browser/relauncher.contribution.ts +++ b/src/vs/workbench/contrib/relauncher/browser/relauncher.contribution.ts @@ -31,6 +31,7 @@ interface IConfiguration extends IWindowsConfiguration { window: IWindowSettings; workbench?: { enableExperiments?: boolean }; telemetry?: { feedback?: { enabled?: boolean } }; + chat?: { extensionUnification?: { enabled?: boolean } }; _extensionsGallery?: { enablePPE?: boolean }; accessibility?: { verbosity?: { debug?: boolean } }; } @@ -52,7 +53,8 @@ export class SettingsChangeRelauncher extends Disposable implements IWorkbenchCo '_extensionsGallery.enablePPE', 'security.restrictUNCAccess', 'accessibility.verbosity.debug', - 'telemetry.feedback.enabled' + 'telemetry.feedback.enabled', + 'chat.extensionUnification.enabled' ]; private readonly titleBarStyle = new ChangeObserver('string'); @@ -70,6 +72,7 @@ export class SettingsChangeRelauncher extends Disposable implements IWorkbenchCo private readonly restrictUNCAccess = new ChangeObserver('boolean'); private readonly accessibilityVerbosityDebug = new ChangeObserver('boolean'); private readonly telemetryFeedbackEnabled = new ChangeObserver('boolean'); + private readonly extensionUnificationEnabled = new ChangeObserver('boolean'); constructor( @IHostService private readonly hostService: IHostService, @@ -165,6 +168,9 @@ export class SettingsChangeRelauncher extends Disposable implements IWorkbenchCo // Enable Feedback processChanged(this.telemetryFeedbackEnabled.handleChange(config.telemetry?.feedback?.enabled)); + // Extension Unification (only when turning on) + processChanged(this.extensionUnificationEnabled.handleChange(config.chat?.extensionUnification?.enabled) && config.chat?.extensionUnification?.enabled === true); + if (askToRelaunch && changed && this.hostService.hasFocus) { this.doConfirm( isNative ? diff --git a/src/vs/workbench/services/configuration/browser/configuration.ts b/src/vs/workbench/services/configuration/browser/configuration.ts index 8bc22c7a99d..011aa62a24a 100644 --- a/src/vs/workbench/services/configuration/browser/configuration.ts +++ b/src/vs/workbench/services/configuration/browser/configuration.ts @@ -37,8 +37,6 @@ export class DefaultConfiguration extends BaseDefaultConfiguration { private cachedConfigurationDefaultsOverrides: IStringDictionary = {}; private readonly cacheKey: ConfigurationKey = { type: 'defaults', key: 'configurationDefaultsOverrides' }; - private updateCache: boolean = false; - constructor( private readonly configurationCache: IConfigurationCache, environmentService: IBrowserWorkbenchEnvironmentService, @@ -60,7 +58,6 @@ export class DefaultConfiguration extends BaseDefaultConfiguration { } override reload(): ConfigurationModel { - this.updateCache = true; this.cachedConfigurationDefaultsOverrides = {}; this.updateCachedConfigurationDefaultsOverrides(); return super.reload(); @@ -97,9 +94,6 @@ export class DefaultConfiguration extends BaseDefaultConfiguration { } private async updateCachedConfigurationDefaultsOverrides(): Promise { - if (!this.updateCache) { - return; - } const cachedConfigurationDefaultsOverrides: IStringDictionary = {}; const configurationDefaultsOverrides = this.configurationRegistry.getConfigurationDefaultsOverrides(); for (const [key, value] of configurationDefaultsOverrides) { diff --git a/src/vs/workbench/services/extensionManagement/browser/extensionEnablementService.ts b/src/vs/workbench/services/extensionManagement/browser/extensionEnablementService.ts index de611c6184d..796a7ad6f2a 100644 --- a/src/vs/workbench/services/extensionManagement/browser/extensionEnablementService.ts +++ b/src/vs/workbench/services/extensionManagement/browser/extensionEnablementService.ts @@ -38,7 +38,6 @@ const SOURCE = 'IWorkbenchExtensionEnablementService'; type WorkspaceType = { readonly virtual: boolean; readonly trusted: boolean }; const EXTENSION_UNIFICATION_SETTING = 'chat.extensionUnification.enabled'; -const EXTENSION_UNIFICATION_STORAGE_KEY = 'chat.extensionUnification.enabled'; export class ExtensionEnablementService extends Disposable implements IWorkbenchExtensionEnablementService { @@ -105,11 +104,10 @@ export class ExtensionEnablementService extends Disposable implements IWorkbench // Disabling extension unification should immediately disable the unified extension flow // Enabling extension unification will only take effect after restart - this._extensionUnificationEnabled = storageService.getBoolean(EXTENSION_UNIFICATION_STORAGE_KEY, StorageScope.PROFILE, false); + this._extensionUnificationEnabled = this.configurationService.getValue(EXTENSION_UNIFICATION_SETTING); this._register(this.configurationService.onDidChangeConfiguration(e => { if (e.affectsConfiguration(EXTENSION_UNIFICATION_SETTING)) { const extensionUnificationEnabled = this.configurationService.getValue(EXTENSION_UNIFICATION_SETTING); - storageService.store(EXTENSION_UNIFICATION_STORAGE_KEY, extensionUnificationEnabled, StorageScope.PROFILE, StorageTarget.MACHINE); if (!extensionUnificationEnabled) { this._extensionUnificationEnabled = false; this._onEnablementChanged.fire(this.extensionsManager.extensions.filter(ext => unificationExtensions.includes(ext.identifier.id.toLowerCase())));