diff --git a/packages/cli/src/commands/extensions/list.ts b/packages/cli/src/commands/extensions/list.ts index f6689a3c0c..acfe758890 100644 --- a/packages/cli/src/commands/extensions/list.ts +++ b/packages/cli/src/commands/extensions/list.ts @@ -5,12 +5,16 @@ */ import type { CommandModule } from 'yargs'; -import { loadUserExtensions, toOutputString } from '../../config/extension.js'; +import { loadExtensions, toOutputString } from '../../config/extension.js'; import { getErrorMessage } from '../../utils/errors.js'; +import { ExtensionEnablementManager } from '../../config/extensions/extensionEnablement.js'; export async function handleList() { try { - const extensions = loadUserExtensions(); + const extensions = loadExtensions( + new ExtensionEnablementManager(), + process.cwd(), + ); if (extensions.length === 0) { console.log('No extensions installed.'); return; diff --git a/packages/cli/src/commands/extensions/update.ts b/packages/cli/src/commands/extensions/update.ts index bf28bbc90f..4361474346 100644 --- a/packages/cli/src/commands/extensions/update.ts +++ b/packages/cli/src/commands/extensions/update.ts @@ -8,7 +8,6 @@ import type { CommandModule } from 'yargs'; import { loadExtensions, annotateActiveExtensions, - ExtensionStorage, requestConsentNonInteractive, } from '../../config/extension.js'; import { @@ -33,7 +32,6 @@ const updateOutput = (info: ExtensionUpdateInfo) => export async function handleUpdate(args: UpdateArgs) { const workingDir = process.cwd(); const extensionEnablementManager = new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), // Force enable named extensions, otherwise we will only update the enabled // ones. args.name ? [args.name] : [], diff --git a/packages/cli/src/commands/mcp/list.ts b/packages/cli/src/commands/mcp/list.ts index 252dcfd52b..125fdab41c 100644 --- a/packages/cli/src/commands/mcp/list.ts +++ b/packages/cli/src/commands/mcp/list.ts @@ -10,7 +10,7 @@ import { loadSettings } from '../../config/settings.js'; import type { MCPServerConfig } from '@google/gemini-cli-core'; import { MCPServerStatus, createTransport } from '@google/gemini-cli-core'; import { Client } from '@modelcontextprotocol/sdk/client/index.js'; -import { ExtensionStorage, loadExtensions } from '../../config/extension.js'; +import { loadExtensions } from '../../config/extension.js'; import { ExtensionEnablementManager } from '../../config/extensions/extensionEnablement.js'; const COLOR_GREEN = '\u001b[32m'; @@ -22,9 +22,7 @@ async function getMcpServersFromConfig(): Promise< Record > { const settings = loadSettings(); - const extensions = loadExtensions( - new ExtensionEnablementManager(ExtensionStorage.getUserExtensionsDir()), - ); + const extensions = loadExtensions(new ExtensionEnablementManager()); const mcpServers = { ...(settings.merged.mcpServers || {}) }; for (const extension of extensions) { Object.entries(extension.mcpServers || {}).forEach(([key, server]) => { diff --git a/packages/cli/src/config/config.test.ts b/packages/cli/src/config/config.test.ts index 5312daf62b..15e9fdd24b 100644 --- a/packages/cli/src/config/config.test.ts +++ b/packages/cli/src/config/config.test.ts @@ -23,7 +23,6 @@ import { type CliArgs, } from './config.js'; import type { Settings } from './settings.js'; -import { ExtensionStorage } from './extension.js'; import * as ServerConfig from '@google/gemini-cli-core'; import { isWorkspaceTrusted } from './trustedFolders.js'; import { ExtensionEnablementManager } from './extensions/extensionEnablement.js'; @@ -547,10 +546,7 @@ describe('loadCliConfig', () => { const config = await loadCliConfig( settings, [], - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -597,10 +593,7 @@ describe('loadCliConfig', () => { const config = await loadCliConfig( settings, [], - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -655,10 +648,7 @@ describe('Hierarchical Memory Loading (config.ts) - Placeholder Suite', () => { settings, extensions, - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'session-id', argv, ); @@ -741,10 +731,7 @@ describe('mergeMcpServers', () => { await loadCliConfig( settings, extensions, - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -789,10 +776,7 @@ describe('mergeExcludeTools', () => { const config = await loadCliConfig( settings, extensions, - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -819,10 +803,7 @@ describe('mergeExcludeTools', () => { const config = await loadCliConfig( settings, extensions, - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -857,10 +838,7 @@ describe('mergeExcludeTools', () => { const config = await loadCliConfig( settings, extensions, - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -879,10 +857,7 @@ describe('mergeExcludeTools', () => { const config = await loadCliConfig( settings, extensions, - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -898,10 +873,7 @@ describe('mergeExcludeTools', () => { const config = await loadCliConfig( settings, extensions, - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -916,10 +888,7 @@ describe('mergeExcludeTools', () => { const config = await loadCliConfig( settings, extensions, - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -946,10 +915,7 @@ describe('mergeExcludeTools', () => { const config = await loadCliConfig( settings, extensions, - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -977,10 +943,7 @@ describe('mergeExcludeTools', () => { await loadCliConfig( settings, extensions, - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -1012,10 +975,7 @@ describe('Approval mode tool exclusion logic', () => { const config = await loadCliConfig( settings, extensions, - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -1042,10 +1002,7 @@ describe('Approval mode tool exclusion logic', () => { const config = await loadCliConfig( settings, extensions, - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -1072,10 +1029,7 @@ describe('Approval mode tool exclusion logic', () => { const config = await loadCliConfig( settings, extensions, - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -1102,10 +1056,7 @@ describe('Approval mode tool exclusion logic', () => { const config = await loadCliConfig( settings, extensions, - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -1125,10 +1076,7 @@ describe('Approval mode tool exclusion logic', () => { const config = await loadCliConfig( settings, extensions, - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -1159,10 +1107,7 @@ describe('Approval mode tool exclusion logic', () => { const config = await loadCliConfig( settings, extensions, - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -1190,10 +1135,7 @@ describe('Approval mode tool exclusion logic', () => { const config = await loadCliConfig( settings, extensions, - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -1220,10 +1162,7 @@ describe('Approval mode tool exclusion logic', () => { loadCliConfig( settings, extensions, - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - invalidArgv.extensions, - ), + new ExtensionEnablementManager(invalidArgv.extensions), 'test-session', invalidArgv as CliArgs, ), @@ -1262,10 +1201,7 @@ describe('loadCliConfig with allowed-mcp-server-names', () => { const config = await loadCliConfig( baseSettings, [], - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -1283,10 +1219,7 @@ describe('loadCliConfig with allowed-mcp-server-names', () => { const config = await loadCliConfig( baseSettings, [], - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -1308,10 +1241,7 @@ describe('loadCliConfig with allowed-mcp-server-names', () => { const config = await loadCliConfig( baseSettings, [], - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -1334,10 +1264,7 @@ describe('loadCliConfig with allowed-mcp-server-names', () => { const config = await loadCliConfig( baseSettings, [], - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -1352,10 +1279,7 @@ describe('loadCliConfig with allowed-mcp-server-names', () => { const config = await loadCliConfig( baseSettings, [], - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -1372,10 +1296,7 @@ describe('loadCliConfig with allowed-mcp-server-names', () => { const config = await loadCliConfig( settings, [], - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -1395,10 +1316,7 @@ describe('loadCliConfig with allowed-mcp-server-names', () => { const config = await loadCliConfig( settings, [], - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -1420,10 +1338,7 @@ describe('loadCliConfig with allowed-mcp-server-names', () => { const config = await loadCliConfig( settings, [], - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -1450,10 +1365,7 @@ describe('loadCliConfig with allowed-mcp-server-names', () => { const config = await loadCliConfig( settings, [], - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -1482,10 +1394,7 @@ describe('loadCliConfig with allowed-mcp-server-names', () => { const config = await loadCliConfig( settings, [], - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -1521,10 +1430,7 @@ describe('loadCliConfig extensions', () => { const config = await loadCliConfig( settings, mockExtensions, - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -1541,10 +1447,7 @@ describe('loadCliConfig extensions', () => { const config = await loadCliConfig( settings, mockExtensions, - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -1563,10 +1466,7 @@ describe('loadCliConfig model selection', () => { }, }, [], - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -1582,10 +1482,7 @@ describe('loadCliConfig model selection', () => { // No model set. }, [], - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -1603,10 +1500,7 @@ describe('loadCliConfig model selection', () => { }, }, [], - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -1622,10 +1516,7 @@ describe('loadCliConfig model selection', () => { // No model provided via settings. }, [], - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -1645,10 +1536,7 @@ describe('loadCliConfig model selection with model router', () => { }, }, [], - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -1666,10 +1554,7 @@ describe('loadCliConfig model selection with model router', () => { }, }, [], - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -1687,10 +1572,7 @@ describe('loadCliConfig model selection with model router', () => { }, }, [], - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -1711,10 +1593,7 @@ describe('loadCliConfig model selection with model router', () => { }, }, [], - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -1733,10 +1612,7 @@ describe('loadCliConfig model selection with model router', () => { }, }, [], - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -1773,10 +1649,7 @@ describe('loadCliConfig folderTrust', () => { const config = await loadCliConfig( settings, [], - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -1796,10 +1669,7 @@ describe('loadCliConfig folderTrust', () => { const config = await loadCliConfig( settings, [], - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -1813,10 +1683,7 @@ describe('loadCliConfig folderTrust', () => { const config = await loadCliConfig( settings, [], - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -1863,10 +1730,7 @@ describe('loadCliConfig with includeDirectories', () => { const config = await loadCliConfig( settings, [], - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -1915,10 +1779,7 @@ describe('loadCliConfig chatCompression', () => { const config = await loadCliConfig( settings, [], - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -1934,10 +1795,7 @@ describe('loadCliConfig chatCompression', () => { const config = await loadCliConfig( settings, [], - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -1967,10 +1825,7 @@ describe('loadCliConfig useRipgrep', () => { const config = await loadCliConfig( settings, [], - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -1984,10 +1839,7 @@ describe('loadCliConfig useRipgrep', () => { const config = await loadCliConfig( settings, [], - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -2001,10 +1853,7 @@ describe('loadCliConfig useRipgrep', () => { const config = await loadCliConfig( settings, [], - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -2019,10 +1868,7 @@ describe('loadCliConfig useRipgrep', () => { const config = await loadCliConfig( settings, [], - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -2036,10 +1882,7 @@ describe('loadCliConfig useRipgrep', () => { const config = await loadCliConfig( settings, [], - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -2053,10 +1896,7 @@ describe('loadCliConfig useRipgrep', () => { const config = await loadCliConfig( settings, [], - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -2089,10 +1929,7 @@ describe('screenReader configuration', () => { const config = await loadCliConfig( settings, [], - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -2108,10 +1945,7 @@ describe('screenReader configuration', () => { const config = await loadCliConfig( settings, [], - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -2127,10 +1961,7 @@ describe('screenReader configuration', () => { const config = await loadCliConfig( settings, [], - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -2144,10 +1975,7 @@ describe('screenReader configuration', () => { const config = await loadCliConfig( settings, [], - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -2184,10 +2012,7 @@ describe('loadCliConfig tool exclusions', () => { const config = await loadCliConfig( {}, [], - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -2203,10 +2028,7 @@ describe('loadCliConfig tool exclusions', () => { const config = await loadCliConfig( {}, [], - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -2222,10 +2044,7 @@ describe('loadCliConfig tool exclusions', () => { const config = await loadCliConfig( {}, [], - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -2241,10 +2060,7 @@ describe('loadCliConfig tool exclusions', () => { const config = await loadCliConfig( {}, [], - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -2267,10 +2083,7 @@ describe('loadCliConfig tool exclusions', () => { const config = await loadCliConfig( {}, [], - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -2291,10 +2104,7 @@ describe('loadCliConfig tool exclusions', () => { const config = await loadCliConfig( {}, [], - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -2315,10 +2125,7 @@ describe('loadCliConfig tool exclusions', () => { const config = await loadCliConfig( {}, [], - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -2351,10 +2158,7 @@ describe('loadCliConfig interactive', () => { const config = await loadCliConfig( {}, [], - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -2368,10 +2172,7 @@ describe('loadCliConfig interactive', () => { const config = await loadCliConfig( {}, [], - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -2385,10 +2186,7 @@ describe('loadCliConfig interactive', () => { const config = await loadCliConfig( {}, [], - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -2402,10 +2200,7 @@ describe('loadCliConfig interactive', () => { const config = await loadCliConfig( {}, [], - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -2419,10 +2214,7 @@ describe('loadCliConfig interactive', () => { const config = await loadCliConfig( {}, [], - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -2443,10 +2235,7 @@ describe('loadCliConfig interactive', () => { const config = await loadCliConfig( {}, [], - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -2463,10 +2252,7 @@ describe('loadCliConfig interactive', () => { const config = await loadCliConfig( {}, [], - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -2482,10 +2268,7 @@ describe('loadCliConfig interactive', () => { const config = await loadCliConfig( {}, [], - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -2512,10 +2295,7 @@ describe('loadCliConfig interactive', () => { const config = await loadCliConfig( {}, [], - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -2531,10 +2311,7 @@ describe('loadCliConfig interactive', () => { const config = await loadCliConfig( {}, [], - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -2559,10 +2336,7 @@ describe('loadCliConfig interactive', () => { const config = await loadCliConfig( {}, [], - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -2578,10 +2352,7 @@ describe('loadCliConfig interactive', () => { const config = await loadCliConfig( {}, [], - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -2615,10 +2386,7 @@ describe('loadCliConfig approval mode', () => { const config = await loadCliConfig( {}, [], - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -2631,10 +2399,7 @@ describe('loadCliConfig approval mode', () => { const config = await loadCliConfig( {}, [], - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -2647,10 +2412,7 @@ describe('loadCliConfig approval mode', () => { const config = await loadCliConfig( {}, [], - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -2663,10 +2425,7 @@ describe('loadCliConfig approval mode', () => { const config = await loadCliConfig( {}, [], - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -2679,10 +2438,7 @@ describe('loadCliConfig approval mode', () => { const config = await loadCliConfig( {}, [], - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -2695,10 +2451,7 @@ describe('loadCliConfig approval mode', () => { const config = await loadCliConfig( {}, [], - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -2715,10 +2468,7 @@ describe('loadCliConfig approval mode', () => { const config = await loadCliConfig( {}, [], - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -2731,10 +2481,7 @@ describe('loadCliConfig approval mode', () => { const config = await loadCliConfig( {}, [], - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -2756,10 +2503,7 @@ describe('loadCliConfig approval mode', () => { const config = await loadCliConfig( {}, [], - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -2772,10 +2516,7 @@ describe('loadCliConfig approval mode', () => { const config = await loadCliConfig( {}, [], - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -2788,10 +2529,7 @@ describe('loadCliConfig approval mode', () => { const config = await loadCliConfig( {}, [], - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -2804,10 +2542,7 @@ describe('loadCliConfig approval mode', () => { const config = await loadCliConfig( {}, [], - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -2891,10 +2626,7 @@ describe('loadCliConfig fileFiltering', () => { const config = await loadCliConfig( settings, [], - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -2910,10 +2642,7 @@ describe('Output format', () => { const config = await loadCliConfig( {}, [], - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -2926,10 +2655,7 @@ describe('Output format', () => { const config = await loadCliConfig( { output: { format: OutputFormat.JSON } }, [], - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -2942,10 +2668,7 @@ describe('Output format', () => { const config = await loadCliConfig( { output: { format: OutputFormat.JSON } }, [], - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -2958,10 +2681,7 @@ describe('Output format', () => { const config = await loadCliConfig( {}, [], - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -3061,10 +2781,7 @@ describe('Telemetry configuration via environment variables', () => { const config = await loadCliConfig( settings, [], - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -3081,10 +2798,7 @@ describe('Telemetry configuration via environment variables', () => { const config = await loadCliConfig( settings, [], - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -3102,10 +2816,7 @@ describe('Telemetry configuration via environment variables', () => { loadCliConfig( settings, [], - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ), @@ -3126,10 +2837,7 @@ describe('Telemetry configuration via environment variables', () => { const config = await loadCliConfig( settings, [], - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -3144,10 +2852,7 @@ describe('Telemetry configuration via environment variables', () => { const config = await loadCliConfig( settings, [], - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -3162,10 +2867,7 @@ describe('Telemetry configuration via environment variables', () => { const config = await loadCliConfig( settings, [], - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -3182,10 +2884,7 @@ describe('Telemetry configuration via environment variables', () => { const config = await loadCliConfig( settings, [], - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -3200,10 +2899,7 @@ describe('Telemetry configuration via environment variables', () => { const config = await loadCliConfig( settings, [], - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -3218,10 +2914,7 @@ describe('Telemetry configuration via environment variables', () => { const config = await loadCliConfig( settings, [], - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -3238,10 +2931,7 @@ describe('Telemetry configuration via environment variables', () => { const config = await loadCliConfig( settings, [], - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -3255,10 +2945,7 @@ describe('Telemetry configuration via environment variables', () => { const config = await loadCliConfig( {}, [], - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -3272,10 +2959,7 @@ describe('Telemetry configuration via environment variables', () => { const config = await loadCliConfig( { telemetry: { enabled: true } }, [], - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -3289,10 +2973,7 @@ describe('Telemetry configuration via environment variables', () => { const config = await loadCliConfig( {}, [], - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); @@ -3306,10 +2987,7 @@ describe('Telemetry configuration via environment variables', () => { const config = await loadCliConfig( { telemetry: { logPrompts: true } }, [], - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - argv.extensions, - ), + new ExtensionEnablementManager(argv.extensions), 'test-session', argv, ); diff --git a/packages/cli/src/config/extension.test.ts b/packages/cli/src/config/extension.test.ts index 033fa872ae..d1f80c6c30 100644 --- a/packages/cli/src/config/extension.test.ts +++ b/packages/cli/src/config/extension.test.ts @@ -21,7 +21,6 @@ import { loadExtension, loadExtensionConfig, loadExtensions, - performWorkspaceExtensionMigration, uninstallExtension, } from './extension.js'; import { @@ -155,9 +154,7 @@ describe('extension tests', () => { version: '1.0.0', }); - const extensions = loadExtensions( - new ExtensionEnablementManager(ExtensionStorage.getUserExtensionsDir()), - ); + const extensions = loadExtensions(new ExtensionEnablementManager()); expect(extensions).toHaveLength(1); expect(extensions[0].path).toBe(extensionDir); expect(extensions[0].name).toBe('test-extension'); @@ -176,9 +173,7 @@ describe('extension tests', () => { version: '2.0.0', }); - const extensions = loadExtensions( - new ExtensionEnablementManager(ExtensionStorage.getUserExtensionsDir()), - ); + const extensions = loadExtensions(new ExtensionEnablementManager()); expect(extensions).toHaveLength(2); const ext1 = extensions.find((e) => e.name === 'ext1'); @@ -198,9 +193,7 @@ describe('extension tests', () => { contextFileName: 'my-context-file.md', }); - const extensions = loadExtensions( - new ExtensionEnablementManager(ExtensionStorage.getUserExtensionsDir()), - ); + const extensions = loadExtensions(new ExtensionEnablementManager()); expect(extensions).toHaveLength(1); const ext1 = extensions.find((e) => e.name === 'ext1'); @@ -225,9 +218,7 @@ describe('extension tests', () => { SettingScope.User, tempWorkspaceDir, ); - const manager = new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - ); + const manager = new ExtensionEnablementManager(); const extensions = loadExtensions(manager); const activeExtensions = annotateActiveExtensions( extensions, @@ -252,9 +243,7 @@ describe('extension tests', () => { }, }); - const extensions = loadExtensions( - new ExtensionEnablementManager(ExtensionStorage.getUserExtensionsDir()), - ); + const extensions = loadExtensions(new ExtensionEnablementManager()); expect(extensions).toHaveLength(1); const expectedCwd = path.join( userExtensionsDir, @@ -282,9 +271,7 @@ describe('extension tests', () => { ); expect(extensionName).toEqual('my-linked-extension'); - const extensions = loadExtensions( - new ExtensionEnablementManager(ExtensionStorage.getUserExtensionsDir()), - ); + const extensions = loadExtensions(new ExtensionEnablementManager()); expect(extensions).toHaveLength(1); const linkedExt = extensions[0]; @@ -333,11 +320,7 @@ describe('extension tests', () => { }; fs.writeFileSync(configPath, JSON.stringify(extensionConfig)); - const extensions = loadExtensions( - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - ), - ); + const extensions = loadExtensions(new ExtensionEnablementManager()); expect(extensions).toHaveLength(1); const extension = extensions[0]; @@ -388,9 +371,7 @@ describe('extension tests', () => { JSON.stringify(extensionConfig), ); - const extensions = loadExtensions( - new ExtensionEnablementManager(ExtensionStorage.getUserExtensionsDir()), - ); + const extensions = loadExtensions(new ExtensionEnablementManager()); expect(extensions).toHaveLength(1); const extension = extensions[0]; @@ -418,9 +399,7 @@ describe('extension tests', () => { const badConfigPath = path.join(badExtDir, EXTENSIONS_CONFIG_FILENAME); fs.writeFileSync(badConfigPath, '{ "name": "bad-ext"'); // Malformed - const extensions = loadExtensions( - new ExtensionEnablementManager(ExtensionStorage.getUserExtensionsDir()), - ); + const extensions = loadExtensions(new ExtensionEnablementManager()); expect(extensions).toHaveLength(1); expect(extensions[0].name).toBe('good-ext'); @@ -452,9 +431,7 @@ describe('extension tests', () => { const badConfigPath = path.join(badExtDir, EXTENSIONS_CONFIG_FILENAME); fs.writeFileSync(badConfigPath, JSON.stringify({ version: '1.0.0' })); - const extensions = loadExtensions( - new ExtensionEnablementManager(ExtensionStorage.getUserExtensionsDir()), - ); + const extensions = loadExtensions(new ExtensionEnablementManager()); expect(extensions).toHaveLength(1); expect(extensions[0].name).toBe('good-ext'); @@ -482,9 +459,7 @@ describe('extension tests', () => { }, }); - const extensions = loadExtensions( - new ExtensionEnablementManager(ExtensionStorage.getUserExtensionsDir()), - ); + const extensions = loadExtensions(new ExtensionEnablementManager()); expect(extensions).toHaveLength(1); expect(extensions[0].mcpServers?.['test-server'].trust).toBeUndefined(); }); @@ -698,7 +673,7 @@ describe('extension tests', () => { const activeExtensions = annotateActiveExtensions( extensions, '/path/to/workspace', - new ExtensionEnablementManager(ExtensionStorage.getUserExtensionsDir()), + new ExtensionEnablementManager(), ); expect(activeExtensions).toHaveLength(3); expect(activeExtensions.every((e) => e.isActive)).toBe(true); @@ -708,10 +683,7 @@ describe('extension tests', () => { const activeExtensions = annotateActiveExtensions( extensions, '/path/to/workspace', - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - ['ext1', 'ext3'], - ), + new ExtensionEnablementManager(['ext1', 'ext3']), ); expect(activeExtensions).toHaveLength(3); expect(activeExtensions.find((e) => e.name === 'ext1')?.isActive).toBe( @@ -729,10 +701,7 @@ describe('extension tests', () => { const activeExtensions = annotateActiveExtensions( extensions, '/path/to/workspace', - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - ['none'], - ), + new ExtensionEnablementManager(['none']), ); expect(activeExtensions).toHaveLength(3); expect(activeExtensions.every((e) => !e.isActive)).toBe(true); @@ -742,10 +711,7 @@ describe('extension tests', () => { const activeExtensions = annotateActiveExtensions( extensions, '/path/to/workspace', - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - ['EXT1'], - ), + new ExtensionEnablementManager(['EXT1']), ); expect(activeExtensions.find((e) => e.name === 'ext1')?.isActive).toBe( true, @@ -759,10 +725,7 @@ describe('extension tests', () => { annotateActiveExtensions( extensions, '/path/to/workspace', - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - ['ext4'], - ), + new ExtensionEnablementManager(['ext4']), ); expect(consoleSpy).toHaveBeenCalledWith('Extension not found: ext4'); consoleSpy.mockRestore(); @@ -773,9 +736,7 @@ describe('extension tests', () => { const activeExtensions = annotateActiveExtensions( extensions, tempHomeDir, - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - ), + new ExtensionEnablementManager(), ); expect( activeExtensions.every( @@ -797,9 +758,7 @@ describe('extension tests', () => { const activeExtensions = annotateActiveExtensions( extensionsWithAutoUpdate, tempHomeDir, - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - ), + new ExtensionEnablementManager(), ); expect( activeExtensions.every((e) => e.installMetadata?.autoUpdate === true), @@ -843,9 +802,7 @@ describe('extension tests', () => { const activeExtensions = annotateActiveExtensions( extensionsWithAutoUpdate, tempHomeDir, - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - ), + new ExtensionEnablementManager(), ); expect( activeExtensions.find((e) => e.name === 'ext1')?.installMetadata @@ -1073,9 +1030,7 @@ describe('extension tests', () => { }); it(`should ${isUpdate ? 'not ' : ''} alter the extension enablement configuration`, async () => { - const enablementManager = new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - ); + const enablementManager = new ExtensionEnablementManager(); enablementManager.enable('my-local-extension', true, '/some/scope'); await installOrUpdateExtension( @@ -1457,13 +1412,7 @@ This extension will run the following MCP servers: await uninstallExtension('my-local-extension', false); expect(fs.existsSync(sourceExtDir)).toBe(false); - expect( - loadExtensions( - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - ), - ), - ).toHaveLength(1); + expect(loadExtensions(new ExtensionEnablementManager())).toHaveLength(1); expect(fs.existsSync(otherExtDir)).toBe(true); }); @@ -1501,9 +1450,7 @@ This extension will run the following MCP servers: name: 'test-extension', version: '1.0.0', }); - const enablementManager = new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - ); + const enablementManager = new ExtensionEnablementManager(); enablementManager.enable('test-extension', true, '/some/scope'); await uninstallExtension('test-extension', isUpdate); @@ -1557,182 +1504,6 @@ This extension will run the following MCP servers: }); }); - describe('performWorkspaceExtensionMigration', () => { - let workspaceExtensionsDir: string; - - beforeEach(() => { - workspaceExtensionsDir = path.join( - tempWorkspaceDir, - EXTENSIONS_DIRECTORY_NAME, - ); - fs.mkdirSync(workspaceExtensionsDir, { recursive: true }); - }); - - afterEach(() => { - fs.rmSync(workspaceExtensionsDir, { recursive: true, force: true }); - }); - - describe('folder trust', () => { - it('refuses to install extensions from untrusted folders', async () => { - vi.mocked(isWorkspaceTrusted).mockReturnValue({ - isTrusted: false, - source: undefined, - }); - const ext1Path = createExtension({ - extensionsDir: workspaceExtensionsDir, - name: 'ext1', - version: '1.0.0', - }); - - const failed = await performWorkspaceExtensionMigration( - [ - loadExtension({ - extensionDir: ext1Path, - workspaceDir: tempWorkspaceDir, - })!, - ], - async () => true, - ); - - expect(failed).toEqual(['ext1']); - }); - - it('does not copy extensions to the user dir', async () => { - vi.mocked(isWorkspaceTrusted).mockReturnValue({ - isTrusted: false, - source: undefined, - }); - const ext1Path = createExtension({ - extensionsDir: workspaceExtensionsDir, - name: 'ext1', - version: '1.0.0', - }); - - await performWorkspaceExtensionMigration( - [ - loadExtension({ - extensionDir: ext1Path, - workspaceDir: tempWorkspaceDir, - })!, - ], - async (_) => true, - ); - - const userExtensionsDir = path.join( - tempHomeDir, - GEMINI_DIR, - 'extensions', - ); - expect(fs.readdirSync(userExtensionsDir).length).toBe(0); - }); - - it('does not load any extensions in the workspace config', async () => { - vi.mocked(isWorkspaceTrusted).mockReturnValue({ - isTrusted: false, - source: undefined, - }); - const ext1Path = createExtension({ - extensionsDir: workspaceExtensionsDir, - name: 'ext1', - version: '1.0.0', - }); - - await performWorkspaceExtensionMigration( - [ - loadExtension({ - extensionDir: ext1Path, - workspaceDir: tempWorkspaceDir, - })!, - ], - async (_) => true, - ); - const extensions = loadExtensions( - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - ), - ); - - expect(extensions).toEqual([]); - }); - }); - - it('should install the extensions in the user directory', async () => { - const ext1Path = createExtension({ - extensionsDir: workspaceExtensionsDir, - name: 'ext1', - version: '1.0.0', - }); - const ext2Path = createExtension({ - extensionsDir: workspaceExtensionsDir, - name: 'ext2', - version: '1.0.0', - }); - const extensionsToMigrate: GeminiCLIExtension[] = [ - loadExtension({ - extensionDir: ext1Path, - workspaceDir: tempWorkspaceDir, - })!, - loadExtension({ - extensionDir: ext2Path, - workspaceDir: tempWorkspaceDir, - })!, - ]; - const failed = await performWorkspaceExtensionMigration( - extensionsToMigrate, - async (_) => true, - ); - - expect(failed).toEqual([]); - - const userExtensionsDir = path.join( - tempHomeDir, - GEMINI_DIR, - 'extensions', - ); - const userExt1Path = path.join(userExtensionsDir, 'ext1'); - const extensions = loadExtensions( - new ExtensionEnablementManager(ExtensionStorage.getUserExtensionsDir()), - ); - - expect(extensions).toHaveLength(2); - const metadataPath = path.join(userExt1Path, INSTALL_METADATA_FILENAME); - expect(fs.existsSync(metadataPath)).toBe(true); - const metadata = JSON.parse(fs.readFileSync(metadataPath, 'utf-8')); - expect(metadata).toEqual({ - source: ext1Path, - type: 'local', - }); - }); - - it('should return the names of failed installations', async () => { - const ext1Path = createExtension({ - extensionsDir: workspaceExtensionsDir, - name: 'ext1', - version: '1.0.0', - }); - - const extensions: GeminiCLIExtension[] = [ - loadExtension({ - extensionDir: ext1Path, - workspaceDir: tempWorkspaceDir, - })!, - { - path: '/ext/path/1', - name: 'ext2', - version: '1.0.0', - contextFiles: [], - isActive: true, - }, - ]; - - const failed = await performWorkspaceExtensionMigration( - extensions, - async (_) => true, - ); - expect(failed).toEqual(['ext2']); - }); - }); - describe('disableExtension', () => { it('should disable an extension at the user scope', () => { createExtension({ @@ -1745,7 +1516,6 @@ This extension will run the following MCP servers: expect( isEnabled({ name: 'my-extension', - configDir: userExtensionsDir, enabledForPath: tempWorkspaceDir, }), ).toBe(false); @@ -1766,14 +1536,12 @@ This extension will run the following MCP servers: expect( isEnabled({ name: 'my-extension', - configDir: userExtensionsDir, enabledForPath: tempHomeDir, }), ).toBe(true); expect( isEnabled({ name: 'my-extension', - configDir: userExtensionsDir, enabledForPath: tempWorkspaceDir, }), ).toBe(false); @@ -1791,7 +1559,6 @@ This extension will run the following MCP servers: expect( isEnabled({ name: 'my-extension', - configDir: userExtensionsDir, enabledForPath: tempWorkspaceDir, }), ).toBe(false); @@ -1826,9 +1593,7 @@ This extension will run the following MCP servers: }); const getActiveExtensions = (): GeminiCLIExtension[] => { - const manager = new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - ); + const manager = new ExtensionEnablementManager(); const extensions = loadExtensions(manager); const activeExtensions = annotateActiveExtensions( extensions, @@ -1888,11 +1653,7 @@ This extension will run the following MCP servers: }); }); -function isEnabled(options: { - name: string; - configDir: string; - enabledForPath: string; -}) { - const manager = new ExtensionEnablementManager(options.configDir); +function isEnabled(options: { name: string; enabledForPath: string }) { + const manager = new ExtensionEnablementManager(); return manager.isEnabled(options.name, options.enabledForPath); } diff --git a/packages/cli/src/config/extension.ts b/packages/cli/src/config/extension.ts index 8557341be1..d102edfa9e 100644 --- a/packages/cli/src/config/extension.ts +++ b/packages/cli/src/config/extension.ts @@ -104,16 +104,6 @@ export class ExtensionStorage { } } -export function getWorkspaceExtensions( - workspaceDir: string, -): GeminiCLIExtension[] { - // If the workspace dir is the user extensions dir, there are no workspace extensions. - if (path.resolve(workspaceDir) === path.resolve(os.homedir())) { - return []; - } - return loadExtensionsFromDir(workspaceDir); -} - export async function copyExtension( source: string, destination: string, @@ -121,26 +111,6 @@ export async function copyExtension( await fs.promises.cp(source, destination, { recursive: true }); } -export async function performWorkspaceExtensionMigration( - extensions: GeminiCLIExtension[], - requestConsent: (consent: string) => Promise, -): Promise { - const failedInstallNames: string[] = []; - - for (const extension of extensions) { - try { - const installMetadata: ExtensionInstallMetadata = { - source: extension.path, - type: 'local', - }; - await installOrUpdateExtension(installMetadata, requestConsent); - } catch (_) { - failedInstallNames.push(extension.name); - } - } - return failedInstallNames; -} - function getTelemetryConfig(cwd: string) { const settings = loadSettings(cwd); const config = new Config({ @@ -159,20 +129,27 @@ export function loadExtensions( extensionEnablementManager: ExtensionEnablementManager, workspaceDir: string = process.cwd(), ): GeminiCLIExtension[] { - const settings = loadSettings(workspaceDir).merged; - const allExtensions = [...loadUserExtensions()]; + const extensionsDir = ExtensionStorage.getUserExtensionsDir(); + if (!fs.existsSync(extensionsDir)) { + return []; + } - if ( - isWorkspaceTrusted(settings).isTrusted && - // Default management setting to true - !(settings.experimental?.extensionManagement ?? true) - ) { - allExtensions.push(...getWorkspaceExtensions(workspaceDir)); + const extensions: GeminiCLIExtension[] = []; + for (const subdir of fs.readdirSync(extensionsDir)) { + const extensionDir = path.join(extensionsDir, subdir); + + const extension = loadExtension({ + extensionDir, + workspaceDir, + }); + if (extension != null) { + extensions.push(extension); + } } const uniqueExtensions = new Map(); - for (const extension of allExtensions) { + for (const extension of extensions) { if ( !uniqueExtensions.has(extension.name) && extensionEnablementManager.isEnabled(extension.name, workspaceDir) @@ -184,38 +161,6 @@ export function loadExtensions( return Array.from(uniqueExtensions.values()); } -export function loadUserExtensions(): GeminiCLIExtension[] { - const userExtensions = loadExtensionsFromDir(os.homedir()); - - const uniqueExtensions = new Map(); - for (const extension of userExtensions) { - if (!uniqueExtensions.has(extension.name)) { - uniqueExtensions.set(extension.name, extension); - } - } - - return Array.from(uniqueExtensions.values()); -} - -export function loadExtensionsFromDir(dir: string): GeminiCLIExtension[] { - const storage = new Storage(dir); - const extensionsDir = storage.getExtensionsDir(); - if (!fs.existsSync(extensionsDir)) { - return []; - } - - const extensions: GeminiCLIExtension[] = []; - for (const subdir of fs.readdirSync(extensionsDir)) { - const extensionDir = path.join(extensionsDir, subdir); - - const extension = loadExtension({ extensionDir, workspaceDir: dir }); - if (extension != null) { - extensions.push(extension); - } - } - return extensions; -} - export function loadExtension( context: LoadExtensionContext, ): GeminiCLIExtension | null { @@ -538,7 +483,10 @@ export async function installOrUpdateExtension( const newExtensionName = newExtensionConfig.name; if (!isUpdate) { - const installedExtensions = loadUserExtensions(); + const installedExtensions = loadExtensions( + new ExtensionEnablementManager(), + cwd, + ); if ( installedExtensions.some( (installed) => installed.name === newExtensionName, @@ -762,7 +710,10 @@ export async function uninstallExtension( isUpdate: boolean, cwd: string = process.cwd(), ): Promise { - const installedExtensions = loadUserExtensions(); + const installedExtensions = loadExtensions( + new ExtensionEnablementManager(), + cwd, + ); const extensionName = installedExtensions.find( (installed) => installed.name.toLowerCase() === extensionIdentifier.toLowerCase() || @@ -783,10 +734,7 @@ export async function uninstallExtension( // uninstalls related to updates. if (isUpdate) return; - const manager = new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - [extensionName], - ); + const manager = new ExtensionEnablementManager([extensionName]); manager.remove(extensionName); const telemetryConfig = getTelemetryConfig(cwd); @@ -800,9 +748,7 @@ export function toOutputString( extension: GeminiCLIExtension, workspaceDir: string, ): string { - const manager = new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - ); + const manager = new ExtensionEnablementManager(); const userEnabled = manager.isEnabled(extension.name, os.homedir()); const workspaceEnabled = manager.isEnabled(extension.name, workspaceDir); @@ -855,10 +801,7 @@ export function disableExtension( throw new Error(`Extension with name ${name} does not exist.`); } - const manager = new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - [name], - ); + const manager = new ExtensionEnablementManager([name]); const scopePath = scope === SettingScope.Workspace ? cwd : os.homedir(); manager.disable(name, true, scopePath); logExtensionDisable(config, new ExtensionDisableEvent(name, scope)); @@ -876,9 +819,7 @@ export function enableExtension( if (!extension) { throw new Error(`Extension with name ${name} does not exist.`); } - const manager = new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - ); + const manager = new ExtensionEnablementManager(); const scopePath = scope === SettingScope.Workspace ? cwd : os.homedir(); manager.enable(name, true, scopePath); const config = getTelemetryConfig(cwd); diff --git a/packages/cli/src/config/extensions/extensionEnablement.test.ts b/packages/cli/src/config/extensions/extensionEnablement.test.ts index 6887c73dc6..c42374acac 100644 --- a/packages/cli/src/config/extensions/extensionEnablement.test.ts +++ b/packages/cli/src/config/extensions/extensionEnablement.test.ts @@ -6,12 +6,20 @@ import * as path from 'node:path'; import fs from 'node:fs'; -import os from 'node:os'; -import { afterEach, beforeEach, describe, expect, it } from 'vitest'; +import * as os from 'node:os'; +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; import { ExtensionEnablementManager, Override } from './extensionEnablement.js'; import { GEMINI_DIR, type GeminiCLIExtension } from '@google/gemini-cli-core'; +vi.mock('os', async (importOriginal) => { + const mockedOs = await importOriginal(); + return { + ...mockedOs, + homedir: vi.fn(), + }; +}); + // Helper to create a temporary directory for testing function createTestDir() { const dirPath = fs.mkdtempSync(path.join(os.tmpdir(), 'gemini-test-')); @@ -22,14 +30,13 @@ function createTestDir() { } let testDir: { path: string; cleanup: () => void }; -let configDir: string; let manager: ExtensionEnablementManager; describe('ExtensionEnablementManager', () => { beforeEach(() => { testDir = createTestDir(); - configDir = path.join(testDir.path, GEMINI_DIR); - manager = new ExtensionEnablementManager(configDir); + vi.mocked(os.homedir).mockReturnValue(path.join(testDir.path, GEMINI_DIR)); + manager = new ExtensionEnablementManager(); }); afterEach(() => { @@ -230,7 +237,7 @@ describe('ExtensionEnablementManager', () => { describe('extension overrides (-e )', () => { beforeEach(() => { - manager = new ExtensionEnablementManager(configDir, ['ext-test']); + manager = new ExtensionEnablementManager(['ext-test']); }); it('can enable extensions, case-insensitive', () => { @@ -238,29 +245,29 @@ describe('ExtensionEnablementManager', () => { expect(manager.isEnabled('ext-test', '/')).toBe(true); expect(manager.isEnabled('Ext-Test', '/')).toBe(true); // Double check that it would have been disabled otherwise - expect( - new ExtensionEnablementManager(configDir).isEnabled('ext-test', '/'), - ).toBe(false); + expect(new ExtensionEnablementManager().isEnabled('ext-test', '/')).toBe( + false, + ); }); it('disable all other extensions', () => { - manager = new ExtensionEnablementManager(configDir, ['ext-test']); + manager = new ExtensionEnablementManager(['ext-test']); manager.enable('ext-test-2', true, '/'); expect(manager.isEnabled('ext-test-2', '/')).toBe(false); // Double check that it would have been enabled otherwise expect( - new ExtensionEnablementManager(configDir).isEnabled('ext-test-2', '/'), + new ExtensionEnablementManager().isEnabled('ext-test-2', '/'), ).toBe(true); }); it('none disables all extensions', () => { - manager = new ExtensionEnablementManager(configDir, ['none']); + manager = new ExtensionEnablementManager(['none']); manager.enable('ext-test', true, '/'); expect(manager.isEnabled('ext-test', '/path/to/dir')).toBe(false); // Double check that it would have been enabled otherwise - expect( - new ExtensionEnablementManager(configDir).isEnabled('ext-test', '/'), - ).toBe(true); + expect(new ExtensionEnablementManager().isEnabled('ext-test', '/')).toBe( + true, + ); }); }); @@ -276,16 +283,13 @@ describe('ExtensionEnablementManager', () => { }); it('should not log an error if enabledExtensionNamesOverride is empty', () => { - const manager = new ExtensionEnablementManager(configDir, []); + const manager = new ExtensionEnablementManager([]); manager.validateExtensionOverrides([]); expect(consoleErrorSpy).not.toHaveBeenCalled(); }); it('should not log an error if all enabledExtensionNamesOverride are valid', () => { - const manager = new ExtensionEnablementManager(configDir, [ - 'ext-one', - 'ext-two', - ]); + const manager = new ExtensionEnablementManager(['ext-one', 'ext-two']); const extensions = [ { name: 'ext-one' }, { name: 'ext-two' }, @@ -295,7 +299,7 @@ describe('ExtensionEnablementManager', () => { }); it('should log an error for each invalid extension name in enabledExtensionNamesOverride', () => { - const manager = new ExtensionEnablementManager(configDir, [ + const manager = new ExtensionEnablementManager([ 'ext-one', 'ext-invalid', 'ext-another-invalid', @@ -315,7 +319,7 @@ describe('ExtensionEnablementManager', () => { }); it('should not log an error if "none" is in enabledExtensionNamesOverride', () => { - const manager = new ExtensionEnablementManager(configDir, ['none']); + const manager = new ExtensionEnablementManager(['none']); manager.validateExtensionOverrides([]); expect(consoleErrorSpy).not.toHaveBeenCalled(); }); diff --git a/packages/cli/src/config/extensions/extensionEnablement.ts b/packages/cli/src/config/extensions/extensionEnablement.ts index 6dbdf2491c..f5018df6a8 100644 --- a/packages/cli/src/config/extensions/extensionEnablement.ts +++ b/packages/cli/src/config/extensions/extensionEnablement.ts @@ -7,6 +7,7 @@ import fs from 'node:fs'; import path from 'node:path'; import type { GeminiCLIExtension } from '@google/gemini-cli-core'; +import { ExtensionStorage } from '../extension.js'; export interface ExtensionEnablementConfig { overrides: string[]; @@ -112,9 +113,12 @@ export class ExtensionEnablementManager { // only the ones in this list. private enabledExtensionNamesOverride: string[]; - constructor(configDir: string, enabledExtensionNames?: string[]) { - this.configDir = configDir; - this.configFilePath = path.join(configDir, 'extension-enablement.json'); + constructor(enabledExtensionNames?: string[]) { + this.configDir = ExtensionStorage.getUserExtensionsDir(); + this.configFilePath = path.join( + this.configDir, + 'extension-enablement.json', + ); this.enabledExtensionNamesOverride = enabledExtensionNames?.map((name) => name.toLowerCase()) ?? []; } diff --git a/packages/cli/src/config/extensions/update.test.ts b/packages/cli/src/config/extensions/update.test.ts index 82624868a3..99a83737f3 100644 --- a/packages/cli/src/config/extensions/update.test.ts +++ b/packages/cli/src/config/extensions/update.test.ts @@ -10,7 +10,6 @@ import * as os from 'node:os'; import * as path from 'node:path'; import { EXTENSIONS_CONFIG_FILENAME, - ExtensionStorage, INSTALL_METADATA_FILENAME, annotateActiveExtensions, loadExtension, @@ -137,7 +136,7 @@ describe('update tests', () => { })!, ], process.cwd(), - new ExtensionEnablementManager(ExtensionStorage.getUserExtensionsDir()), + new ExtensionEnablementManager(), )[0]; const updateInfo = await updateExtension( extension, @@ -194,7 +193,7 @@ describe('update tests', () => { })!, ], process.cwd(), - new ExtensionEnablementManager(ExtensionStorage.getUserExtensionsDir()), + new ExtensionEnablementManager(), )[0]; await updateExtension( extension, @@ -244,7 +243,7 @@ describe('update tests', () => { })!, ], process.cwd(), - new ExtensionEnablementManager(ExtensionStorage.getUserExtensionsDir()), + new ExtensionEnablementManager(), )[0]; await expect( updateExtension( @@ -292,7 +291,7 @@ describe('update tests', () => { })!, ], process.cwd(), - new ExtensionEnablementManager(ExtensionStorage.getUserExtensionsDir()), + new ExtensionEnablementManager(), )[0]; mockGit.getRemotes.mockResolvedValue([ @@ -334,7 +333,7 @@ describe('update tests', () => { })!, ], process.cwd(), - new ExtensionEnablementManager(ExtensionStorage.getUserExtensionsDir()), + new ExtensionEnablementManager(), )[0]; mockGit.getRemotes.mockResolvedValue([ @@ -380,7 +379,7 @@ describe('update tests', () => { })!, ], process.cwd(), - new ExtensionEnablementManager(ExtensionStorage.getUserExtensionsDir()), + new ExtensionEnablementManager(), )[0]; const dispatch = vi.fn(); await checkForAllExtensionUpdates( @@ -419,7 +418,7 @@ describe('update tests', () => { })!, ], process.cwd(), - new ExtensionEnablementManager(ExtensionStorage.getUserExtensionsDir()), + new ExtensionEnablementManager(), )[0]; const dispatch = vi.fn(); await checkForAllExtensionUpdates( @@ -454,7 +453,7 @@ describe('update tests', () => { })!, ], process.cwd(), - new ExtensionEnablementManager(ExtensionStorage.getUserExtensionsDir()), + new ExtensionEnablementManager(), )[0]; mockGit.getRemotes.mockRejectedValue(new Error('Git error')); diff --git a/packages/cli/src/gemini.tsx b/packages/cli/src/gemini.tsx index 75e4795be0..70950167b9 100644 --- a/packages/cli/src/gemini.tsx +++ b/packages/cli/src/gemini.tsx @@ -26,7 +26,7 @@ import { getStartupWarnings } from './utils/startupWarnings.js'; import { getUserStartupWarnings } from './utils/userStartupWarnings.js'; import { ConsolePatcher } from './ui/utils/ConsolePatcher.js'; import { runNonInteractive } from './nonInteractiveCli.js'; -import { ExtensionStorage, loadExtensions } from './config/extension.js'; +import { loadExtensions } from './config/extension.js'; import { cleanupCheckpoints, registerCleanup, @@ -286,7 +286,7 @@ export async function main() { const partialConfig = await loadCliConfig( settings.merged, [], - new ExtensionEnablementManager(ExtensionStorage.getUserExtensionsDir()), + new ExtensionEnablementManager(), sessionId, argv, ); @@ -358,7 +358,6 @@ export async function main() { // may have side effects. { const extensionEnablementManager = new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), argv.extensions, ); const extensions = loadExtensions(extensionEnablementManager); diff --git a/packages/cli/src/ui/AppContainer.test.tsx b/packages/cli/src/ui/AppContainer.test.tsx index 88779bb760..abd4b47420 100644 --- a/packages/cli/src/ui/AppContainer.test.tsx +++ b/packages/cli/src/ui/AppContainer.test.tsx @@ -73,7 +73,6 @@ vi.mock('./hooks/useFolderTrust.js'); vi.mock('./hooks/useIdeTrustListener.js'); vi.mock('./hooks/useMessageQueue.js'); vi.mock('./hooks/useAutoAcceptIndicator.js'); -vi.mock('./hooks/useWorkspaceMigration.js'); vi.mock('./hooks/useGitBranchName.js'); vi.mock('./contexts/VimModeContext.js'); vi.mock('./contexts/SessionContext.js'); @@ -100,7 +99,6 @@ import { useFolderTrust } from './hooks/useFolderTrust.js'; import { useIdeTrustListener } from './hooks/useIdeTrustListener.js'; import { useMessageQueue } from './hooks/useMessageQueue.js'; import { useAutoAcceptIndicator } from './hooks/useAutoAcceptIndicator.js'; -import { useWorkspaceMigration } from './hooks/useWorkspaceMigration.js'; import { useGitBranchName } from './hooks/useGitBranchName.js'; import { useVimMode } from './contexts/VimModeContext.js'; import { useSessionStats } from './contexts/SessionContext.js'; @@ -132,7 +130,6 @@ describe('AppContainer State Management', () => { const mockedUseIdeTrustListener = useIdeTrustListener as Mock; const mockedUseMessageQueue = useMessageQueue as Mock; const mockedUseAutoAcceptIndicator = useAutoAcceptIndicator as Mock; - const mockedUseWorkspaceMigration = useWorkspaceMigration as Mock; const mockedUseGitBranchName = useGitBranchName as Mock; const mockedUseVimMode = useVimMode as Mock; const mockedUseSessionStats = useSessionStats as Mock; @@ -236,12 +233,6 @@ describe('AppContainer State Management', () => { getQueuedMessagesText: vi.fn().mockReturnValue(''), }); mockedUseAutoAcceptIndicator.mockReturnValue(false); - mockedUseWorkspaceMigration.mockReturnValue({ - showWorkspaceMigrationDialog: false, - workspaceExtensions: [], - onWorkspaceMigrationDialogOpen: vi.fn(), - onWorkspaceMigrationDialogClose: vi.fn(), - }); mockedUseGitBranchName.mockReturnValue('main'); mockedUseVimMode.mockReturnValue({ isVimEnabled: false, diff --git a/packages/cli/src/ui/AppContainer.tsx b/packages/cli/src/ui/AppContainer.tsx index 1beec81da5..a839fb7f7c 100644 --- a/packages/cli/src/ui/AppContainer.tsx +++ b/packages/cli/src/ui/AppContainer.tsx @@ -86,7 +86,6 @@ import { ConsolePatcher } from './utils/ConsolePatcher.js'; import { registerCleanup, runExitCleanup } from '../utils/cleanup.js'; import { useMessageQueue } from './hooks/useMessageQueue.js'; import { useAutoAcceptIndicator } from './hooks/useAutoAcceptIndicator.js'; -import { useWorkspaceMigration } from './hooks/useWorkspaceMigration.js'; import { useSessionStats } from './contexts/SessionContext.js'; import { useGitBranchName } from './hooks/useGitBranchName.js'; import { useExtensionUpdates } from './hooks/useExtensionUpdates.js'; @@ -448,13 +447,6 @@ Logging in with Google... Please restart Gemini CLI to continue. const { isModelDialogOpen, openModelDialog, closeModelDialog } = useModelCommand(); - const { - showWorkspaceMigrationDialog, - workspaceExtensions, - onWorkspaceMigrationDialogOpen, - onWorkspaceMigrationDialogClose, - } = useWorkspaceMigration(settings); - const { toggleVimEnabled } = useVimMode(); const slashCommandActions = useMemo( @@ -1073,7 +1065,6 @@ Logging in with Google... Please restart Gemini CLI to continue. const nightly = props.version.includes('nightly'); const dialogsVisible = - showWorkspaceMigrationDialog || shouldShowIdePrompt || isFolderTrustDialogOpen || !!shellConfirmationRequest || @@ -1151,8 +1142,6 @@ Logging in with Google... Please restart Gemini CLI to continue. messageQueue, queueErrorMessage, showAutoAcceptIndicator, - showWorkspaceMigrationDialog, - workspaceExtensions, currentModel, userTier, proQuotaRequest, @@ -1233,8 +1222,6 @@ Logging in with Google... Please restart Gemini CLI to continue. messageQueue, queueErrorMessage, showAutoAcceptIndicator, - showWorkspaceMigrationDialog, - workspaceExtensions, userTier, proQuotaRequest, contextFileNames, @@ -1293,8 +1280,6 @@ Logging in with Google... Please restart Gemini CLI to continue. refreshStatic, handleFinalSubmit, handleClearScreen, - onWorkspaceMigrationDialogOpen, - onWorkspaceMigrationDialogClose, handleProQuotaChoice, setQueueErrorMessage, popAllMessages, @@ -1320,8 +1305,6 @@ Logging in with Google... Please restart Gemini CLI to continue. refreshStatic, handleFinalSubmit, handleClearScreen, - onWorkspaceMigrationDialogOpen, - onWorkspaceMigrationDialogClose, handleProQuotaChoice, setQueueErrorMessage, popAllMessages, diff --git a/packages/cli/src/ui/components/DialogManager.tsx b/packages/cli/src/ui/components/DialogManager.tsx index 7af65aac58..762de65794 100644 --- a/packages/cli/src/ui/components/DialogManager.tsx +++ b/packages/cli/src/ui/components/DialogManager.tsx @@ -16,7 +16,6 @@ import { AuthInProgress } from '../auth/AuthInProgress.js'; import { AuthDialog } from '../auth/AuthDialog.js'; import { EditorSettingsDialog } from './EditorSettingsDialog.js'; import { PrivacyNotice } from '../privacy/PrivacyNotice.js'; -import { WorkspaceMigrationDialog } from './WorkspaceMigrationDialog.js'; import { ProQuotaDialog } from './ProQuotaDialog.js'; import { PermissionsModifyTrustDialog } from './PermissionsModifyTrustDialog.js'; import { ModelDialog } from './ModelDialog.js'; @@ -50,15 +49,6 @@ export const DialogManager = ({ if (uiState.showIdeRestartPrompt) { return ; } - if (uiState.showWorkspaceMigrationDialog) { - return ( - - ); - } if (uiState.proQuotaRequest) { return ( void; - onClose: () => void; -}) { - const { workspaceExtensions, onOpen, onClose } = props; - const [migrationComplete, setMigrationComplete] = useState(false); - const [failedExtensions, setFailedExtensions] = useState([]); - onOpen(); - const onMigrate = async () => { - const failed = await performWorkspaceExtensionMigration( - workspaceExtensions, - // We aren't updating extensions, just moving them around, don't need to ask for consent. - async (_) => true, - ); - setFailedExtensions(failed); - setMigrationComplete(true); - }; - - useInput((input) => { - if (migrationComplete && input === 'q') { - process.exit(0); - } - }); - - if (migrationComplete) { - return ( - - {failedExtensions.length > 0 ? ( - <> - - The following extensions failed to migrate. Please try installing - them manually. To see other changes, Gemini CLI must be restarted. - Press 'q' to quit. - - - {failedExtensions.map((failed) => ( - - {failed} - ))} - - - ) : ( - - Migration complete. To see changes, Gemini CLI must be restarted. - Press 'q' to quit. - - )} - - ); - } - - return ( - - - Workspace-level extensions are deprecated{'\n'} - - - Would you like to install them at the user level? - - - The extension definition will remain in your workspace directory. - - - If you opt to skip, you can install them manually using the extensions - install command. - - - - {workspaceExtensions.map((extension) => ( - - {extension.name} - ))} - - - { - if (value === 'migrate') { - onMigrate(); - } else { - onClose(); - } - }} - /> - - - ); -} diff --git a/packages/cli/src/ui/contexts/UIActionsContext.tsx b/packages/cli/src/ui/contexts/UIActionsContext.tsx index 99d3c5a852..aa79365033 100644 --- a/packages/cli/src/ui/contexts/UIActionsContext.tsx +++ b/packages/cli/src/ui/contexts/UIActionsContext.tsx @@ -42,8 +42,6 @@ export interface UIActions { refreshStatic: () => void; handleFinalSubmit: (value: string) => void; handleClearScreen: () => void; - onWorkspaceMigrationDialogOpen: () => void; - onWorkspaceMigrationDialogClose: () => void; handleProQuotaChoice: (choice: 'auth' | 'continue') => void; setQueueErrorMessage: (message: string | null) => void; popAllMessages: (onPop: (messages: string | undefined) => void) => void; diff --git a/packages/cli/src/ui/contexts/UIStateContext.tsx b/packages/cli/src/ui/contexts/UIStateContext.tsx index d2bc6e7b9f..d893d38c10 100644 --- a/packages/cli/src/ui/contexts/UIStateContext.tsx +++ b/packages/cli/src/ui/contexts/UIStateContext.tsx @@ -91,9 +91,6 @@ export interface UIState { messageQueue: string[]; queueErrorMessage: string | null; showAutoAcceptIndicator: ApprovalMode; - showWorkspaceMigrationDialog: boolean; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - workspaceExtensions: any[]; // Extension[] // Quota-related state userTier: UserTierId | undefined; proQuotaRequest: ProQuotaDialogRequest | null; diff --git a/packages/cli/src/ui/hooks/useExtensionUpdates.test.ts b/packages/cli/src/ui/hooks/useExtensionUpdates.test.ts index bfdbcea54c..770c060e8a 100644 --- a/packages/cli/src/ui/hooks/useExtensionUpdates.test.ts +++ b/packages/cli/src/ui/hooks/useExtensionUpdates.test.ts @@ -9,7 +9,6 @@ import * as fs from 'node:fs'; import * as os from 'node:os'; import * as path from 'node:path'; import { - ExtensionStorage, annotateActiveExtensions, loadExtension, } from '../../config/extension.js'; @@ -117,7 +116,7 @@ describe('useExtensionUpdates', () => { const extension = annotateActiveExtensions( [loadExtension({ extensionDir, workspaceDir: tempHomeDir })!], tempHomeDir, - new ExtensionEnablementManager(ExtensionStorage.getUserExtensionsDir()), + new ExtensionEnablementManager(), )[0]; const addItem = vi.fn(); @@ -190,7 +189,7 @@ describe('useExtensionUpdates', () => { })!, ], tempHomeDir, - new ExtensionEnablementManager(ExtensionStorage.getUserExtensionsDir()), + new ExtensionEnablementManager(), ); const addItem = vi.fn(); diff --git a/packages/cli/src/ui/hooks/useWorkspaceMigration.ts b/packages/cli/src/ui/hooks/useWorkspaceMigration.ts deleted file mode 100644 index 2183f41ab3..0000000000 --- a/packages/cli/src/ui/hooks/useWorkspaceMigration.ts +++ /dev/null @@ -1,76 +0,0 @@ -/** - * @license - * Copyright 2025 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -import { useState, useEffect, useCallback, useMemo } from 'react'; -import type { GeminiCLIExtension } from '@google/gemini-cli-core'; -import { getWorkspaceExtensions } from '../../config/extension.js'; -import { type LoadedSettings, SettingScope } from '../../config/settings.js'; -import process from 'node:process'; - -export function useWorkspaceMigration(settings: LoadedSettings) { - const [showWorkspaceMigrationDialog, setShowWorkspaceMigrationDialog] = - useState(false); - const [workspaceExtensions, setWorkspaceExtensions] = useState< - GeminiCLIExtension[] - >([]); - - useEffect(() => { - // Default to true if not set. - if (!(settings.merged.experimental?.extensionManagement ?? true)) { - return; - } - const cwd = process.cwd(); - const extensions = getWorkspaceExtensions(cwd); - if ( - extensions.length > 0 && - !settings.merged.extensions?.workspacesWithMigrationNudge?.includes(cwd) - ) { - setWorkspaceExtensions(extensions); - setShowWorkspaceMigrationDialog(true); - console.log(settings.merged.extensions); - } - }, [ - settings.merged.extensions, - settings.merged.experimental?.extensionManagement, - ]); - - const onWorkspaceMigrationDialogOpen = useCallback(() => { - const userSettings = settings.forScope(SettingScope.User); - const extensionSettings = userSettings.settings.extensions || { - disabled: [], - }; - const workspacesWithMigrationNudge = - extensionSettings.workspacesWithMigrationNudge || []; - - const cwd = process.cwd(); - if (!workspacesWithMigrationNudge.includes(cwd)) { - workspacesWithMigrationNudge.push(cwd); - } - - extensionSettings.workspacesWithMigrationNudge = - workspacesWithMigrationNudge; - settings.setValue(SettingScope.User, 'extensions', extensionSettings); - }, [settings]); - - const onWorkspaceMigrationDialogClose = useCallback(() => { - setShowWorkspaceMigrationDialog(false); - }, [setShowWorkspaceMigrationDialog]); - - return useMemo( - () => ({ - showWorkspaceMigrationDialog, - workspaceExtensions, - onWorkspaceMigrationDialogOpen, - onWorkspaceMigrationDialogClose, - }), - [ - showWorkspaceMigrationDialog, - workspaceExtensions, - onWorkspaceMigrationDialogOpen, - onWorkspaceMigrationDialogClose, - ], - ); -} diff --git a/packages/cli/src/zed-integration/zedIntegration.ts b/packages/cli/src/zed-integration/zedIntegration.ts index 2235f9dc66..9cc13a6512 100644 --- a/packages/cli/src/zed-integration/zedIntegration.ts +++ b/packages/cli/src/zed-integration/zedIntegration.ts @@ -42,7 +42,6 @@ import * as path from 'node:path'; import { z } from 'zod'; import { randomUUID } from 'node:crypto'; -import { ExtensionStorage } from '../config/extension.js'; import type { CliArgs } from '../config/config.js'; import { loadCliConfig } from '../config/config.js'; import { ExtensionEnablementManager } from '../config/extensions/extensionEnablement.js'; @@ -207,10 +206,7 @@ class GeminiAgent { const config = await loadCliConfig( settings, this.extensions, - new ExtensionEnablementManager( - ExtensionStorage.getUserExtensionsDir(), - this.argv.extensions, - ), + new ExtensionEnablementManager(this.argv.extensions), sessionId, this.argv, cwd,