refactor(logging): Centralize all console messaging to a shared logger (part 1) (#11537)

This commit is contained in:
Abhi
2025-10-20 18:16:47 -04:00
committed by GitHub
parent d5a06d3cd2
commit 995ae717cc
18 changed files with 145 additions and 143 deletions
+5 -5
View File
@@ -8,7 +8,7 @@
import './src/gemini.js'; import './src/gemini.js';
import { main } from './src/gemini.js'; import { main } from './src/gemini.js';
import { FatalError } from '@google/gemini-cli-core'; import { debugLogger, FatalError } from '@google/gemini-cli-core';
// --- Global Entry Point --- // --- Global Entry Point ---
main().catch((error) => { main().catch((error) => {
@@ -17,14 +17,14 @@ main().catch((error) => {
if (!process.env['NO_COLOR']) { if (!process.env['NO_COLOR']) {
errorMessage = `\x1b[31m${errorMessage}\x1b[0m`; errorMessage = `\x1b[31m${errorMessage}\x1b[0m`;
} }
console.error(errorMessage); debugLogger.error(errorMessage);
process.exit(error.exitCode); process.exit(error.exitCode);
} }
console.error('An unexpected critical error occurred:'); debugLogger.error('An unexpected critical error occurred:');
if (error instanceof Error) { if (error instanceof Error) {
console.error(error.stack); debugLogger.error(error.stack);
} else { } else {
console.error(String(error)); debugLogger.error(String(error));
} }
process.exit(1); process.exit(1);
}); });
@@ -8,6 +8,7 @@ import { type CommandModule } from 'yargs';
import { disableExtension } from '../../config/extension.js'; import { disableExtension } from '../../config/extension.js';
import { SettingScope } from '../../config/settings.js'; import { SettingScope } from '../../config/settings.js';
import { getErrorMessage } from '../../utils/errors.js'; import { getErrorMessage } from '../../utils/errors.js';
import { debugLogger } from '@google/gemini-cli-core';
interface DisableArgs { interface DisableArgs {
name: string; name: string;
@@ -21,11 +22,11 @@ export function handleDisable(args: DisableArgs) {
} else { } else {
disableExtension(args.name, SettingScope.User); disableExtension(args.name, SettingScope.User);
} }
console.log( debugLogger.log(
`Extension "${args.name}" successfully disabled for scope "${args.scope}".`, `Extension "${args.name}" successfully disabled for scope "${args.scope}".`,
); );
} catch (error) { } catch (error) {
console.error(getErrorMessage(error)); debugLogger.error(getErrorMessage(error));
process.exit(1); process.exit(1);
} }
} }
@@ -10,7 +10,10 @@ import {
installOrUpdateExtension, installOrUpdateExtension,
requestConsentNonInteractive, requestConsentNonInteractive,
} from '../../config/extension.js'; } from '../../config/extension.js';
import type { ExtensionInstallMetadata } from '@google/gemini-cli-core'; import {
debugLogger,
type ExtensionInstallMetadata,
} from '@google/gemini-cli-core';
import { getErrorMessage } from '../../utils/errors.js'; import { getErrorMessage } from '../../utils/errors.js';
import { stat } from 'node:fs/promises'; import { stat } from 'node:fs/promises';
@@ -60,16 +63,16 @@ export async function handleInstall(args: InstallArgs) {
? () => Promise.resolve(true) ? () => Promise.resolve(true)
: requestConsentNonInteractive; : requestConsentNonInteractive;
if (args.consent) { if (args.consent) {
console.log('You have consented to the following:'); debugLogger.log('You have consented to the following:');
console.log(INSTALL_WARNING_MESSAGE); debugLogger.log(INSTALL_WARNING_MESSAGE);
} }
const name = await installOrUpdateExtension( const name = await installOrUpdateExtension(
installMetadata, installMetadata,
requestConsent, requestConsent,
); );
console.log(`Extension "${name}" installed successfully and enabled.`); debugLogger.log(`Extension "${name}" installed successfully and enabled.`);
} catch (error) { } catch (error) {
console.error(getErrorMessage(error)); debugLogger.error(getErrorMessage(error));
process.exit(1); process.exit(1);
} }
} }
+6 -3
View File
@@ -9,7 +9,10 @@ import {
installOrUpdateExtension, installOrUpdateExtension,
requestConsentNonInteractive, requestConsentNonInteractive,
} from '../../config/extension.js'; } from '../../config/extension.js';
import type { ExtensionInstallMetadata } from '@google/gemini-cli-core'; import {
debugLogger,
type ExtensionInstallMetadata,
} from '@google/gemini-cli-core';
import { getErrorMessage } from '../../utils/errors.js'; import { getErrorMessage } from '../../utils/errors.js';
@@ -27,11 +30,11 @@ export async function handleLink(args: InstallArgs) {
installMetadata, installMetadata,
requestConsentNonInteractive, requestConsentNonInteractive,
); );
console.log( debugLogger.log(
`Extension "${extensionName}" linked successfully and enabled.`, `Extension "${extensionName}" linked successfully and enabled.`,
); );
} catch (error) { } catch (error) {
console.error(getErrorMessage(error)); debugLogger.error(getErrorMessage(error));
process.exit(1); process.exit(1);
} }
} }
+4 -3
View File
@@ -8,6 +8,7 @@ import type { CommandModule } from 'yargs';
import { loadExtensions, toOutputString } from '../../config/extension.js'; import { loadExtensions, toOutputString } from '../../config/extension.js';
import { getErrorMessage } from '../../utils/errors.js'; import { getErrorMessage } from '../../utils/errors.js';
import { ExtensionEnablementManager } from '../../config/extensions/extensionEnablement.js'; import { ExtensionEnablementManager } from '../../config/extensions/extensionEnablement.js';
import { debugLogger } from '@google/gemini-cli-core';
export async function handleList() { export async function handleList() {
try { try {
@@ -16,16 +17,16 @@ export async function handleList() {
process.cwd(), process.cwd(),
); );
if (extensions.length === 0) { if (extensions.length === 0) {
console.log('No extensions installed.'); debugLogger.log('No extensions installed.');
return; return;
} }
console.log( debugLogger.log(
extensions extensions
.map((extension, _): string => toOutputString(extension, process.cwd())) .map((extension, _): string => toOutputString(extension, process.cwd()))
.join('\n\n'), .join('\n\n'),
); );
} catch (error) { } catch (error) {
console.error(getErrorMessage(error)); debugLogger.error(getErrorMessage(error));
process.exit(1); process.exit(1);
} }
} }
+20 -25
View File
@@ -8,7 +8,7 @@ import { access, cp, mkdir, readdir, writeFile } from 'node:fs/promises';
import { join, dirname, basename } from 'node:path'; import { join, dirname, basename } from 'node:path';
import type { CommandModule } from 'yargs'; import type { CommandModule } from 'yargs';
import { fileURLToPath } from 'node:url'; import { fileURLToPath } from 'node:url';
import { getErrorMessage } from '../../utils/errors.js'; import { debugLogger } from '@google/gemini-cli-core';
interface NewArgs { interface NewArgs {
path: string; path: string;
@@ -49,32 +49,27 @@ async function copyDirectory(template: string, path: string) {
} }
async function handleNew(args: NewArgs) { async function handleNew(args: NewArgs) {
try { if (args.template) {
if (args.template) { await copyDirectory(args.template, args.path);
await copyDirectory(args.template, args.path); debugLogger.log(
console.log( `Successfully created new extension from template "${args.template}" at ${args.path}.`,
`Successfully created new extension from template "${args.template}" at ${args.path}.`,
);
} else {
await createDirectory(args.path);
const extensionName = basename(args.path);
const manifest = {
name: extensionName,
version: '1.0.0',
};
await writeFile(
join(args.path, 'gemini-extension.json'),
JSON.stringify(manifest, null, 2),
);
console.log(`Successfully created new extension at ${args.path}.`);
}
console.log(
`You can install this using "gemini extensions link ${args.path}" to test it out.`,
); );
} catch (error) { } else {
console.error(getErrorMessage(error)); await createDirectory(args.path);
throw error; const extensionName = basename(args.path);
const manifest = {
name: extensionName,
version: '1.0.0',
};
await writeFile(
join(args.path, 'gemini-extension.json'),
JSON.stringify(manifest, null, 2),
);
debugLogger.log(`Successfully created new extension at ${args.path}.`);
} }
debugLogger.log(
`You can install this using "gemini extensions link ${args.path}" to test it out.`,
);
} }
async function getBoilerplateChoices() { async function getBoilerplateChoices() {
@@ -7,6 +7,7 @@
import type { CommandModule } from 'yargs'; import type { CommandModule } from 'yargs';
import { uninstallExtension } from '../../config/extension.js'; import { uninstallExtension } from '../../config/extension.js';
import { getErrorMessage } from '../../utils/errors.js'; import { getErrorMessage } from '../../utils/errors.js';
import { debugLogger } from '@google/gemini-cli-core';
interface UninstallArgs { interface UninstallArgs {
name: string; // can be extension name or source URL. name: string; // can be extension name or source URL.
@@ -15,9 +16,9 @@ interface UninstallArgs {
export async function handleUninstall(args: UninstallArgs) { export async function handleUninstall(args: UninstallArgs) {
try { try {
await uninstallExtension(args.name, false); await uninstallExtension(args.name, false);
console.log(`Extension "${args.name}" successfully uninstalled.`); debugLogger.log(`Extension "${args.name}" successfully uninstalled.`);
} catch (error) { } catch (error) {
console.error(getErrorMessage(error)); debugLogger.error(getErrorMessage(error));
process.exit(1); process.exit(1);
} }
} }
+10 -9
View File
@@ -20,6 +20,7 @@ import { checkForExtensionUpdate } from '../../config/extensions/github.js';
import { getErrorMessage } from '../../utils/errors.js'; import { getErrorMessage } from '../../utils/errors.js';
import { ExtensionUpdateState } from '../../ui/state/extensions.js'; import { ExtensionUpdateState } from '../../ui/state/extensions.js';
import { ExtensionEnablementManager } from '../../config/extensions/extensionEnablement.js'; import { ExtensionEnablementManager } from '../../config/extensions/extensionEnablement.js';
import { debugLogger } from '@google/gemini-cli-core';
interface UpdateArgs { interface UpdateArgs {
name?: string; name?: string;
@@ -48,18 +49,18 @@ export async function handleUpdate(args: UpdateArgs) {
(extension) => extension.name === args.name, (extension) => extension.name === args.name,
); );
if (!extension) { if (!extension) {
console.log(`Extension "${args.name}" not found.`); debugLogger.log(`Extension "${args.name}" not found.`);
return; return;
} }
if (!extension.installMetadata) { if (!extension.installMetadata) {
console.log( debugLogger.log(
`Unable to install extension "${args.name}" due to missing install metadata`, `Unable to install extension "${args.name}" due to missing install metadata`,
); );
return; return;
} }
const updateState = await checkForExtensionUpdate(extension); const updateState = await checkForExtensionUpdate(extension);
if (updateState !== ExtensionUpdateState.UPDATE_AVAILABLE) { if (updateState !== ExtensionUpdateState.UPDATE_AVAILABLE) {
console.log(`Extension "${args.name}" is already up to date.`); debugLogger.log(`Extension "${args.name}" is already up to date.`);
return; return;
} }
// TODO(chrstnb): we should list extensions if the requested extension is not installed. // TODO(chrstnb): we should list extensions if the requested extension is not installed.
@@ -74,14 +75,14 @@ export async function handleUpdate(args: UpdateArgs) {
updatedExtensionInfo.originalVersion !== updatedExtensionInfo.originalVersion !==
updatedExtensionInfo.updatedVersion updatedExtensionInfo.updatedVersion
) { ) {
console.log( debugLogger.log(
`Extension "${args.name}" successfully updated: ${updatedExtensionInfo.originalVersion}${updatedExtensionInfo.updatedVersion}.`, `Extension "${args.name}" successfully updated: ${updatedExtensionInfo.originalVersion}${updatedExtensionInfo.updatedVersion}.`,
); );
} else { } else {
console.log(`Extension "${args.name}" is already up to date.`); debugLogger.log(`Extension "${args.name}" is already up to date.`);
} }
} catch (error) { } catch (error) {
console.error(getErrorMessage(error)); debugLogger.error(getErrorMessage(error));
} }
} }
if (args.all) { if (args.all) {
@@ -109,12 +110,12 @@ export async function handleUpdate(args: UpdateArgs) {
(info) => info.originalVersion !== info.updatedVersion, (info) => info.originalVersion !== info.updatedVersion,
); );
if (updateInfos.length === 0) { if (updateInfos.length === 0) {
console.log('No extensions to update.'); debugLogger.log('No extensions to update.');
return; return;
} }
console.log(updateInfos.map((info) => updateOutput(info)).join('\n')); debugLogger.log(updateInfos.map((info) => updateOutput(info)).join('\n'));
} catch (error) { } catch (error) {
console.error(getErrorMessage(error)); debugLogger.error(getErrorMessage(error));
} }
} }
} }
+5 -5
View File
@@ -7,7 +7,7 @@
// File for 'gemini mcp add' command // File for 'gemini mcp add' command
import type { CommandModule } from 'yargs'; import type { CommandModule } from 'yargs';
import { loadSettings, SettingScope } from '../../config/settings.js'; import { loadSettings, SettingScope } from '../../config/settings.js';
import type { MCPServerConfig } from '@google/gemini-cli-core'; import { debugLogger, type MCPServerConfig } from '@google/gemini-cli-core';
async function addMcpServer( async function addMcpServer(
name: string, name: string,
@@ -41,7 +41,7 @@ async function addMcpServer(
const inHome = settings.workspace.path === settings.user.path; const inHome = settings.workspace.path === settings.user.path;
if (scope === 'project' && inHome) { if (scope === 'project' && inHome) {
console.error( debugLogger.error(
'Error: Please use --scope user to edit settings in the home directory.', 'Error: Please use --scope user to edit settings in the home directory.',
); );
process.exit(1); process.exit(1);
@@ -116,7 +116,7 @@ async function addMcpServer(
const isExistingServer = !!mcpServers[name]; const isExistingServer = !!mcpServers[name];
if (isExistingServer) { if (isExistingServer) {
console.log( debugLogger.log(
`MCP server "${name}" is already configured within ${scope} settings.`, `MCP server "${name}" is already configured within ${scope} settings.`,
); );
} }
@@ -126,9 +126,9 @@ async function addMcpServer(
settings.setValue(settingsScope, 'mcpServers', mcpServers); settings.setValue(settingsScope, 'mcpServers', mcpServers);
if (isExistingServer) { if (isExistingServer) {
console.log(`MCP server "${name}" updated in ${scope} settings.`); debugLogger.log(`MCP server "${name}" updated in ${scope} settings.`);
} else { } else {
console.log( debugLogger.log(
`MCP server "${name}" added to ${scope} settings. (${transport})`, `MCP server "${name}" added to ${scope} settings. (${transport})`,
); );
} }
+5 -14
View File
@@ -36,6 +36,7 @@ import {
FatalConfigError, FatalConfigError,
getPty, getPty,
EDIT_TOOL_NAME, EDIT_TOOL_NAME,
debugLogger,
} from '@google/gemini-cli-core'; } from '@google/gemini-cli-core';
import type { Settings } from './settings.js'; import type { Settings } from './settings.js';
@@ -49,16 +50,6 @@ import { isWorkspaceTrusted } from './trustedFolders.js';
import { createPolicyEngineConfig } from './policy.js'; import { createPolicyEngineConfig } from './policy.js';
import type { ExtensionEnablementManager } from './extensions/extensionEnablement.js'; import type { ExtensionEnablementManager } from './extensions/extensionEnablement.js';
// Simple console logger for now - replace with actual logger if available
const logger = {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
debug: (...args: any[]) => console.debug('[DEBUG]', ...args),
// eslint-disable-next-line @typescript-eslint/no-explicit-any
warn: (...args: any[]) => console.warn('[WARN]', ...args),
// eslint-disable-next-line @typescript-eslint/no-explicit-any
error: (...args: any[]) => console.error('[ERROR]', ...args),
};
export interface CliArgs { export interface CliArgs {
query: string | undefined; query: string | undefined;
model: string | undefined; model: string | undefined;
@@ -210,7 +201,7 @@ export async function parseArguments(settings: Settings): Promise<CliArgs> {
) )
// Ensure validation flows through .fail() for clean UX // Ensure validation flows through .fail() for clean UX
.fail((msg, err, yargs) => { .fail((msg, err, yargs) => {
console.error(msg || err?.message || 'Unknown error'); debugLogger.error(msg || err?.message || 'Unknown error');
yargs.showHelp(); yargs.showHelp();
process.exit(1); process.exit(1);
}) })
@@ -313,7 +304,7 @@ export async function loadHierarchicalGeminiMemory(
const effectiveCwd = isHomeDirectory ? '' : currentWorkingDirectory; const effectiveCwd = isHomeDirectory ? '' : currentWorkingDirectory;
if (debugMode) { if (debugMode) {
logger.debug( debugLogger.debug(
`CLI: Delegating hierarchical memory load to server for CWD: ${currentWorkingDirectory} (memoryImportFormat: ${memoryImportFormat})`, `CLI: Delegating hierarchical memory load to server for CWD: ${currentWorkingDirectory} (memoryImportFormat: ${memoryImportFormat})`,
); );
} }
@@ -470,7 +461,7 @@ export async function loadCliConfig(
// Force approval mode to default if the folder is not trusted. // Force approval mode to default if the folder is not trusted.
if (!trustedFolder && approvalMode !== ApprovalMode.DEFAULT) { if (!trustedFolder && approvalMode !== ApprovalMode.DEFAULT) {
logger.warn( debugLogger.warn(
`Approval mode overridden to "default" because the current folder is not trusted.`, `Approval mode overridden to "default" because the current folder is not trusted.`,
); );
approvalMode = ApprovalMode.DEFAULT; approvalMode = ApprovalMode.DEFAULT;
@@ -700,7 +691,7 @@ function mergeMcpServers(settings: Settings, extensions: GeminiCLIExtension[]) {
for (const extension of extensions) { for (const extension of extensions) {
Object.entries(extension.mcpServers || {}).forEach(([key, server]) => { Object.entries(extension.mcpServers || {}).forEach(([key, server]) => {
if (mcpServers[key]) { if (mcpServers[key]) {
logger.warn( debugLogger.warn(
`Skipping extension MCP config for server with key "${key}" as it already exists.`, `Skipping extension MCP config for server with key "${key}" as it already exists.`,
); );
return; return;
+3 -2
View File
@@ -23,6 +23,7 @@ import {
logExtensionUninstall, logExtensionUninstall,
logExtensionUpdateEvent, logExtensionUpdateEvent,
logExtensionDisable, logExtensionDisable,
debugLogger,
} from '@google/gemini-cli-core'; } from '@google/gemini-cli-core';
import * as fs from 'node:fs'; import * as fs from 'node:fs';
import * as path from 'node:path'; import * as path from 'node:path';
@@ -233,7 +234,7 @@ export function loadExtension(
id, id,
}; };
} catch (e) { } catch (e) {
console.error( debugLogger.error(
`Warning: Skipping extension in ${effectiveExtensionPath}: ${getErrorMessage( `Warning: Skipping extension in ${effectiveExtensionPath}: ${getErrorMessage(
e, e,
)}`, )}`,
@@ -324,7 +325,7 @@ export function annotateActiveExtensions(
export async function requestConsentNonInteractive( export async function requestConsentNonInteractive(
consentDescription: string, consentDescription: string,
): Promise<boolean> { ): Promise<boolean> {
console.info(consentDescription); debugLogger.log(consentDescription);
const result = await promptForConsentNonInteractive( const result = await promptForConsentNonInteractive(
'Do you want to continue? [Y/n]: ', 'Do you want to continue? [Y/n]: ',
); );
+14 -11
View File
@@ -6,9 +6,10 @@
import { simpleGit } from 'simple-git'; import { simpleGit } from 'simple-git';
import { getErrorMessage } from '../../utils/errors.js'; import { getErrorMessage } from '../../utils/errors.js';
import type { import {
ExtensionInstallMetadata, debugLogger,
GeminiCLIExtension, type ExtensionInstallMetadata,
type GeminiCLIExtension,
} from '@google/gemini-cli-core'; } from '@google/gemini-cli-core';
import { ExtensionUpdateState } from '../../ui/state/extensions.js'; import { ExtensionUpdateState } from '../../ui/state/extensions.js';
import * as os from 'node:os'; import * as os from 'node:os';
@@ -160,7 +161,7 @@ export async function checkForExtensionUpdate(
workspaceDir: cwd, workspaceDir: cwd,
}); });
if (!newExtension) { if (!newExtension) {
console.error( debugLogger.error(
`Failed to check for update for local extension "${extension.name}". Could not load extension from source path: ${installMetadata.source}`, `Failed to check for update for local extension "${extension.name}". Could not load extension from source path: ${installMetadata.source}`,
); );
return ExtensionUpdateState.ERROR; return ExtensionUpdateState.ERROR;
@@ -182,12 +183,14 @@ export async function checkForExtensionUpdate(
const git = simpleGit(extension.path); const git = simpleGit(extension.path);
const remotes = await git.getRemotes(true); const remotes = await git.getRemotes(true);
if (remotes.length === 0) { if (remotes.length === 0) {
console.error('No git remotes found.'); debugLogger.error('No git remotes found.');
return ExtensionUpdateState.ERROR; return ExtensionUpdateState.ERROR;
} }
const remoteUrl = remotes[0].refs.fetch; const remoteUrl = remotes[0].refs.fetch;
if (!remoteUrl) { if (!remoteUrl) {
console.error(`No fetch URL found for git remote ${remotes[0].name}.`); debugLogger.error(
`No fetch URL found for git remote ${remotes[0].name}.`,
);
return ExtensionUpdateState.ERROR; return ExtensionUpdateState.ERROR;
} }
@@ -197,7 +200,7 @@ export async function checkForExtensionUpdate(
const lsRemoteOutput = await git.listRemote([remoteUrl, refToCheck]); const lsRemoteOutput = await git.listRemote([remoteUrl, refToCheck]);
if (typeof lsRemoteOutput !== 'string' || lsRemoteOutput.trim() === '') { if (typeof lsRemoteOutput !== 'string' || lsRemoteOutput.trim() === '') {
console.error(`Git ref ${refToCheck} not found.`); debugLogger.error(`Git ref ${refToCheck} not found.`);
return ExtensionUpdateState.ERROR; return ExtensionUpdateState.ERROR;
} }
@@ -205,7 +208,7 @@ export async function checkForExtensionUpdate(
const localHash = await git.revparse(['HEAD']); const localHash = await git.revparse(['HEAD']);
if (!remoteHash) { if (!remoteHash) {
console.error( debugLogger.error(
`Unable to parse hash from git ls-remote output "${lsRemoteOutput}"`, `Unable to parse hash from git ls-remote output "${lsRemoteOutput}"`,
); );
return ExtensionUpdateState.ERROR; return ExtensionUpdateState.ERROR;
@@ -217,12 +220,12 @@ export async function checkForExtensionUpdate(
} else { } else {
const { source, releaseTag } = installMetadata; const { source, releaseTag } = installMetadata;
if (!source) { if (!source) {
console.error(`No "source" provided for extension.`); debugLogger.error(`No "source" provided for extension.`);
return ExtensionUpdateState.ERROR; return ExtensionUpdateState.ERROR;
} }
const repoInfo = tryParseGithubUrl(source); const repoInfo = tryParseGithubUrl(source);
if (!repoInfo) { if (!repoInfo) {
console.error( debugLogger.error(
`Source is not a valid GitHub repository for release checks: ${source}`, `Source is not a valid GitHub repository for release checks: ${source}`,
); );
return ExtensionUpdateState.ERROR; return ExtensionUpdateState.ERROR;
@@ -244,7 +247,7 @@ export async function checkForExtensionUpdate(
return ExtensionUpdateState.UP_TO_DATE; return ExtensionUpdateState.UP_TO_DATE;
} }
} catch (error) { } catch (error) {
console.error( debugLogger.error(
`Failed to check for updates for extension "${installMetadata.source}": ${getErrorMessage(error)}`, `Failed to check for updates for extension "${installMetadata.source}": ${getErrorMessage(error)}`,
); );
return ExtensionUpdateState.ERROR; return ExtensionUpdateState.ERROR;
+2 -2
View File
@@ -18,7 +18,7 @@ import {
loadExtensionConfig, loadExtensionConfig,
} from '../extension.js'; } from '../extension.js';
import { checkForExtensionUpdate } from './github.js'; import { checkForExtensionUpdate } from './github.js';
import type { GeminiCLIExtension } from '@google/gemini-cli-core'; import { debugLogger, type GeminiCLIExtension } from '@google/gemini-cli-core';
import * as fs from 'node:fs'; import * as fs from 'node:fs';
import { getErrorMessage } from '../../utils/errors.js'; import { getErrorMessage } from '../../utils/errors.js';
@@ -101,7 +101,7 @@ export async function updateExtension(
updatedVersion, updatedVersion,
}; };
} catch (e) { } catch (e) {
console.error( debugLogger.error(
`Error updating extension, rolling back. ${getErrorMessage(e)}`, `Error updating extension, rolling back. ${getErrorMessage(e)}`,
); );
dispatchExtensionStateUpdate({ dispatchExtensionStateUpdate({
+14 -11
View File
@@ -40,6 +40,7 @@ import {
AuthType, AuthType,
getOauthClient, getOauthClient,
UserPromptEvent, UserPromptEvent,
debugLogger,
} from '@google/gemini-cli-core'; } from '@google/gemini-cli-core';
import { import {
initializeApp, initializeApp,
@@ -79,7 +80,7 @@ export function validateDnsResolutionOrder(
return order; return order;
} }
// We don't want to throw here, just warn and use the default. // We don't want to throw here, just warn and use the default.
console.warn( debugLogger.warn(
`Invalid value for dnsResolutionOrder in settings: "${order}". Using default "${defaultValue}".`, `Invalid value for dnsResolutionOrder in settings: "${order}". Using default "${defaultValue}".`,
); );
return defaultValue; return defaultValue;
@@ -95,7 +96,7 @@ function getNodeMemoryArgs(isDebugMode: boolean): string[] {
// Set target to 50% of total memory // Set target to 50% of total memory
const targetMaxOldSpaceSizeInMB = Math.floor(totalMemoryMB * 0.5); const targetMaxOldSpaceSizeInMB = Math.floor(totalMemoryMB * 0.5);
if (isDebugMode) { if (isDebugMode) {
console.debug( debugLogger.debug(
`Current heap size ${currentMaxOldSpaceSizeMb.toFixed(2)} MB`, `Current heap size ${currentMaxOldSpaceSizeMb.toFixed(2)} MB`,
); );
} }
@@ -106,7 +107,7 @@ function getNodeMemoryArgs(isDebugMode: boolean): string[] {
if (targetMaxOldSpaceSizeInMB > currentMaxOldSpaceSizeMb) { if (targetMaxOldSpaceSizeInMB > currentMaxOldSpaceSizeMb) {
if (isDebugMode) { if (isDebugMode) {
console.debug( debugLogger.debug(
`Need to relaunch with more memory: ${targetMaxOldSpaceSizeInMB.toFixed(2)} MB`, `Need to relaunch with more memory: ${targetMaxOldSpaceSizeInMB.toFixed(2)} MB`,
); );
} }
@@ -213,7 +214,7 @@ export async function startInteractiveUI(
.catch((err) => { .catch((err) => {
// Silently ignore update check errors. // Silently ignore update check errors.
if (config.getDebugMode()) { if (config.getDebugMode()) {
console.error('Update check failed:', err); debugLogger.warn('Update check failed:', err);
} }
}); });
@@ -230,7 +231,7 @@ export async function main() {
// Check for invalid input combinations early to prevent crashes // Check for invalid input combinations early to prevent crashes
if (argv.promptInteractive && !process.stdin.isTTY) { if (argv.promptInteractive && !process.stdin.isTTY) {
console.error( debugLogger.error(
'Error: The --prompt-interactive flag cannot be used when input is piped from stdin.', 'Error: The --prompt-interactive flag cannot be used when input is piped from stdin.',
); );
process.exit(1); process.exit(1);
@@ -266,7 +267,9 @@ export async function main() {
if (!themeManager.setActiveTheme(settings.merged.ui?.theme)) { if (!themeManager.setActiveTheme(settings.merged.ui?.theme)) {
// If the theme is not found during initial load, log a warning and continue. // If the theme is not found during initial load, log a warning and continue.
// The useThemeCommand hook in AppContainer.tsx will handle opening the dialog. // The useThemeCommand hook in AppContainer.tsx will handle opening the dialog.
console.warn(`Warning: Theme "${settings.merged.ui?.theme}" not found.`); debugLogger.warn(
`Warning: Theme "${settings.merged.ui?.theme}" not found.`,
);
} }
} }
@@ -308,7 +311,7 @@ export async function main() {
settings.merged.security.auth.selectedType, settings.merged.security.auth.selectedType,
); );
} catch (err) { } catch (err) {
console.error('Error authenticating:', err); debugLogger.error('Error authenticating:', err);
process.exit(1); process.exit(1);
} }
} }
@@ -373,9 +376,9 @@ export async function main() {
await cleanupExpiredSessions(config, settings.merged); await cleanupExpiredSessions(config, settings.merged);
if (config.getListExtensions()) { if (config.getListExtensions()) {
console.log('Installed extensions:'); debugLogger.log('Installed extensions:');
for (const extension of extensions) { for (const extension of extensions) {
console.log(`- ${extension.name}`); debugLogger.log(`- ${extension.name}`);
} }
process.exit(0); process.exit(0);
} }
@@ -443,7 +446,7 @@ export async function main() {
} }
} }
if (!input) { if (!input) {
console.error( debugLogger.error(
`No input provided via stdin. Input can be provided by piping data into gemini or using the --prompt option.`, `No input provided via stdin. Input can be provided by piping data into gemini or using the --prompt option.`,
); );
process.exit(1); process.exit(1);
@@ -468,7 +471,7 @@ export async function main() {
); );
if (config.getDebugMode()) { if (config.getDebugMode()) {
console.log('Session ID: %s', sessionId); debugLogger.log('Session ID: %s', sessionId);
} }
await runNonInteractive(nonInteractiveConfig, settings, input, prompt_id); await runNonInteractive(nonInteractiveConfig, settings, input, prompt_id);
+2 -1
View File
@@ -23,6 +23,7 @@ import {
StreamJsonFormatter, StreamJsonFormatter,
JsonStreamEventType, JsonStreamEventType,
uiTelemetryService, uiTelemetryService,
debugLogger,
} from '@google/gemini-cli-core'; } from '@google/gemini-cli-core';
import type { Content, Part } from '@google/genai'; import type { Content, Part } from '@google/genai';
@@ -255,7 +256,7 @@ export async function runNonInteractive(
.getChat() .getChat()
.recordCompletedToolCalls(currentModel, completedToolCalls); .recordCompletedToolCalls(currentModel, completedToolCalls);
} catch (error) { } catch (error) {
console.error( debugLogger.error(
`Error recording completed tool call information: ${error}`, `Error recording completed tool call information: ${error}`,
); );
} }
@@ -5,6 +5,7 @@
*/ */
import { import {
debugLogger,
flatMapTextParts, flatMapTextParts,
readPathFromWorkspace, readPathFromWorkspace,
} from '@google/gemini-cli-core'; } from '@google/gemini-cli-core';
@@ -68,8 +69,9 @@ export class AtFileProcessor implements IPromptProcessor {
error instanceof Error ? error.message : String(error); error instanceof Error ? error.message : String(error);
const uiMessage = `Failed to inject content for '@{${pathStr}}': ${message}`; const uiMessage = `Failed to inject content for '@{${pathStr}}': ${message}`;
console.error( // `context.invocation` should always be present at this point.
`[AtFileProcessor] ${uiMessage}. Leaving placeholder in prompt.`, debugLogger.error(
`Error while loading custom command (${context.invocation!.name}) ${uiMessage}. Leaving placeholder in prompt.`,
); );
context.ui.addItem( context.ui.addItem(
{ type: MessageType.ERROR, text: uiMessage }, { type: MessageType.ERROR, text: uiMessage },
@@ -5,7 +5,7 @@
*/ */
import type { Config } from '@google/gemini-cli-core'; import type { Config } from '@google/gemini-cli-core';
import { AuthType, OutputFormat } from '@google/gemini-cli-core'; import { AuthType, debugLogger, OutputFormat } from '@google/gemini-cli-core';
import { USER_SETTINGS_PATH } from './config/settings.js'; import { USER_SETTINGS_PATH } from './config/settings.js';
import { validateAuthMethod } from './config/auth.js'; import { validateAuthMethod } from './config/auth.js';
import { type LoadedSettings } from './config/settings.js'; import { type LoadedSettings } from './config/settings.js';
@@ -65,7 +65,7 @@ export async function validateNonInteractiveAuth(
1, 1,
); );
} else { } else {
console.error(error instanceof Error ? error.message : String(error)); debugLogger.error(error instanceof Error ? error.message : String(error));
process.exit(1); process.exit(1);
} }
} }
+35 -39
View File
@@ -5,6 +5,7 @@
*/ */
import { execSync, spawn, spawnSync } from 'node:child_process'; import { execSync, spawn, spawnSync } from 'node:child_process';
import { debugLogger } from './debugLogger.js';
export type EditorType = export type EditorType =
| 'vscode' | 'vscode'
@@ -168,50 +169,45 @@ export async function openDiff(
): Promise<void> { ): Promise<void> {
const diffCommand = getDiffCommand(oldPath, newPath, editor); const diffCommand = getDiffCommand(oldPath, newPath, editor);
if (!diffCommand) { if (!diffCommand) {
console.error('No diff tool available. Install a supported editor.'); debugLogger.error('No diff tool available. Install a supported editor.');
return; return;
} }
try { const isTerminalEditor = ['vim', 'emacs', 'neovim'].includes(editor);
const isTerminalEditor = ['vim', 'emacs', 'neovim'].includes(editor);
if (isTerminalEditor) { if (isTerminalEditor) {
try { try {
const result = spawnSync(diffCommand.command, diffCommand.args, { const result = spawnSync(diffCommand.command, diffCommand.args, {
stdio: 'inherit',
});
if (result.error) {
throw result.error;
}
if (result.status !== 0) {
throw new Error(`${editor} exited with code ${result.status}`);
}
} finally {
onEditorClose();
}
return;
}
return new Promise<void>((resolve, reject) => {
const childProcess = spawn(diffCommand.command, diffCommand.args, {
stdio: 'inherit', stdio: 'inherit',
shell: process.platform === 'win32',
}); });
if (result.error) {
childProcess.on('close', (code) => { throw result.error;
if (code === 0) { }
resolve(); if (result.status !== 0) {
} else { throw new Error(`${editor} exited with code ${result.status}`);
reject(new Error(`${editor} exited with code ${code}`)); }
} } finally {
}); onEditorClose();
}
childProcess.on('error', (error) => { return;
reject(error);
});
});
} catch (error) {
console.error(error);
throw error;
} }
return new Promise<void>((resolve, reject) => {
const childProcess = spawn(diffCommand.command, diffCommand.args, {
stdio: 'inherit',
shell: process.platform === 'win32',
});
childProcess.on('close', (code) => {
if (code === 0) {
resolve();
} else {
reject(new Error(`${editor} exited with code ${code}`));
}
});
childProcess.on('error', (error) => {
reject(error);
});
});
} }