mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-05-12 12:54:07 -07:00
refactor(logging): Centralize all console messaging to a shared logger (part 1) (#11537)
This commit is contained in:
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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})`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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]: ',
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user