mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-03-10 22:21:22 -07:00
This change adds an optional `gitCommitInfo` string to the app state, which, if set by the GET_COMMIT_INFO environment variable when the application is launched, will be displayed in the /about section. The `start.sh` and `build_package.sh` scripts set `GET_COMMIT_INFO` to the most recent git commit's short hash if known, appending the string "(local modifications)" if additional changes are detected beyond that point.
139 lines
4.5 KiB
TypeScript
139 lines
4.5 KiB
TypeScript
/**
|
|
* @license
|
|
* Copyright 2025 Google LLC
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
import React from 'react';
|
|
import { render } from 'ink';
|
|
import { App } from './ui/App.js';
|
|
import { loadCliConfig } from './config/config.js';
|
|
import { readStdin } from './utils/readStdin.js';
|
|
import { GeminiClient } from '@gemini-code/server';
|
|
import { readPackageUp } from 'read-package-up';
|
|
import { fileURLToPath } from 'node:url';
|
|
import { dirname } from 'node:path';
|
|
import { sandbox_command, start_sandbox } from './utils/sandbox.js';
|
|
import { loadSettings } from './config/settings.js';
|
|
import { themeManager } from './ui/themes/theme-manager.js';
|
|
import { getStartupWarnings } from './utils/startupWarnings.js';
|
|
|
|
const __filename = fileURLToPath(import.meta.url);
|
|
const __dirname = dirname(__filename);
|
|
|
|
async function main() {
|
|
const settings = loadSettings(process.cwd());
|
|
const config = await loadCliConfig(settings.merged);
|
|
|
|
// warn about deprecated environment variables
|
|
if (process.env.GEMINI_CODE_MODEL) {
|
|
console.warn('GEMINI_CODE_MODEL is deprecated. Use GEMINI_MODEL instead.');
|
|
process.env.GEMINI_MODEL = process.env.GEMINI_CODE_MODEL;
|
|
}
|
|
if (process.env.GEMINI_CODE_SANDBOX) {
|
|
console.warn(
|
|
'GEMINI_CODE_SANDBOX is deprecated. Use GEMINI_SANDBOX instead.',
|
|
);
|
|
process.env.GEMINI_SANDBOX = process.env.GEMINI_CODE_SANDBOX;
|
|
}
|
|
if (process.env.GEMINI_CODE_SANDBOX_IMAGE) {
|
|
console.warn(
|
|
'GEMINI_CODE_SANDBOX_IMAGE is deprecated. Use GEMINI_SANDBOX_IMAGE_NAME instead.',
|
|
);
|
|
process.env.GEMINI_SANDBOX_IMAGE = process.env.GEMINI_CODE_SANDBOX_IMAGE;
|
|
}
|
|
|
|
if (settings.merged.theme) {
|
|
if (!themeManager.setActiveTheme(settings.merged.theme)) {
|
|
// If the theme is not found during initial load, log a warning and continue.
|
|
// The useThemeCommand hook in App.tsx will handle opening the dialog.
|
|
console.warn(`Warning: Theme "${settings.merged.theme}" not found.`);
|
|
}
|
|
}
|
|
|
|
// hop into sandbox if we are outside and sandboxing is enabled
|
|
if (!process.env.SANDBOX) {
|
|
const sandbox = sandbox_command(config.getSandbox());
|
|
if (sandbox) {
|
|
await start_sandbox(sandbox);
|
|
process.exit(0);
|
|
}
|
|
}
|
|
|
|
let input = config.getQuestion();
|
|
const startupWarnings = await getStartupWarnings();
|
|
|
|
// Render UI, passing necessary config values. Check that there is no command line question.
|
|
if (process.stdin.isTTY && input?.length === 0) {
|
|
const readUpResult = await readPackageUp({ cwd: __dirname });
|
|
const cliVersion =
|
|
process.env.CLI_VERSION || readUpResult?.packageJson.version || 'unknown';
|
|
const gitCommitInfo = process.env.GIT_COMMIT_INFO || 'N/A';
|
|
|
|
render(
|
|
React.createElement(App, {
|
|
config,
|
|
settings,
|
|
cliVersion,
|
|
gitCommitInfo,
|
|
startupWarnings,
|
|
}),
|
|
);
|
|
return;
|
|
}
|
|
// If not a TTY, read from stdin
|
|
// This is for cases where the user pipes input directly into the command
|
|
if (!process.stdin.isTTY) {
|
|
input += await readStdin();
|
|
}
|
|
if (!input) {
|
|
console.error('No input provided via stdin.');
|
|
process.exit(1);
|
|
}
|
|
|
|
// If not a TTY and we have initial input, process it directly
|
|
const geminiClient = new GeminiClient(config);
|
|
const chat = await geminiClient.startChat();
|
|
try {
|
|
for await (const event of geminiClient.sendMessageStream(chat, [
|
|
{ text: input },
|
|
])) {
|
|
if (event.type === 'content') {
|
|
process.stdout.write(event.value);
|
|
}
|
|
// We might need to handle other event types later, but for now, just content.
|
|
}
|
|
process.stdout.write('\n'); // Add a newline at the end
|
|
process.exit(0);
|
|
} catch (error) {
|
|
console.error('Error processing piped input:', error);
|
|
process.exit(1);
|
|
}
|
|
}
|
|
|
|
// --- Global Unhandled Rejection Handler ---
|
|
process.on('unhandledRejection', (reason, _promise) => {
|
|
// Log other unexpected unhandled rejections as critical errors
|
|
console.error('=========================================');
|
|
console.error('CRITICAL: Unhandled Promise Rejection!');
|
|
console.error('=========================================');
|
|
console.error('Reason:', reason);
|
|
console.error('Stack trace may follow:');
|
|
if (!(reason instanceof Error)) {
|
|
console.error(reason);
|
|
}
|
|
// Exit for genuinely unhandled errors
|
|
process.exit(1);
|
|
});
|
|
|
|
// --- Global Entry Point ---
|
|
main().catch((error) => {
|
|
console.error('An unexpected critical error occurred:');
|
|
if (error instanceof Error) {
|
|
console.error(error.message);
|
|
} else {
|
|
console.error(String(error));
|
|
}
|
|
process.exit(1);
|
|
});
|