diff --git a/packages/cli/src/config/extension-manager.ts b/packages/cli/src/config/extension-manager.ts index 48cd17b873..adc7743cf1 100644 --- a/packages/cli/src/config/extension-manager.ts +++ b/packages/cli/src/config/extension-manager.ts @@ -44,6 +44,7 @@ import { type GeminiCLIExtension, type HookDefinition, type HookEventName, + type ResolvedExtensionSetting, } from '@google/gemini-cli-core'; import { maybeRequestConsentOrFail } from './extensions/consent.js'; import { resolveEnvVarsInObject } from '../utils/envVarResolver.js'; @@ -509,6 +510,24 @@ Would you like to attempt to install via "git clone" instead?`, ); config = resolveEnvVarsInObject(config, customEnv); + const resolvedSettings: ResolvedExtensionSetting[] = []; + if (config.settings) { + for (const setting of config.settings) { + const value = customEnv[setting.envVar]; + resolvedSettings.push({ + name: setting.name, + envVar: setting.envVar, + value: + value === undefined + ? '[not set]' + : setting.sensitive + ? '***' + : value, + sensitive: setting.sensitive ?? false, + }); + } + } + if (config.mcpServers) { config.mcpServers = Object.fromEntries( Object.entries(config.mcpServers).map(([key, value]) => [ @@ -532,7 +551,7 @@ Would you like to attempt to install via "git clone" instead?`, }); } - const extension = { + const extension: GeminiCLIExtension = { name: config.name, version: config.version, path: effectiveExtensionPath, @@ -546,6 +565,8 @@ Would you like to attempt to install via "git clone" instead?`, this.workspaceDir, ), id: getExtensionId(config, installMetadata), + settings: config.settings, + resolvedSettings, }; this.loadedExtensions = [...this.loadedExtensions, extension]; @@ -700,6 +721,13 @@ Would you like to attempt to install via "git clone" instead?`, output += `\n ${tool}`; }); } + const resolvedSettings = extension.resolvedSettings; + if (resolvedSettings && resolvedSettings.length > 0) { + output += `\n Settings:`; + resolvedSettings.forEach((setting) => { + output += `\n ${setting.name}: ${setting.value}`; + }); + } return output; } diff --git a/packages/cli/src/ui/components/views/ExtensionsList.test.tsx b/packages/cli/src/ui/components/views/ExtensionsList.test.tsx index 8c841991ce..7fb5d2f361 100644 --- a/packages/cli/src/ui/components/views/ExtensionsList.test.tsx +++ b/packages/cli/src/ui/components/views/ExtensionsList.test.tsx @@ -125,4 +125,33 @@ describe('', () => { unmount(); }); } + + it('should render resolved settings for an extension', () => { + mockUIState(new Map()); + const extensionWithSettings = { + ...mockExtensions[0], + resolvedSettings: [ + { + name: 'sensitiveApiKey', + value: '***', + envVar: 'API_KEY', + sensitive: true, + }, + { + name: 'maxTokens', + value: '1000', + envVar: 'MAX_TOKENS', + sensitive: false, + }, + ], + }; + const { lastFrame, unmount } = render( + , + ); + const output = lastFrame(); + expect(output).toContain('settings:'); + expect(output).toContain('- sensitiveApiKey: ***'); + expect(output).toContain('- maxTokens: 1000'); + unmount(); + }); }); diff --git a/packages/cli/src/ui/components/views/ExtensionsList.tsx b/packages/cli/src/ui/components/views/ExtensionsList.tsx index 9297d2496a..2d456625f1 100644 --- a/packages/cli/src/ui/components/views/ExtensionsList.tsx +++ b/packages/cli/src/ui/components/views/ExtensionsList.tsx @@ -23,7 +23,7 @@ export const ExtensionsList: React.FC = ({ extensions }) => { return ( - Installed extensions: + Installed extensions: {extensions.map((ext) => { const state = extensionsUpdateState.get(ext.name); @@ -59,12 +59,22 @@ export const ExtensionsList: React.FC = ({ extensions }) => { } return ( - + {`${ext.name} (v${ext.version})`} {` - ${activeString}`} {{` (${stateText})`}} + {ext.resolvedSettings && ext.resolvedSettings.length > 0 && ( + + settings: + {ext.resolvedSettings.map((setting) => ( + + - {setting.name}: {setting.value} + + ))} + + )} ); })} diff --git a/packages/core/src/config/config.ts b/packages/core/src/config/config.ts index e07d40d03d..e1aeed6eee 100644 --- a/packages/core/src/config/config.ts +++ b/packages/core/src/config/config.ts @@ -134,6 +134,20 @@ export interface CodebaseInvestigatorSettings { model?: string; } +export interface ExtensionSetting { + name: string; + description: string; + envVar: string; + sensitive?: boolean; +} + +export interface ResolvedExtensionSetting { + name: string; + envVar: string; + value: string; + sensitive: boolean; +} + export interface IntrospectionAgentSettings { enabled?: boolean; } @@ -155,6 +169,8 @@ export interface GeminiCLIExtension { excludeTools?: string[]; id: string; hooks?: { [K in HookEventName]?: HookDefinition[] }; + settings?: ExtensionSetting[]; + resolvedSettings?: ResolvedExtensionSetting[]; } export interface ExtensionInstallMetadata {