summaryrefslogtreecommitdiff
path: root/packages/cli/src/config
diff options
context:
space:
mode:
Diffstat (limited to 'packages/cli/src/config')
-rw-r--r--packages/cli/src/config/config.ts37
-rw-r--r--packages/cli/src/config/extension.test.ts44
-rw-r--r--packages/cli/src/config/extension.ts47
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;
}