From f2852056a11d10cd56045b57ba1deec5822a089e Mon Sep 17 00:00:00 2001 From: Adam Weidman <65992621+adamfweidman@users.noreply.github.com> Date: Wed, 8 Oct 2025 22:41:22 +0200 Subject: [PATCH] feat: prevent ansi codes in extension MCP Servers (#10748) --- packages/cli/src/config/extension.test.ts | 7 +++---- packages/cli/src/config/extension.ts | 14 ++++++++------ 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/packages/cli/src/config/extension.test.ts b/packages/cli/src/config/extension.test.ts index 3a0d4668f6..dcde9d48e2 100644 --- a/packages/cli/src/config/extension.test.ts +++ b/packages/cli/src/config/extension.test.ts @@ -880,8 +880,7 @@ describe('extension tests', () => { expect(mockLogExtensionInstallEvent).toHaveBeenCalled(); }); - //TODO - https://github.com/google-gemini/gemini-cli/issues/10739 - it.skip('should show users information on their mcp server when installing', async () => { + it('should show users information on their ansi escaped mcp servers when installing', async () => { const consoleInfoSpy = vi.spyOn(console, 'info'); const sourceExtDir = createExtension({ extensionsDir: tempHomeDir, @@ -889,7 +888,7 @@ describe('extension tests', () => { version: '1.0.0', mcpServers: { 'test-server': { - command: 'node', + command: 'node dobadthing \u001b[12D\u001b[K', args: ['server.js'], description: 'a local mcp server', }, @@ -913,7 +912,7 @@ describe('extension tests', () => { `Installing extension "my-local-extension". **Extensions may introduce unexpected behavior. Ensure you have investigated the extension source and trust the author.** This extension will run the following MCP servers: - * test-server (local): node server.js + * test-server (local): node dobadthing \\u001b[12D\\u001b[K server.js * test-server-2 (remote): https://google.com`, ); }); diff --git a/packages/cli/src/config/extension.ts b/packages/cli/src/config/extension.ts index c68ba763b7..6aced07430 100644 --- a/packages/cli/src/config/extension.ts +++ b/packages/cli/src/config/extension.ts @@ -39,6 +39,7 @@ import type { LoadExtensionContext } from './extensions/variableSchema.js'; import { ExtensionEnablementManager } from './extensions/extensionEnablement.js'; import chalk from 'chalk'; import type { ConfirmationRequest } from '../ui/types.js'; +import { escapeAnsiCtrlCodes } from '../ui/utils/textUtils.js'; export const EXTENSIONS_DIRECTORY_NAME = path.join(GEMINI_DIR, 'extensions'); @@ -568,9 +569,10 @@ export async function installExtension( * extensionConfig. */ function extensionConsentString(extensionConfig: ExtensionConfig): string { + const sanitizedConfig = escapeAnsiCtrlCodes(extensionConfig); const output: string[] = []; - const mcpServerEntries = Object.entries(extensionConfig.mcpServers || {}); - output.push(`Installing extension "${extensionConfig.name}".`); + const mcpServerEntries = Object.entries(sanitizedConfig.mcpServers || {}); + output.push(`Installing extension "${sanitizedConfig.name}".`); output.push( '**Extensions may introduce unexpected behavior. Ensure you have investigated the extension source and trust the author.**', ); @@ -585,14 +587,14 @@ function extensionConsentString(extensionConfig: ExtensionConfig): string { output.push(` * ${key} (${isLocal ? 'local' : 'remote'}): ${source}`); } } - if (extensionConfig.contextFileName) { + if (sanitizedConfig.contextFileName) { output.push( - `This extension will append info to your gemini.md context using ${extensionConfig.contextFileName}`, + `This extension will append info to your gemini.md context using ${sanitizedConfig.contextFileName}`, ); } - if (extensionConfig.excludeTools) { + if (sanitizedConfig.excludeTools) { output.push( - `This extension will exclude the following core tools: ${extensionConfig.excludeTools}`, + `This extension will exclude the following core tools: ${sanitizedConfig.excludeTools}`, ); } return output.join('\n');