refactor(logging): Centralize console logging with debugLogger (#11590)

This commit is contained in:
Abhi
2025-10-21 16:35:22 -04:00
committed by GitHub
parent f5e07d94bd
commit b364f37655
72 changed files with 345 additions and 289 deletions
@@ -5,7 +5,11 @@
*/
import { type CommandModule } from 'yargs';
import { FatalConfigError, getErrorMessage } from '@google/gemini-cli-core';
import {
debugLogger,
FatalConfigError,
getErrorMessage,
} from '@google/gemini-cli-core';
import { enableExtension } from '../../config/extension.js';
import { SettingScope } from '../../config/settings.js';
import { ExtensionEnablementManager } from '../../config/extensions/extensionEnablement.js';
@@ -28,11 +32,11 @@ export function handleEnable(args: EnableArgs) {
enableExtension(args.name, SettingScope.User, extensionEnablementManager);
}
if (args.scope) {
console.log(
debugLogger.log(
`Extension "${args.name}" successfully enabled for scope "${args.scope}".`,
);
} else {
console.log(
debugLogger.log(
`Extension "${args.name}" successfully enabled in all scopes.`,
);
}
+16 -26
View File
@@ -4,20 +4,11 @@
* SPDX-License-Identifier: Apache-2.0
*/
import {
vi,
describe,
it,
expect,
beforeEach,
afterEach,
type Mock,
type MockInstance,
} from 'vitest';
import { vi, describe, it, expect, beforeEach, type Mock } from 'vitest';
import { listMcpServers } from './list.js';
import { loadSettings } from '../../config/settings.js';
import { ExtensionStorage, loadExtensions } from '../../config/extension.js';
import { createTransport } from '@google/gemini-cli-core';
import { createTransport, debugLogger } from '@google/gemini-cli-core';
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
vi.mock('../../config/settings.js', () => ({
@@ -43,6 +34,12 @@ vi.mock('@google/gemini-cli-core', () => ({
})),
GEMINI_DIR: '.gemini',
getErrorMessage: (e: unknown) => (e instanceof Error ? e.message : String(e)),
debugLogger: {
log: vi.fn(),
warn: vi.fn(),
error: vi.fn(),
debug: vi.fn(),
},
}));
vi.mock('@modelcontextprotocol/sdk/client/index.js');
@@ -64,15 +61,12 @@ interface MockTransport {
}
describe('mcp list command', () => {
let consoleSpy: MockInstance;
let mockClient: MockClient;
let mockTransport: MockTransport;
beforeEach(() => {
vi.resetAllMocks();
consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
mockTransport = { close: vi.fn() };
mockClient = {
connect: vi.fn(),
@@ -86,16 +80,12 @@ describe('mcp list command', () => {
mockedGetUserExtensionsDir.mockReturnValue('/mocked/extensions/dir');
});
afterEach(() => {
consoleSpy.mockRestore();
});
it('should display message when no servers configured', async () => {
mockedLoadSettings.mockReturnValue({ merged: { mcpServers: {} } });
await listMcpServers();
expect(consoleSpy).toHaveBeenCalledWith('No MCP servers configured.');
expect(debugLogger.log).toHaveBeenCalledWith('No MCP servers configured.');
});
it('should display different server types with connected status', async () => {
@@ -114,18 +104,18 @@ describe('mcp list command', () => {
await listMcpServers();
expect(consoleSpy).toHaveBeenCalledWith('Configured MCP servers:\n');
expect(consoleSpy).toHaveBeenCalledWith(
expect(debugLogger.log).toHaveBeenCalledWith('Configured MCP servers:\n');
expect(debugLogger.log).toHaveBeenCalledWith(
expect.stringContaining(
'stdio-server: /path/to/server arg1 (stdio) - Connected',
),
);
expect(consoleSpy).toHaveBeenCalledWith(
expect(debugLogger.log).toHaveBeenCalledWith(
expect.stringContaining(
'sse-server: https://example.com/sse (sse) - Connected',
),
);
expect(consoleSpy).toHaveBeenCalledWith(
expect(debugLogger.log).toHaveBeenCalledWith(
expect.stringContaining(
'http-server: https://example.com/http (http) - Connected',
),
@@ -145,7 +135,7 @@ describe('mcp list command', () => {
await listMcpServers();
expect(consoleSpy).toHaveBeenCalledWith(
expect(debugLogger.log).toHaveBeenCalledWith(
expect.stringContaining(
'test-server: /test/server (stdio) - Disconnected',
),
@@ -171,12 +161,12 @@ describe('mcp list command', () => {
await listMcpServers();
expect(consoleSpy).toHaveBeenCalledWith(
expect(debugLogger.log).toHaveBeenCalledWith(
expect.stringContaining(
'config-server: /config/server (stdio) - Connected',
),
);
expect(consoleSpy).toHaveBeenCalledWith(
expect(debugLogger.log).toHaveBeenCalledWith(
expect.stringContaining(
'extension-server (from test-extension): /ext/server (stdio) - Connected',
),
+8 -4
View File
@@ -8,7 +8,11 @@
import type { CommandModule } from 'yargs';
import { loadSettings } from '../../config/settings.js';
import type { MCPServerConfig } from '@google/gemini-cli-core';
import { MCPServerStatus, createTransport } from '@google/gemini-cli-core';
import {
MCPServerStatus,
createTransport,
debugLogger,
} from '@google/gemini-cli-core';
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
import { loadExtensions } from '../../config/extension.js';
import { ExtensionEnablementManager } from '../../config/extensions/extensionEnablement.js';
@@ -84,11 +88,11 @@ export async function listMcpServers(): Promise<void> {
const serverNames = Object.keys(mcpServers);
if (serverNames.length === 0) {
console.log('No MCP servers configured.');
debugLogger.log('No MCP servers configured.');
return;
}
console.log('Configured MCP servers:\n');
debugLogger.log('Configured MCP servers:\n');
for (const serverName of serverNames) {
const server = mcpServers[serverName];
@@ -125,7 +129,7 @@ export async function listMcpServers(): Promise<void> {
serverInfo += `${server.command} ${server.args?.join(' ') || ''} (stdio)`;
}
console.log(`${statusIndicator} ${serverInfo} - ${statusText}`);
debugLogger.log(`${statusIndicator} ${serverInfo} - ${statusText}`);
}
}
+3 -2
View File
@@ -7,6 +7,7 @@
// File for 'gemini mcp remove' command
import type { CommandModule } from 'yargs';
import { loadSettings, SettingScope } from '../../config/settings.js';
import { debugLogger } from '@google/gemini-cli-core';
async function removeMcpServer(
name: string,
@@ -23,7 +24,7 @@ async function removeMcpServer(
const mcpServers = existingSettings.mcpServers || {};
if (!mcpServers[name]) {
console.log(`Server "${name}" not found in ${scope} settings.`);
debugLogger.log(`Server "${name}" not found in ${scope} settings.`);
return;
}
@@ -31,7 +32,7 @@ async function removeMcpServer(
settings.setValue(settingsScope, 'mcpServers', mcpServers);
console.log(`Server "${name}" removed from ${scope} settings.`);
debugLogger.log(`Server "${name}" removed from ${scope} settings.`);
}
export const removeCommand: CommandModule = {
-2
View File
@@ -1073,8 +1073,6 @@ describe('Settings Loading and Merging', () => {
);
const settings = loadSettings(MOCK_WORKSPACE_DIR);
const e = settings.user.settings.model?.chatCompression;
console.log(e);
expect(settings.user.settings.model?.chatCompression).toEqual({
contextPercentageThreshold: 0.5,
+2 -1
View File
@@ -10,6 +10,7 @@ import { homedir, platform } from 'node:os';
import * as dotenv from 'dotenv';
import process from 'node:process';
import {
debugLogger,
FatalConfigError,
GEMINI_DIR,
getErrorMessage,
@@ -753,7 +754,7 @@ export function migrateDeprecatedSettings(
const processScope = (scope: SettingScope) => {
const settings = loadedSettings.forScope(scope).settings;
if (settings.extensions?.disabled) {
console.log(
debugLogger.log(
`Migrating deprecated extensions.disabled settings from ${scope} settings...`,
);
const extensionEnablementManager = new ExtensionEnablementManager();
+2 -1
View File
@@ -4,6 +4,7 @@
* SPDX-License-Identifier: Apache-2.0
*/
import { debugLogger } from '@google/gemini-cli-core';
import type { SlashCommand } from '../ui/commands/types.js';
import type { ICommandLoader } from './types.js';
@@ -57,7 +58,7 @@ export class CommandService {
if (result.status === 'fulfilled') {
allCommands.push(...result.value);
} else {
console.debug('A command loader failed:', result.reason);
debugLogger.debug('A command loader failed:', result.reason);
}
}
+4 -3
View File
@@ -42,6 +42,7 @@ import {
AuthType,
clearCachedCredentialFile,
ShellExecutionService,
debugLogger,
} from '@google/gemini-cli-core';
import { validateAuthMethod } from '../config/auth.js';
import { loadHierarchicalGeminiMemory } from '../config/config.js';
@@ -389,7 +390,7 @@ export const AppContainer = (props: AppContainerProps) => {
config.isBrowserLaunchSuppressed()
) {
await runExitCleanup();
console.log(`
debugLogger.log(`
----------------------------------------------------------------
Logging in with Google... Please restart Gemini CLI to continue.
----------------------------------------------------------------
@@ -558,7 +559,7 @@ Logging in with Google... Please restart Gemini CLI to continue.
Date.now(),
);
if (config.getDebugMode()) {
console.log(
debugLogger.log(
`[DEBUG] Refreshed memory content in config: ${memoryContent.substring(
0,
200,
@@ -933,7 +934,7 @@ Logging in with Google... Please restart Gemini CLI to continue.
(key: Key) => {
// Debug log keystrokes if enabled
if (settings.merged.general?.debugKeystrokeLogging) {
console.log('[DEBUG] Keystroke:', JSON.stringify(key));
debugLogger.log('[DEBUG] Keystroke:', JSON.stringify(key));
}
if (keyMatchers[Command.QUIT](key)) {
+2 -1
View File
@@ -14,6 +14,7 @@ import { SettingScope } from '../../config/settings.js';
import {
AuthType,
clearCachedCredentialFile,
debugLogger,
type Config,
} from '@google/gemini-cli-core';
import { useKeypress } from '../hooks/useKeypress.js';
@@ -108,7 +109,7 @@ export function AuthDialog({
config.isBrowserLaunchSuppressed()
) {
runExitCleanup();
console.log(
debugLogger.log(
`
----------------------------------------------------------------
Logging in with Google... Please restart Gemini CLI to continue.
+2 -2
View File
@@ -6,7 +6,7 @@
import { useState, useEffect, useCallback } from 'react';
import type { LoadedSettings } from '../../config/settings.js';
import { AuthType, type Config } from '@google/gemini-cli-core';
import { AuthType, debugLogger, type Config } from '@google/gemini-cli-core';
import { getErrorMessage } from '@google/gemini-cli-core';
import { AuthState } from '../types.js';
import { validateAuthMethod } from '../../config/auth.js';
@@ -80,7 +80,7 @@ export const useAuthCommand = (settings: LoadedSettings, config: Config) => {
try {
await config.refreshAuth(authType);
console.log(`Authenticated via "${authType}".`);
debugLogger.log(`Authenticated via "${authType}".`);
setAuthError(null);
setAuthState(AuthState.Authenticated);
} catch (e) {
+2 -1
View File
@@ -4,6 +4,7 @@
* SPDX-License-Identifier: Apache-2.0
*/
import { debugLogger } from '@google/gemini-cli-core';
import { copyToClipboard } from '../utils/commandUtils.js';
import type { SlashCommand, SlashCommandActionReturn } from './types.js';
import { CommandKind } from './types.js';
@@ -45,7 +46,7 @@ export const copyCommand: SlashCommand = {
};
} catch (error) {
const message = error instanceof Error ? error.message : String(error);
console.debug(message);
debugLogger.debug(message);
return {
type: 'message',
@@ -20,6 +20,7 @@ import {
import type { SlashCommand, SlashCommandActionReturn } from './types.js';
import { CommandKind } from './types.js';
import { getUrlOpenCommand } from '../../ui/utils/commandUtils.js';
import { debugLogger } from '@google/gemini-cli-core';
export const GITHUB_WORKFLOW_PATHS = [
'gemini-dispatch/gemini-dispatch.yml',
@@ -84,7 +85,7 @@ export async function updateGitignore(gitRepoRoot: string): Promise<void> {
}
}
} catch (error) {
console.debug('Failed to update .gitignore:', error);
debugLogger.debug('Failed to update .gitignore:', error);
// Continue without failing the whole command
}
}
@@ -109,7 +110,7 @@ export const setupGithubCommand: SlashCommand = {
try {
gitRepoRoot = getGitRepoRoot();
} catch (_error) {
console.debug(`Failed to get git repo root:`, _error);
debugLogger.debug(`Failed to get git repo root:`, _error);
throw new Error(
'Unable to determine the GitHub repository. /setup-github must be run from a git repository.',
);
@@ -125,7 +126,7 @@ export const setupGithubCommand: SlashCommand = {
try {
await fs.promises.mkdir(githubWorkflowsDir, { recursive: true });
} catch (_error) {
console.debug(
debugLogger.debug(
`Failed to create ${githubWorkflowsDir} directory:`,
_error,
);
@@ -37,6 +37,7 @@ import {
type SettingsValue,
TOGGLE_TYPES,
} from '../../config/settingsSchema.js';
import { debugLogger } from '@google/gemini-cli-core';
interface SettingsDialogProps {
settings: LoadedSettings;
@@ -162,7 +163,7 @@ export function SettingsDialog({
newValue,
currentScopeSettings,
);
console.log(
debugLogger.log(
`[DEBUG SettingsDialog] Saving ${key} immediately with value:`,
newValue,
);
@@ -207,7 +208,7 @@ export function SettingsDialog({
setModifiedSettings((prev) => {
const updated = new Set(prev).add(key);
const needsRestart = hasRestartRequiredSettings(updated);
console.log(
debugLogger.log(
`[DEBUG SettingsDialog] Modified settings:`,
Array.from(updated),
'Needs restart:',
@@ -9,6 +9,7 @@ import * as path from 'node:path';
import type { PartListUnion, PartUnion } from '@google/genai';
import type { AnyToolInvocation, Config } from '@google/gemini-cli-core';
import {
debugLogger,
getErrorMessage,
isNodeError,
unescapePath,
@@ -372,7 +373,7 @@ export async function handleAtCommand({
}
const message = `Ignored ${totalIgnored} files:\n${messages.join('\n')}`;
console.log(message);
debugLogger.log(message);
onDebugMessage(message);
}
@@ -222,8 +222,6 @@ export const useShellCommandProcessor = (
shellExecutionConfig,
);
console.log(terminalHeight, terminalWidth);
executionPid = pid;
if (pid) {
setActiveShellPtyId(pid);
@@ -4,6 +4,7 @@
* SPDX-License-Identifier: Apache-2.0
*/
import { debugLogger } from '@google/gemini-cli-core';
import { useState, useCallback } from 'react';
interface Logger {
@@ -69,7 +70,10 @@ export function useInputHistoryStore(): UseInputHistoryStoreReturn {
setIsInitialized(true);
} catch (error) {
// Start with empty history even if logger initialization fails
console.warn('Failed to initialize input history from logger:', error);
debugLogger.warn(
'Failed to initialize input history from logger:',
error,
);
setPastSessionMessages([]);
recalculateHistory([], []);
setIsInitialized(true);
@@ -20,7 +20,7 @@ import type {
Status as CoreStatus,
EditorType,
} from '@google/gemini-cli-core';
import { CoreToolScheduler } from '@google/gemini-cli-core';
import { CoreToolScheduler, debugLogger } from '@google/gemini-cli-core';
import { useCallback, useState, useMemo } from 'react';
import type {
HistoryItemToolGroup,
@@ -198,7 +198,7 @@ function mapCoreStatusToDisplayStatus(coreStatus: CoreStatus): ToolCallStatus {
return ToolCallStatus.Pending;
default: {
const exhaustiveCheck: never = coreStatus;
console.warn(`Unknown core status encountered: ${exhaustiveCheck}`);
debugLogger.warn(`Unknown core status encountered: ${exhaustiveCheck}`);
return ToolCallStatus.Error;
}
}
@@ -6,7 +6,7 @@
import type { Message } from '../types.js';
import { MessageType } from '../types.js';
import type { Config } from '@google/gemini-cli-core';
import { debugLogger, type Config } from '@google/gemini-cli-core';
import type { LoadedSettings } from '../../config/settings.js';
export function createShowMemoryAction(
@@ -27,7 +27,7 @@ export function createShowMemoryAction(
const debugMode = config.getDebugMode();
if (debugMode) {
console.log('[DEBUG] Show Memory command invoked.');
debugLogger.log('[DEBUG] Show Memory command invoked.');
}
const currentMemory = config.getUserMemory();
@@ -38,10 +38,10 @@ export function createShowMemoryAction(
: [contextFileName];
if (debugMode) {
console.log(
debugLogger.log(
`[DEBUG] Showing memory. Content from config.getUserMemory() (first 200 chars): ${currentMemory.substring(0, 200)}...`,
);
console.log(`[DEBUG] Number of context files loaded: ${fileCount}`);
debugLogger.log(`[DEBUG] Number of context files loaded: ${fileCount}`);
}
if (fileCount > 0) {
@@ -12,6 +12,7 @@ import {
type CommandContext,
type SlashCommand,
} from '../commands/types.js';
import { debugLogger } from '@google/gemini-cli-core';
// Type alias for improved type safety based on actual fzf result structure
type FzfCommandResult = {
@@ -189,7 +190,7 @@ function useCommandSuggestions(
// Safety check: ensure leafCommand and completion exist
if (!leafCommand?.completion) {
console.warn(
debugLogger.warn(
'Attempted argument completion without completion function',
);
return;
+2 -1
View File
@@ -8,6 +8,7 @@ import { useCallback, useReducer, useEffect } from 'react';
import type { Key } from './useKeypress.js';
import type { TextBuffer } from '../components/shared/text-buffer.js';
import { useVimMode } from '../contexts/VimModeContext.js';
import { debugLogger } from '@google/gemini-cli-core';
export type VimMode = 'NORMAL' | 'INSERT';
@@ -394,7 +395,7 @@ export function useVim(buffer: TextBuffer, onSubmit?: (value: string) => void) {
normalizedKey = normalizeKey(key);
} catch (error) {
// Handle malformed key inputs gracefully
console.warn('Malformed key input in vim mode:', key, error);
debugLogger.warn('Malformed key input in vim mode:', key, error);
return false;
}
+3 -1
View File
@@ -4,6 +4,8 @@
* SPDX-License-Identifier: Apache-2.0
*/
import { debugLogger } from '@google/gemini-cli-core';
// Mapping from common CSS color names (lowercase) to hex codes (lowercase)
// Excludes names directly supported by Ink
export const CSS_NAME_TO_HEX_MAP: Readonly<Record<string, string>> = {
@@ -224,7 +226,7 @@ export function resolveColor(colorValue: string): string | undefined {
}
// 4. Could not resolve
console.warn(
debugLogger.warn(
`[ColorUtils] Could not resolve color "${colorValue}" to an Ink-compatible format.`,
);
return undefined;
+11 -7
View File
@@ -25,6 +25,7 @@ import { ANSI } from './ansi.js';
import { ANSILight } from './ansi-light.js';
import { NoColorTheme } from './no-color.js';
import process from 'node:process';
import { debugLogger } from '@google/gemini-cli-core';
export interface ThemeDisplay {
name: string;
@@ -75,7 +76,7 @@ class ThemeManager {
const validation = validateCustomTheme(customThemeConfig);
if (validation.isValid) {
if (validation.warning) {
console.warn(`Theme "${name}": ${validation.warning}`);
debugLogger.warn(`Theme "${name}": ${validation.warning}`);
}
const themeWithDefaults: CustomTheme = {
...DEFAULT_THEME.colors,
@@ -88,10 +89,10 @@ class ThemeManager {
const theme = createCustomTheme(themeWithDefaults);
this.customThemes.set(name, theme);
} catch (error) {
console.warn(`Failed to load custom theme "${name}":`, error);
debugLogger.warn(`Failed to load custom theme "${name}":`, error);
}
} else {
console.warn(`Invalid custom theme "${name}": ${validation.error}`);
debugLogger.warn(`Invalid custom theme "${name}": ${validation.error}`);
}
}
// If the current active theme is a custom theme, keep it if still valid
@@ -246,7 +247,7 @@ class ThemeManager {
// 2. Perform security check.
const homeDir = path.resolve(os.homedir());
if (!canonicalPath.startsWith(homeDir)) {
console.warn(
debugLogger.warn(
`Theme file at "${themePath}" is outside your home directory. ` +
`Only load themes from trusted sources.`,
);
@@ -259,14 +260,14 @@ class ThemeManager {
const validation = validateCustomTheme(customThemeConfig);
if (!validation.isValid) {
console.warn(
debugLogger.warn(
`Invalid custom theme from file "${themePath}": ${validation.error}`,
);
return undefined;
}
if (validation.warning) {
console.warn(`Theme from "${themePath}": ${validation.warning}`);
debugLogger.warn(`Theme from "${themePath}": ${validation.warning}`);
}
// 4. Create and cache the theme.
@@ -286,7 +287,10 @@ class ThemeManager {
if (
!(error instanceof Error && 'code' in error && error.code === 'ENOENT')
) {
console.warn(`Could not load theme from file "${themePath}":`, error);
debugLogger.warn(
`Could not load theme from file "${themePath}":`,
error,
);
}
return undefined;
}
+2 -1
View File
@@ -4,6 +4,7 @@
* SPDX-License-Identifier: Apache-2.0
*/
import { debugLogger } from '@google/gemini-cli-core';
import type { SpawnOptions } from 'node:child_process';
import { spawn } from 'node:child_process';
@@ -165,7 +166,7 @@ export const getUrlOpenCommand = (): string => {
default:
// Default to xdg-open, which appears to be supported for the less popular operating systems.
openCmd = 'xdg-open';
console.warn(
debugLogger.warn(
`Unknown platform: ${process.platform}. Attempting to open URLs with: ${openCmd}.`,
);
break;
+3 -2
View File
@@ -30,6 +30,7 @@ import { exec } from 'node:child_process';
import { promisify } from 'node:util';
import { isKittyProtocolEnabled } from './kittyProtocolDetector.js';
import { VSCODE_SHIFT_ENTER_SEQUENCE } from './platformConstants.js';
import { debugLogger } from '@google/gemini-cli-core';
const execAsync = promisify(exec);
@@ -88,7 +89,7 @@ async function detectTerminal(): Promise<SupportedTerminal | null> {
return 'vscode';
} catch (error) {
// Continue detection even if process check fails
console.debug('Parent process detection failed:', error);
debugLogger.debug('Parent process detection failed:', error);
}
}
@@ -103,7 +104,7 @@ async function backupFile(filePath: string): Promise<void> {
await fs.copyFile(filePath, backupPath);
} catch (error) {
// Log backup errors but continue with operation
console.warn(`Failed to create backup of ${filePath}:`, error);
debugLogger.warn(`Failed to create backup of ${filePath}:`, error);
}
}
+2 -1
View File
@@ -9,6 +9,7 @@ import updateNotifier from 'update-notifier';
import semver from 'semver';
import { getPackageJson } from '../../utils/package.js';
import type { LoadedSettings } from '../../config/settings.js';
import { debugLogger } from '@google/gemini-cli-core';
export const FETCH_TIMEOUT_MS = 2000;
@@ -101,7 +102,7 @@ export async function checkForUpdates(
return null;
} catch (e) {
console.warn('Failed to check for updates: ' + e);
debugLogger.warn('Failed to check for updates: ' + e);
return null;
}
}
+6 -2
View File
@@ -4,6 +4,7 @@
* SPDX-License-Identifier: Apache-2.0
*/
import { debugLogger } from '@google/gemini-cli-core';
import { execSync } from 'node:child_process';
import { ProxyAgent } from 'undici';
@@ -24,7 +25,7 @@ export const isGitHubRepository = (): boolean => {
return pattern.test(remotes);
} catch (_error) {
// If any filesystem error occurs, assume not a git repo
console.debug(`Failed to get git remote:`, _error);
debugLogger.debug(`Failed to get git remote:`, _error);
return false;
}
};
@@ -83,7 +84,10 @@ export const getLatestGitHubRelease = async (
}
return releaseTag;
} catch (_error) {
console.debug(`Failed to determine latest run-gemini-cli release:`, _error);
debugLogger.debug(
`Failed to determine latest run-gemini-cli release:`,
_error,
);
throw new Error(
`Unable to determine the latest run-gemini-cli release on GitHub.`,
);
@@ -9,10 +9,16 @@ import { getInstallationInfo, PackageManager } from './installationInfo.js';
import * as fs from 'node:fs';
import * as path from 'node:path';
import * as childProcess from 'node:child_process';
import { isGitRepository } from '@google/gemini-cli-core';
import { isGitRepository, debugLogger } from '@google/gemini-cli-core';
vi.mock('@google/gemini-cli-core', () => ({
isGitRepository: vi.fn(),
debugLogger: {
log: vi.fn(),
warn: vi.fn(),
error: vi.fn(),
debug: vi.fn(),
},
}));
vi.mock('fs', async (importOriginal) => {
@@ -59,7 +65,6 @@ describe('getInstallationInfo', () => {
});
it('should return UNKNOWN and log error if realpathSync fails', () => {
const consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
process.argv[1] = '/path/to/cli';
const error = new Error('realpath failed');
mockedRealPathSync.mockImplementation(() => {
@@ -69,8 +74,7 @@ describe('getInstallationInfo', () => {
const info = getInstallationInfo(projectRoot, false);
expect(info.packageManager).toBe(PackageManager.UNKNOWN);
expect(consoleSpy).toHaveBeenCalledWith(error);
consoleSpy.mockRestore();
expect(debugLogger.log).toHaveBeenCalledWith(error);
});
it('should detect running from a local git clone', () => {
+2 -2
View File
@@ -4,7 +4,7 @@
* SPDX-License-Identifier: Apache-2.0
*/
import { isGitRepository } from '@google/gemini-cli-core';
import { debugLogger, isGitRepository } from '@google/gemini-cli-core';
import * as fs from 'node:fs';
import * as path from 'node:path';
import * as childProcess from 'node:child_process';
@@ -174,7 +174,7 @@ export function getInstallationInfo(
: 'Installed with npm. Attempting to automatically update now...',
};
} catch (error) {
console.log(error);
debugLogger.log(error);
return { packageManager: PackageManager.UNKNOWN, isGlobal: false };
}
}
+3 -1
View File
@@ -4,6 +4,8 @@
* SPDX-License-Identifier: Apache-2.0
*/
import { debugLogger } from '@google/gemini-cli-core';
export async function readStdin(): Promise<string> {
const MAX_STDIN_SIZE = 8 * 1024 * 1024; // 8MB
return new Promise((resolve, reject) => {
@@ -30,7 +32,7 @@ export async function readStdin(): Promise<string> {
if (totalSize + chunk.length > MAX_STDIN_SIZE) {
const remainingSize = MAX_STDIN_SIZE - totalSize;
data += chunk.slice(0, remainingSize);
console.warn(
debugLogger.warn(
`Warning: stdin input truncated to ${MAX_STDIN_SIZE} bytes.`,
);
process.stdin.destroy(); // Stop reading further
+17 -13
View File
@@ -14,7 +14,11 @@ import { quote, parse } from 'shell-quote';
import { USER_SETTINGS_DIR } from '../config/settings.js';
import { promisify } from 'node:util';
import type { Config, SandboxConfig } from '@google/gemini-cli-core';
import { FatalSandboxError, GEMINI_DIR } from '@google/gemini-cli-core';
import {
debugLogger,
FatalSandboxError,
GEMINI_DIR,
} from '@google/gemini-cli-core';
import { ConsolePatcher } from '../ui/utils/ConsolePatcher.js';
import { randomBytes } from 'node:crypto';
@@ -92,7 +96,7 @@ async function shouldUseCurrentUserInSandbox(): Promise<boolean> {
} catch (_err) {
// Silently ignore if /etc/os-release is not found or unreadable.
// The default (false) will be applied in this case.
console.warn(
debugLogger.warn(
'Warning: Could not read /etc/os-release to auto-detect Debian/Ubuntu for UID/GID default.',
);
}
@@ -301,7 +305,7 @@ export async function start_sandbox(
});
// install handlers to stop proxy on exit/signal
const stopProxy = () => {
console.log('stopping proxy ...');
debugLogger.log('stopping proxy ...');
if (proxyProcess?.pid) {
process.kill(-proxyProcess.pid, 'SIGTERM');
}
@@ -325,7 +329,7 @@ export async function start_sandbox(
`Proxy command '${proxyCommand}' exited with code ${code}, signal ${signal}`,
);
});
console.log('waiting for proxy to start ...');
debugLogger.log('waiting for proxy to start ...');
await execAsync(
`until timeout 0.25 curl -s http://localhost:8877; do sleep 0.25; done`,
);
@@ -559,7 +563,7 @@ export async function start_sandbox(
containerName = `gemini-cli-integration-test-${randomBytes(4).toString(
'hex',
)}`;
console.log(`ContainerName: ${containerName}`);
debugLogger.log(`ContainerName: ${containerName}`);
} else {
let index = 0;
const containerNameCheck = execSync(
@@ -571,7 +575,7 @@ export async function start_sandbox(
index++;
}
containerName = `${imageName}-${index}`;
console.log(`ContainerName (regular): ${containerName}`);
debugLogger.log(`ContainerName (regular): ${containerName}`);
}
args.push('--name', containerName, '--hostname', containerName);
@@ -773,7 +777,7 @@ export async function start_sandbox(
});
// install handlers to stop proxy on exit/signal
const stopProxy = () => {
console.log('stopping proxy container ...');
debugLogger.log('stopping proxy container ...');
execSync(`${config.command} rm -f ${SANDBOX_PROXY_NAME}`);
};
process.on('exit', stopProxy);
@@ -795,7 +799,7 @@ export async function start_sandbox(
`Proxy container command '${proxyContainerCommand}' exited with code ${code}, signal ${signal}`,
);
});
console.log('waiting for proxy to start ...');
debugLogger.log('waiting for proxy to start ...');
await execAsync(
`until timeout 0.25 curl -s http://localhost:8877; do sleep 0.25; done`,
);
@@ -821,7 +825,7 @@ export async function start_sandbox(
sandboxProcess?.on('close', (code, signal) => {
process.stdin.resume();
if (code !== 0 && code !== null) {
console.log(
debugLogger.log(
`Sandbox process exited with code: ${code}, signal: ${signal}`,
);
}
@@ -847,7 +851,7 @@ async function imageExists(sandbox: string, image: string): Promise<boolean> {
}
checkProcess.on('error', (err) => {
console.warn(
debugLogger.warn(
`Failed to start '${sandbox}' command for image check: ${err.message}`,
);
resolve(false);
@@ -882,7 +886,7 @@ async function pullImage(sandbox: string, image: string): Promise<boolean> {
};
const onError = (err: Error) => {
console.warn(
debugLogger.warn(
`Failed to start '${sandbox} pull ${image}' command: ${err.message}`,
);
cleanup();
@@ -895,7 +899,7 @@ async function pullImage(sandbox: string, image: string): Promise<boolean> {
cleanup();
resolve(true);
} else {
console.warn(
debugLogger.warn(
`Failed to pull image ${image}. '${sandbox} pull ${image}' exited with code ${code}.`,
);
if (stderrData.trim()) {
@@ -953,7 +957,7 @@ async function ensureSandboxImageIsPresent(
console.info(`Sandbox image ${image} is now available after pulling.`);
return true;
} else {
console.warn(
debugLogger.warn(
`Sandbox image ${image} still not found after a pull attempt. This might indicate an issue with the image name or registry, or the pull command reported success but failed to make the image available.`,
);
return false;
+4 -4
View File
@@ -6,7 +6,7 @@
import * as fs from 'node:fs/promises';
import * as path from 'node:path';
import { type Config } from '@google/gemini-cli-core';
import { debugLogger, type Config } from '@google/gemini-cli-core';
import type { Settings, SessionRetentionSettings } from '../config/settings.js';
import { getAllSessionFiles, type SessionFileEntry } from './sessionUtils.js';
@@ -88,11 +88,11 @@ export async function cleanupExpiredSessions(
if (config.getDebugMode()) {
if (sessionToDelete.sessionInfo === null) {
console.debug(
debugLogger.debug(
`Deleted corrupted session file: ${sessionToDelete.fileName}`,
);
} else {
console.debug(
debugLogger.debug(
`Deleted expired session: ${sessionToDelete.sessionInfo.id} (${sessionToDelete.sessionInfo.lastUpdated})`,
);
}
@@ -125,7 +125,7 @@ export async function cleanupExpiredSessions(
result.skipped = result.scanned - result.deleted - result.failed;
if (config.getDebugMode() && result.deleted > 0) {
console.debug(
debugLogger.debug(
`Session cleanup: deleted ${result.deleted}, skipped ${result.skipped}, failed ${result.failed}`,
);
}
@@ -53,10 +53,7 @@ describe('validateNonInterActiveAuth', () => {
throw new Error(`process.exit(${code}) called`);
});
vi.spyOn(auth, 'validateAuthMethod').mockReturnValue(null);
refreshAuthMock = vi.fn().mockImplementation(async () => {
console.log('DEBUG: refreshAuthMock called');
return 'refreshed';
});
refreshAuthMock = vi.fn().mockImplementation(async () => 'refreshed');
mockSettings = {
system: { path: '', settings: {} },
systemDefaults: { path: '', settings: {} },
@@ -30,6 +30,7 @@ import {
DEFAULT_GEMINI_MODEL,
DEFAULT_GEMINI_MODEL_AUTO,
DEFAULT_GEMINI_FLASH_MODEL,
debugLogger,
} from '@google/gemini-cli-core';
import * as acp from './acp.js';
import { AcpFileSystemService } from './fileSystemService.js';
@@ -592,7 +593,7 @@ class Session {
const reason = respectGitIgnore
? 'git-ignored and will be skipped'
: 'ignored by custom patterns';
console.warn(`Path ${pathName} is ${reason}.`);
debugLogger.warn(`Path ${pathName} is ${reason}.`);
continue;
}
let currentPathSpec = pathName;
@@ -739,7 +740,7 @@ class Session {
if (pathSpecsToRead.length === 0 && embeddedContext.length === 0) {
// Fallback for lone "@" or completely invalid @-commands resulting in empty initialQueryText
console.warn('No valid file paths found in @ commands to read.');
debugLogger.warn('No valid file paths found in @ commands to read.');
return [{ text: initialQueryText }];
}
@@ -802,7 +803,7 @@ class Session {
}
}
} else {
console.warn(
debugLogger.warn(
'read_many_files tool returned no content or empty content.',
);
}
@@ -855,7 +856,7 @@ class Session {
debug(msg: string) {
if (this.config.getDebugMode()) {
console.warn(msg);
debugLogger.warn(msg);
}
}
}