Update enablement behavior + info (#9758)

This commit is contained in:
christine betts
2025-09-25 21:44:28 -04:00
committed by GitHub
parent 2e4e53c3ee
commit 53434d860a
3 changed files with 73 additions and 16 deletions

View File

@@ -5,12 +5,7 @@
*/
import type { CommandModule } from 'yargs';
import {
loadUserExtensions,
toOutputString,
ExtensionStorage,
} from '../../config/extension.js';
import { ExtensionEnablementManager } from '../../config/extensions/extensionEnablement.js';
import { loadUserExtensions, toOutputString } from '../../config/extension.js';
import { getErrorMessage } from '../../utils/errors.js';
export async function handleList() {
@@ -20,16 +15,9 @@ export async function handleList() {
console.log('No extensions installed.');
return;
}
const manager = new ExtensionEnablementManager(
ExtensionStorage.getUserExtensionsDir(),
);
const cwd = process.cwd();
console.log(
extensions
.map((extension): string => {
const isEnabled = manager.isEnabled(extension.config.name, cwd);
return toOutputString(extension, isEnabled);
})
.map((extension, _): string => toOutputString(extension, process.cwd()))
.join('\n\n'),
);
} catch (error) {

View File

@@ -1235,6 +1235,12 @@ This extension will run the following MCP servers:
describe('disableExtension', () => {
it('should disable an extension at the user scope', () => {
createExtension({
extensionsDir: userExtensionsDir,
name: 'my-extension',
version: '1.0.0',
});
disableExtension('my-extension', SettingScope.User);
expect(
isEnabled({
@@ -1246,6 +1252,12 @@ This extension will run the following MCP servers:
});
it('should disable an extension at the workspace scope', () => {
createExtension({
extensionsDir: userExtensionsDir,
name: 'my-extension',
version: '1.0.0',
});
disableExtension(
'my-extension',
SettingScope.Workspace,
@@ -1268,6 +1280,12 @@ This extension will run the following MCP servers:
});
it('should handle disabling the same extension twice', () => {
createExtension({
extensionsDir: userExtensionsDir,
name: 'my-extension',
version: '1.0.0',
});
disableExtension('my-extension', SettingScope.User);
disableExtension('my-extension', SettingScope.User);
expect(
@@ -1286,6 +1304,12 @@ This extension will run the following MCP servers:
});
it('should log a disable event', () => {
createExtension({
extensionsDir: userExtensionsDir,
name: 'ext1',
version: '1.0.0',
});
disableExtension('ext1', SettingScope.Workspace);
expect(mockLogExtensionDisable).toHaveBeenCalled();

View File

@@ -260,6 +260,32 @@ export function loadExtension(context: LoadExtensionContext): Extension | null {
}
}
export function loadExtensionByName(
name: string,
workspaceDir: string = process.cwd(),
): Extension | null {
const userExtensionsDir = ExtensionStorage.getUserExtensionsDir();
if (!fs.existsSync(userExtensionsDir)) {
return null;
}
for (const subdir of fs.readdirSync(userExtensionsDir)) {
const extensionDir = path.join(userExtensionsDir, subdir);
if (!fs.statSync(extensionDir).isDirectory()) {
continue;
}
const extension = loadExtension({ extensionDir, workspaceDir });
if (
extension &&
extension.config.name.toLowerCase() === name.toLowerCase()
) {
return extension;
}
}
return null;
}
function filterMcpConfig(original: MCPServerConfig): MCPServerConfig {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { trust, ...rest } = original;
@@ -701,9 +727,18 @@ export async function uninstallExtension(
export function toOutputString(
extension: Extension,
isEnabled: boolean,
workspaceDir: string,
): string {
const status = isEnabled ? chalk.green('✓') : chalk.red('✗');
const manager = new ExtensionEnablementManager(
ExtensionStorage.getUserExtensionsDir(),
);
const userEnabled = manager.isEnabled(extension.config.name, os.homedir());
const workspaceEnabled = manager.isEnabled(
extension.config.name,
workspaceDir,
);
const status = workspaceEnabled ? chalk.green('✓') : chalk.red('✗');
let output = `${status} ${extension.config.name} (${extension.config.version})`;
output += `\n Path: ${extension.path}`;
if (extension.installMetadata) {
@@ -715,6 +750,8 @@ export function toOutputString(
output += `\n Release tag: ${extension.installMetadata.releaseTag}`;
}
}
output += `\n Enabled (User): ${userEnabled}`;
output += `\n Enabled (Workspace): ${workspaceEnabled}`;
if (extension.contextFiles.length > 0) {
output += `\n Context files:`;
extension.contextFiles.forEach((contextFile) => {
@@ -745,6 +782,10 @@ export function disableExtension(
if (scope === SettingScope.System || scope === SettingScope.SystemDefaults) {
throw new Error('System and SystemDefaults scopes are not supported.');
}
const extension = loadExtensionByName(name, cwd);
if (!extension) {
throw new Error(`Extension with name ${name} does not exist.`);
}
const manager = new ExtensionEnablementManager(
ExtensionStorage.getUserExtensionsDir(),
@@ -762,6 +803,10 @@ export function enableExtension(
if (scope === SettingScope.System || scope === SettingScope.SystemDefaults) {
throw new Error('System and SystemDefaults scopes are not supported.');
}
const extension = loadExtensionByName(name, cwd);
if (!extension) {
throw new Error(`Extension with name ${name} does not exist.`);
}
const manager = new ExtensionEnablementManager(
ExtensionStorage.getUserExtensionsDir(),
);