diff options
Diffstat (limited to 'packages/cli/src/config')
| -rw-r--r-- | packages/cli/src/config/config.ts | 37 | ||||
| -rw-r--r-- | packages/cli/src/config/extension.test.ts | 44 | ||||
| -rw-r--r-- | packages/cli/src/config/extension.ts | 47 |
3 files changed, 82 insertions, 46 deletions
diff --git a/packages/cli/src/config/config.ts b/packages/cli/src/config/config.ts index 543801f0..2d33daa3 100644 --- a/packages/cli/src/config/config.ts +++ b/packages/cli/src/config/config.ts @@ -22,7 +22,7 @@ import { } from '@google/gemini-cli-core'; import { Settings } from './settings.js'; -import { Extension, filterActiveExtensions } from './extension.js'; +import { Extension, annotateActiveExtensions } from './extension.js'; import { getCliVersion } from '../utils/version.js'; import { loadSandboxConfig } from './sandboxConfig.js'; @@ -252,11 +252,15 @@ export async function loadCliConfig( process.env.TERM_PROGRAM === 'vscode' && !process.env.SANDBOX; - const activeExtensions = filterActiveExtensions( + const allExtensions = annotateActiveExtensions( extensions, argv.extensions || [], ); + const activeExtensions = extensions.filter( + (_, i) => allExtensions[i].isActive, + ); + // Set the context filename in the server's memoryTool module BEFORE loading memory // TODO(b/343434939): This is a bit of a hack. The contextFileName should ideally be passed // directly to the Config constructor in core, and have core handle setGeminiMdFilename. @@ -283,6 +287,7 @@ export async function loadCliConfig( let mcpServers = mergeMcpServers(settings, activeExtensions); const excludeTools = mergeExcludeTools(settings, activeExtensions); + const blockedMcpServers: Array<{ name: string; extensionName: string }> = []; if (!argv.allowedMcpServerNames) { if (settings.allowMCPServers) { @@ -308,9 +313,24 @@ export async function loadCliConfig( const allowedNames = new Set(argv.allowedMcpServerNames.filter(Boolean)); if (allowedNames.size > 0) { mcpServers = Object.fromEntries( - Object.entries(mcpServers).filter(([key]) => allowedNames.has(key)), + Object.entries(mcpServers).filter(([key, server]) => { + const isAllowed = allowedNames.has(key); + if (!isAllowed) { + blockedMcpServers.push({ + name: key, + extensionName: server.extensionName || '', + }); + } + return isAllowed; + }), ); } else { + blockedMcpServers.push( + ...Object.entries(mcpServers).map(([key, server]) => ({ + name: key, + extensionName: server.extensionName || '', + })), + ); mcpServers = {}; } } @@ -403,10 +423,8 @@ export async function loadCliConfig( maxSessionTurns: settings.maxSessionTurns ?? -1, experimentalAcp: argv.experimentalAcp || false, listExtensions: argv.listExtensions || false, - activeExtensions: activeExtensions.map((e) => ({ - name: e.config.name, - version: e.config.version, - })), + extensions: allExtensions, + blockedMcpServers, noBrowser: !!process.env.NO_BROWSER, summarizeToolOutput: settings.summarizeToolOutput, ideMode, @@ -424,7 +442,10 @@ function mergeMcpServers(settings: Settings, extensions: Extension[]) { ); return; } - mcpServers[key] = server; + mcpServers[key] = { + ...server, + extensionName: extension.config.name, + }; }, ); } diff --git a/packages/cli/src/config/extension.test.ts b/packages/cli/src/config/extension.test.ts index ab68e3f5..6b2a3f83 100644 --- a/packages/cli/src/config/extension.test.ts +++ b/packages/cli/src/config/extension.test.ts @@ -11,7 +11,7 @@ import * as path from 'path'; import { EXTENSIONS_CONFIG_FILENAME, EXTENSIONS_DIRECTORY_NAME, - filterActiveExtensions, + annotateActiveExtensions, loadExtensions, } from './extension.js'; @@ -86,42 +86,52 @@ describe('loadExtensions', () => { }); }); -describe('filterActiveExtensions', () => { +describe('annotateActiveExtensions', () => { const extensions = [ { config: { name: 'ext1', version: '1.0.0' }, contextFiles: [] }, { config: { name: 'ext2', version: '1.0.0' }, contextFiles: [] }, { config: { name: 'ext3', version: '1.0.0' }, contextFiles: [] }, ]; - it('should return all extensions if no enabled extensions are provided', () => { - const activeExtensions = filterActiveExtensions(extensions, []); + it('should mark all extensions as active if no enabled extensions are provided', () => { + const activeExtensions = annotateActiveExtensions(extensions, []); expect(activeExtensions).toHaveLength(3); + expect(activeExtensions.every((e) => e.isActive)).toBe(true); }); - it('should return only the enabled extensions', () => { - const activeExtensions = filterActiveExtensions(extensions, [ + it('should mark only the enabled extensions as active', () => { + const activeExtensions = annotateActiveExtensions(extensions, [ 'ext1', 'ext3', ]); - expect(activeExtensions).toHaveLength(2); - expect(activeExtensions.some((e) => e.config.name === 'ext1')).toBe(true); - expect(activeExtensions.some((e) => e.config.name === 'ext3')).toBe(true); + expect(activeExtensions).toHaveLength(3); + expect(activeExtensions.find((e) => e.name === 'ext1')?.isActive).toBe( + true, + ); + expect(activeExtensions.find((e) => e.name === 'ext2')?.isActive).toBe( + false, + ); + expect(activeExtensions.find((e) => e.name === 'ext3')?.isActive).toBe( + true, + ); }); - it('should return no extensions when "none" is provided', () => { - const activeExtensions = filterActiveExtensions(extensions, ['none']); - expect(activeExtensions).toHaveLength(0); + it('should mark all extensions as inactive when "none" is provided', () => { + const activeExtensions = annotateActiveExtensions(extensions, ['none']); + expect(activeExtensions).toHaveLength(3); + expect(activeExtensions.every((e) => !e.isActive)).toBe(true); }); it('should handle case-insensitivity', () => { - const activeExtensions = filterActiveExtensions(extensions, ['EXT1']); - expect(activeExtensions).toHaveLength(1); - expect(activeExtensions[0].config.name).toBe('ext1'); + const activeExtensions = annotateActiveExtensions(extensions, ['EXT1']); + expect(activeExtensions.find((e) => e.name === 'ext1')?.isActive).toBe( + true, + ); }); it('should log an error for unknown extensions', () => { - const consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => {}); - filterActiveExtensions(extensions, ['ext4']); + const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {}); + annotateActiveExtensions(extensions, ['ext4']); expect(consoleSpy).toHaveBeenCalledWith('Extension not found: ext4'); consoleSpy.mockRestore(); }); diff --git a/packages/cli/src/config/extension.ts b/packages/cli/src/config/extension.ts index aa540cfd..adefec29 100644 --- a/packages/cli/src/config/extension.ts +++ b/packages/cli/src/config/extension.ts @@ -4,7 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { MCPServerConfig } from '@google/gemini-cli-core'; +import { MCPServerConfig, GeminiCLIExtension } from '@google/gemini-cli-core'; import * as fs from 'fs'; import * as path from 'path'; import * as os from 'os'; @@ -34,9 +34,6 @@ export function loadExtensions(workspaceDir: string): Extension[] { const uniqueExtensions = new Map<string, Extension>(); for (const extension of allExtensions) { if (!uniqueExtensions.has(extension.config.name)) { - console.log( - `Loading extension: ${extension.config.name} (version: ${extension.config.version})`, - ); uniqueExtensions.set(extension.config.name, extension); } } @@ -113,12 +110,18 @@ function getContextFileNames(config: ExtensionConfig): string[] { return config.contextFileName; } -export function filterActiveExtensions( +export function annotateActiveExtensions( extensions: Extension[], enabledExtensionNames: string[], -): Extension[] { +): GeminiCLIExtension[] { + const annotatedExtensions: GeminiCLIExtension[] = []; + if (enabledExtensionNames.length === 0) { - return extensions; + return extensions.map((extension) => ({ + name: extension.config.name, + version: extension.config.version, + isActive: true, + })); } const lowerCaseEnabledExtensions = new Set( @@ -129,31 +132,33 @@ export function filterActiveExtensions( lowerCaseEnabledExtensions.size === 1 && lowerCaseEnabledExtensions.has('none') ) { - if (extensions.length > 0) { - console.log('All extensions are disabled.'); - } - return []; + return extensions.map((extension) => ({ + name: extension.config.name, + version: extension.config.version, + isActive: false, + })); } - const activeExtensions: Extension[] = []; const notFoundNames = new Set(lowerCaseEnabledExtensions); for (const extension of extensions) { const lowerCaseName = extension.config.name.toLowerCase(); - if (lowerCaseEnabledExtensions.has(lowerCaseName)) { - console.log( - `Activated extension: ${extension.config.name} (version: ${extension.config.version})`, - ); - activeExtensions.push(extension); + const isActive = lowerCaseEnabledExtensions.has(lowerCaseName); + + if (isActive) { notFoundNames.delete(lowerCaseName); - } else { - console.log(`Disabled extension: ${extension.config.name}`); } + + annotatedExtensions.push({ + name: extension.config.name, + version: extension.config.version, + isActive, + }); } for (const requestedName of notFoundNames) { - console.log(`Extension not found: ${requestedName}`); + console.error(`Extension not found: ${requestedName}`); } - return activeExtensions; + return annotatedExtensions; } |
