Gemini CLI 項目啓動和初始化流程深度解析
📋 目錄
- 啓動流程概覽
- 主入口點分析
- 配置系統初始化
- 服務組件初始化
- 認證系統初始化
- 工具系統發現註冊
- UI系統啓動
- 沙箱環境配置
- 錯誤處理設置
- 性能監控初始化
- 依賴檢查環境準備
- 完整啓動時序圖
🚀 啓動流程概覽
Gemini
CLI的啓動過程是一個精心設計的多階段初始化流程,涉及環境檢查、配置加載、服務初始化、認證設置等多個關鍵步驟。
核心啓動階段
🎯 主入口點分析
入口文件結構
📍 全局入口點:packages/cli/index.ts
#!/usr/bin/env node
import { main } from './src/gemini.js';
import { FatalError } from './src/core/error.js';
import { debugLogger } from './src/utils/debug.js';
// 🔥 全局錯誤處理 - 確保所有錯誤都被優雅處理
main().catch((error) => {
if (error instanceof FatalError) {
// 🎨 致命錯誤的彩色輸出
let errorMessage = error.message;
if (!process.env['NO_COLOR']) {
errorMessage = `\x1b[31m${errorMessage}\x1b[0m`; // 紅色文本
}
debugLogger.error(errorMessage);
process.exit(error.exitCode);
}
// 🚨 意外錯誤處理
debugLogger.error('An unexpected critical error occurred:');
debugLogger.error(error instanceof Error ? error.stack : String(error));
process.exit(1);
});
關鍵特性:
- ✅ 全局異常捕獲: 確保任何未處理的Promise rejection都被捕獲
- ✅ 錯誤分類處理: 區分致命錯誤和普通錯誤
- ✅ 優雅退出: 提供適當的退出代碼
- ✅ 彩色輸出: 支持終端顏色顯示
📍 主啓動邏輯:packages/cli/src/gemini.tsx
export async function main() {
// 1️⃣ 設置全局異常處理器
setupUnhandledRejectionHandler();
// 2️⃣ 加載和遷移設置
const settings = loadSettings();
const startupWarnings = migrateDeprecatedSettings(settings);
// 3️⃣ 清理歷史檢查點
cleanupCheckpoints();
// 4️⃣ 解析命令行參數
const argv = parseArguments(settings.merged);
const sessionId = `${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
// 5️⃣ 調試模式配置
const isDebugMode = cliConfig.isDebugMode(argv);
if (isDebugMode) {
const consolePatcher = new ConsolePatcher();
consolePatcher.patch();
}
// 6️⃣ DNS解析順序優化
dns.setDefaultResultOrder(
validateDnsResolutionOrder(settings.merged.advanced?.dnsResolutionOrder),
);
// 7️⃣ 認證類型默認設置
if (!settings.merged.security?.auth?.selectedType) {
const isCloudShell =
process.env['CLOUD_SHELL'] || process.env['CLOUDSHELL_GCLOUD_CONFIG'];
const hasApiKey = process.env['GEMINI_API_KEY'];
if (isCloudShell) {
settings.merged.security.auth.selectedType = 'CLOUD_SHELL';
} else if (hasApiKey) {
settings.merged.security.auth.selectedType = 'USE_GEMINI';
} else {
settings.merged.security.auth.selectedType = 'LOGIN_WITH_GOOGLE';
}
}
// 8️⃣ 主題系統初始化
const themeManager = getThemeManager();
await themeManager.loadCustomThemes();
// 9️⃣ 配置構建和初始化
const config = await loadCliConfig(settings.merged, sessionId, argv);
// 🔟 啓動模式選擇
if (config.isInteractive()) {
await startInteractiveUI(config, settings, startupWarnings);
} else {
await runNonInteractive({ config, settings, input, prompt_id });
}
}
⚙️ 配置系統初始化
設置加載機制
📍 設置系統:packages/cli/src/config/settings.ts
// 🗂️ 配置文件路徑定義
export const USER_SETTINGS_PATH = Storage.getGlobalSettingsPath();
export const USER_SETTINGS_DIR = path.dirname(USER_SETTINGS_PATH);
// 🔄 配置遷移映射表
const MIGRATION_MAP: Record<string, string> = {
accessibility: 'ui.accessibility', // UI可訪問性設置
allowedTools: 'tools.allowed', // 允許的工具列表
autoAccept: 'tools.autoAccept', // 工具自動接受
confirmedTools: 'tools.confirmed', // 已確認的工具
customCommands: 'commands.custom', // 自定義命令
debugMode: 'general.debugMode', // 調試模式
defaultModel: 'ai.defaultModel', // 默認AI模型
experimentalFeatures: 'features.experimental', // 實驗性功能
gitIgnore: 'files.respectGitIgnore', // Git忽略文件
maxFileSize: 'files.maxSize', // 最大文件大小
systemPrompt: 'ai.systemPrompt', // 系統提示詞
temperature: 'ai.temperature', // AI温度參數
theme: 'ui.theme', // UI主題
trustedFolders: 'security.trustedFolders', // 信任文件夾
};
// 📋 設置加載函數
export function loadSettings(): {
merged: Settings;
startupWarnings: string[];
} {
let userSettings: Partial<Settings> = {};
const startupWarnings: string[] = [];
try {
// 🔍 檢查用户設置文件是否存在
if (fs.existsSync(USER_SETTINGS_PATH)) {
const settingsContent = fs.readFileSync(USER_SETTINGS_PATH, 'utf8');
// 📖 解析JSON with Comments格式
const parsedSettings = JSON.parse(stripJsonComments(settingsContent));
// 🔄 遷移舊版配置
userSettings = migrateSettings(parsedSettings, startupWarnings);
// 🌍 解析環境變量
userSettings = resolveEnvVarsInObject(userSettings);
}
} catch (error) {
startupWarnings.push(`Failed to load user settings: ${error.message}`);
}
// 🔗 深度合併默認設置和用户設置
const merged = customDeepMerge(getDefaultSettings(), userSettings);
return { merged, startupWarnings };
}
📍 CLI配置構建:packages/cli/src/config/config.ts
export async function loadCliConfig(
settings: Settings,
sessionId: string,
argv: ArgumentsCamelCase<GeminiArguments>,
): Promise<Config> {
// 1️⃣ 沙箱配置加載
const sandboxConfig = loadSandboxConfig(
argv.sandbox,
settings.advanced?.sandbox,
);
// 2️⃣ 工作目錄和包含目錄設置
const cwd = process.cwd();
const includeDirectories =
argv.includeDirectories
?.split(',')
.map((dir) => path.resolve(cwd, dir.trim())) || [];
// 3️⃣ 調試模式檢查
const debugMode = isDebugMode(argv);
// 4️⃣ 策略引擎配置
const policyEngineConfig = await buildPolicyEngineConfig(settings, debugMode);
// 5️⃣ 工具配置處理
const allowedTools = processAllowedTools(
argv.allowedTools,
settings.tools?.allowed,
);
const excludeTools = processExcludeTools(argv.excludeTools);
// 6️⃣ 擴展管理器初始化
const extensionManager = new ExtensionManager({
extensionsRootDir: Storage.getExtensionsDir(),
settingsPath: Storage.getGlobalSettingsPath(),
isDebug: debugMode,
allowedTools,
excludeTools,
});
// 7️⃣ 擴展加載
await extensionManager.loadExtensions();
// 8️⃣ 內存層次加載
const { memoryContent, fileCount, filePaths } =
await loadServerHierarchicalMemory(cwd, includeDirectories, settings);
// 9️⃣ 最終配置對象構建
return new Config({
sessionId,
embeddingModel: DEFAULT_GEMINI_EMBEDDING_MODEL,
sandbox: sandboxConfig,
targetDir: cwd,
includeDirectories,
debugMode,
question: argv.question,
coreTools: settings.tools?.core,
allowedTools: allowedTools.length > 0 ? allowedTools : undefined,
policyEngineConfig,
excludeTools,
extensionManager,
memoryContent,
initialFileCount: fileCount,
initialFilePaths: filePaths,
telemetrySettings,
settings,
});
}
🔧 服務組件初始化
核心服務初始化順序
📍 Config類初始化:packages/core/src/config/config.ts
export class Config {
private toolRegistry!: ToolRegistry;
private geminiClient!: GeminiClient;
private ideContextStore!: IdeContextStore;
private messageBus!: MessageBus;
// 🚀 核心初始化方法
async initialize(): Promise<void> {
// 1️⃣ 創建消息總線
this.messageBus = new MessageBus();
// 2️⃣ 初始化IDE上下文存儲
this.ideContextStore = new IdeContextStore();
// 3️⃣ 創建工具註冊表
this.toolRegistry = await this.createToolRegistry();
// 4️⃣ 初始化Gemini客户端
this.geminiClient = new GeminiClient(
this.genAI!,
this.toolRegistry,
this.messageBus,
this.ideContextStore,
this,
);
// 5️⃣ 設置工具註冊表的客户端引用
this.toolRegistry.setGeminiClient(this.geminiClient);
// 6️⃣ 初始化完成回調
this.onInitialized?.();
}
// 🛠️ 工具註冊表創建
private async createToolRegistry(): Promise<ToolRegistry> {
const mcpClientManager = new McpClientManager(this);
const toolRegistry = new ToolRegistry(
this,
this.messageBus,
mcpClientManager,
);
// 📋 發現所有工具
await toolRegistry.discoverAllTools();
return toolRegistry;
}
}
服務依賴關係圖
🔐 認證系統初始化
認證流程分析
📍 認證初始化:packages/cli/src/core/auth.ts
export async function performInitialAuth(
config: Config,
authType: AuthType | undefined,
): Promise<string | null> {
if (!authType) {
return null;
}
try {
// 🔄 刷新認證狀態
await config.refreshAuth(authType);
return null;
} catch (e) {
return `Failed to login. Message: ${getErrorMessage(e)}`;
}
}
// 🎯 支持的認證類型
export type AuthType =
| 'USE_GEMINI' // Gemini API密鑰
| 'LOGIN_WITH_GOOGLE' // Google OAuth2
| 'CLOUD_SHELL' // Cloud Shell環境
| 'SERVICE_ACCOUNT'; // 服務賬户
📍 認證類型自動檢測:packages/cli/src/gemini.tsx
// 🔍 智能認證類型檢測
if (!settings.merged.security?.auth?.selectedType) {
const isCloudShell =
process.env['CLOUD_SHELL'] || process.env['CLOUDSHELL_GCLOUD_CONFIG'];
const hasApiKey = process.env['GEMINI_API_KEY'];
const hasVertexConfig = process.env['GOOGLE_GENAI_USE_VERTEXAI'];
// 🏷️ 認證類型優先級
if (isCloudShell) {
settings.merged.security.auth.selectedType = 'CLOUD_SHELL';
} else if (hasVertexConfig) {
settings.merged.security.auth.selectedType = 'SERVICE_ACCOUNT';
} else if (hasApiKey) {
settings.merged.security.auth.selectedType = 'USE_GEMINI';
} else {
settings.merged.security.auth.selectedType = 'LOGIN_WITH_GOOGLE';
}
}
OAuth2流程處理
// 📍 OAuth重定向處理:packages/cli/src/core/auth.ts
export function handleOAuthRedirect(url: string): {
success: boolean;
error?: string;
} {
try {
const urlObj = new URL(url);
const code = urlObj.searchParams.get('code');
const error = urlObj.searchParams.get('error');
if (error) {
return { success: false, error: `OAuth error: ${error}` };
}
if (code) {
// 🎉 OAuth授權碼獲取成功
return { success: true };
}
return { success: false, error: 'No authorization code received' };
} catch (e) {
return { success: false, error: `Invalid OAuth URL: ${e.message}` };
}
}
🛠️ 工具系統發現註冊
工具註冊表架構
📍 工具註冊表:packages/core/src/tools/tool-registry.ts
export class ToolRegistry {
private tools = new Map<string, AnyDeclarativeTool>();
private mcpClientManager: McpClientManager;
// 🔍 工具發現主流程
async discoverAllTools(): Promise<void> {
// 1️⃣ 註冊核心工具
await this.registerCoreTools();
// 2️⃣ 發現命令行工具
await this.discoverCommandTools();
// 3️⃣ 發現MCP工具
await this.mcpClientManager.discoverAllMcpTools();
// 4️⃣ 註冊MCP工具
this.registerMcpTools();
// 5️⃣ 應用工具過濾
this.applyToolFilters();
}
// 🧰 核心工具註冊
private async registerCoreTools(): Promise<void> {
const coreTools = [
new ReadFileTool(this.config),
new WriteFileTool(this.config, this.messageBus),
new EditTool(this.config, this.messageBus),
new ShellTool(this.config, this.messageBus),
new LsTool(this.config),
new GrepTool(this.config),
new RipGrepTool(this.config),
new GlobTool(this.config),
new WebFetchTool(this.config),
new WebSearchTool(this.config),
new MemoryTool(this.config, this.messageBus),
];
for (const tool of coreTools) {
this.registerTool(tool);
}
}
// 🔍 命令行工具發現
private async discoverCommandTools(): Promise<void> {
const discoveryCommand = this.config.getToolDiscoveryCommand();
if (!discoveryCommand) return;
try {
// 🚀 執行工具發現命令
const result = await executeShellCommand(discoveryCommand);
const discoveredTools = JSON.parse(result.stdout);
for (const toolSpec of discoveredTools) {
const tool = new DiscoveredTool(
this.config,
toolSpec.name,
toolSpec.description,
toolSpec.parameters,
);
this.registerTool(tool);
}
} catch (error) {
console.warn(`Tool discovery failed: ${error.message}`);
}
}
}
MCP工具集成
📍 MCP客户端管理:packages/core/src/tools/mcp-client-manager.ts
export class McpClientManager {
private clients: Map<string, McpClient> = new Map();
private discoveredTools: DiscoveredMCPTool[] = [];
// 🌐 MCP工具發現
async discoverAllMcpTools(): Promise<void> {
const mcpServers = this.config.getMcpServers();
// 🔄 並行連接所有MCP服務器
const connectionPromises = Object.entries(mcpServers).map(
async ([serverName, serverConfig]) => {
try {
await this.connectToServer(serverName, serverConfig);
} catch (error) {
console.warn(
`Failed to connect to MCP server ${serverName}: ${error.message}`,
);
}
},
);
await Promise.all(connectionPromises);
}
// 🔗 連接MCP服務器
private async connectToServer(
serverName: string,
config: MCPServerConfig,
): Promise<void> {
const client = new McpClient(serverName, config, this.config);
// 🤝 建立連接
await client.connect();
// 🛠️ 獲取工具列表
const tools = await client.listTools();
// 📋 註冊工具
for (const tool of tools) {
const mcpTool = new DiscoveredMCPTool(
tool,
serverName,
tool.name,
client,
this.config,
);
this.discoveredTools.push(mcpTool);
}
this.clients.set(serverName, client);
}
}
🖥️ UI系統啓動
React UI初始化
📍 交互式UI啓動:packages/cli/src/gemini.tsx
async function startInteractiveUI(
config: Config,
settings: { merged: Settings; startupWarnings: string[] },
startupWarnings: string[]
): Promise<void> {
// 1️⃣ 認證初始化
const authError = await performInitialAuth(config, settings.merged.security?.auth?.selectedType);
if (authError) {
throw new FatalError(authError, 1);
}
// 2️⃣ 終端配置
process.stdout.write('\x1b[?7l'); // 禁用行包裝
if (settings.merged.ui?.enableMouse !== false) {
enableMouseEvents(); // 啓用鼠標事件
}
// 3️⃣ Kitty鍵盤協議檢測
await detectAndEnableKittyProtocol();
// 4️⃣ React應用啓動
const AppWrapper = () => {
const kittyProtocolStatus = useKittyKeyboardProtocol();
return (
<SettingsContext.Provider value={settings}>
<KeypressProvider>
<MouseProvider>
<ScrollProvider>
<SessionStatsProvider>
<VimModeProvider>
<AppContainer />
</VimModeProvider>
</SessionStatsProvider>
</ScrollProvider>
</MouseProvider>
</KeypressProvider>
</SettingsContext.Provider>
);
};
// 🎨 Ink渲染器配置
const { unmount } = render(<AppWrapper />, {
exitOnCtrlC: false, // 禁用Ctrl+C自動退出
patchConsole: false // 禁用控制枱補丁
});
// 🧹 註冊清理函數
registerCleanup(async () => {
unmount();
disableMouseEvents();
process.stdout.write('\x1b[?7h'); // 重新啓用行包裝
});
}
📍 應用容器初始化:packages/cli/src/ui/AppContainer.tsx
export function AppContainer() {
const [configInitialized, setConfigInitialized] = useState(false);
const [error, setError] = useState<string | null>(null);
// 🚀 配置初始化
useEffect(() => {
(async () => {
try {
// 📋 異步初始化配置
await config.initialize();
setConfigInitialized(true);
} catch (err) {
setError(`Configuration initialization failed: ${err.message}`);
}
})();
// 🧹 清理資源註冊
registerCleanup(async () => {
disableMouseEvents();
const ideClient = await IdeClient.getInstance();
await ideClient.disconnect();
});
}, [config]);
// 📊 性能監控
useMemoryMonitor(config);
// 🎨 UI渲染
if (error) {
return <ErrorScreen error={error} />;
}
if (!configInitialized) {
return <LoadingScreen message="Initializing Gemini CLI..." />;
}
return <App />;
}
Context Provider鏈
// 🔗 React Context提供者鏈
<SettingsContext.Provider> // 設置上下文
<KeypressProvider> // 鍵盤事件處理
<MouseProvider> // 鼠標事件處理
<ScrollProvider> // 滾動控制
<SessionStatsProvider> // 會話統計
<VimModeProvider> // Vim模式支持
<AppContainer /> // 主應用容器
</VimModeProvider>
</SessionStatsProvider>
</ScrollProvider>
</MouseProvider>
</KeypressProvider>
</SettingsContext.Provider>
🛡️ 沙箱環境配置
沙箱檢測和配置
📍 沙箱配置加載:packages/cli/src/config/sandboxConfig.ts
// 🔍 支持的沙箱命令
const VALID_SANDBOX_COMMANDS = ['docker', 'podman', 'sandbox-exec'];
export function loadSandboxConfig(
sandboxFlag?: boolean | string,
settingsSandbox?: SandboxSettings,
): SandboxConfig {
// 1️⃣ 檢查是否已在沙箱中運行
if (process.env['SANDBOX']) {
return { command: '', flags: [], environment: {} };
}
// 2️⃣ 獲取沙箱命令
const command = getSandboxCommand(sandboxFlag, settingsSandbox);
if (!command) {
return { command: '', flags: [], environment: {} };
}
// 3️⃣ 構建沙箱配置
const config: SandboxConfig = {
command,
flags: buildSandboxFlags(command, settingsSandbox),
environment: buildSandboxEnvironment(settingsSandbox),
imageUri: settingsSandbox?.imageUri || getDefaultImageUri(),
};
return config;
}
// 🔍 沙箱命令檢測
function getSandboxCommand(
sandboxFlag?: boolean | string,
settings?: SandboxSettings,
): SandboxConfig['command'] | '' {
// 🌍 環境變量優先級
const envSandbox = process.env['GEMINI_SANDBOX']?.toLowerCase().trim() || '';
if (envSandbox && VALID_SANDBOX_COMMANDS.includes(envSandbox)) {
return envSandbox as SandboxConfig['command'];
}
// 🖥️ 平台特定檢測
if (os.platform() === 'darwin' && commandExists.sync('sandbox-exec')) {
return 'sandbox-exec';
}
// 🐳 容器引擎檢測
if (sandboxFlag === true || sandboxFlag === 'docker') {
if (commandExists.sync('docker')) {
return 'docker';
}
}
if (sandboxFlag === true || sandboxFlag === 'podman') {
if (commandExists.sync('podman')) {
return 'podman';
}
}
return '';
}
沙箱啓動流程
// 📍 沙箱重啓邏輯:packages/cli/src/gemini.tsx
async function restartInSandbox(sandboxConfig: SandboxConfig): Promise<void> {
// 1️⃣ 認證檢查 - OAuth2在沙箱中會失敗
if (requiresInteractiveAuth(settings.merged.security?.auth?.selectedType)) {
throw new FatalSandboxError(
'Interactive authentication is not supported in sandbox mode. ' +
'Please use API key or service account authentication.',
);
}
// 2️⃣ 讀取stdin數據
let input = '';
if (!process.stdin.isTTY) {
const chunks: Buffer[] = [];
for await (const chunk of process.stdin) {
chunks.push(chunk);
}
input = Buffer.concat(chunks).toString();
}
// 3️⃣ 構建沙箱命令
const sandboxArgs = [
...sandboxConfig.flags,
process.argv[0], // node executable
...process.argv.slice(1), // script and args
];
// 4️⃣ 在沙箱中重啓進程
const childProcess = spawn(sandboxConfig.command, sandboxArgs, {
stdio: ['pipe', 'inherit', 'inherit'],
env: { ...process.env, SANDBOX: '1', ...sandboxConfig.environment },
});
// 5️⃣ 傳遞輸入數據
if (input) {
childProcess.stdin?.write(input);
childProcess.stdin?.end();
}
// 6️⃣ 等待子進程完成
const exitCode = await new Promise<number>((resolve) => {
childProcess.on('close', resolve);
});
process.exit(exitCode);
}
❌ 錯誤處理設置
全局錯誤處理機制
📍 未處理Promise拒絕:packages/cli/src/gemini.tsx
export function setupUnhandledRejectionHandler() {
let unhandledRejectionOccurred = false;
// 🚨 全局Promise rejection處理
process.on('unhandledRejection', (reason, promise) => {
const errorMessage = `=========================================
This is an unexpected error. Please file a bug report using the /bug tool.
CRITICAL: Unhandled Promise Rejection!
=========================================
Reason: ${reason}
Promise: ${promise}`;
// 📢 發送錯誤事件
appEvents.emit(AppEvent.LogError, errorMessage);
// 🔍 首次錯誤時打開調試控制枱
if (!unhandledRejectionOccurred) {
unhandledRejectionOccurred = true;
appEvents.emit(AppEvent.OpenDebugConsole);
}
});
// 🚨 未捕獲異常處理
process.on('uncaughtException', (error) => {
const errorMessage = `=========================================
CRITICAL: Uncaught Exception!
=========================================
Error: ${error.message}
Stack: ${error.stack}`;
appEvents.emit(AppEvent.LogError, errorMessage);
appEvents.emit(AppEvent.OpenDebugConsole);
// 🛑 嚴重錯誤,強制退出
process.exit(1);
});
}
錯誤類型層次結構
// 📍 錯誤類型定義:packages/cli/src/core/error.ts
// 🔴 基礎致命錯誤
export class FatalError extends Error {
constructor(
message: string,
public readonly exitCode: number = 1,
) {
super(message);
this.name = 'FatalError';
}
}
// ⚙️ 配置錯誤
export class FatalConfigError extends FatalError {
constructor(message: string) {
super(`Configuration Error: ${message}`, 1);
this.name = 'FatalConfigError';
}
}
// 🛡️ 沙箱錯誤
export class FatalSandboxError extends FatalError {
constructor(message: string) {
super(`Sandbox Error: ${message}`, 1);
this.name = 'FatalSandboxError';
}
}
// 🔐 認證錯誤
export class FatalAuthError extends FatalError {
constructor(message: string) {
super(`Authentication Error: ${message}`, 1);
this.name = 'FatalAuthError';
}
}
控制枱補丁系統
📍 控制枱攔截:packages/cli/src/ui/utils/ConsolePatcher.js
export class ConsolePatcher {
private originalMethods: Map<string, Function> = new Map();
// 🔧 補丁應用
patch(): void {
const methods = ['log', 'warn', 'error', 'info', 'debug'];
methods.forEach((method) => {
this.originalMethods.set(method, console[method]);
console[method] = (...args: any[]) => {
// 📤 發送到UI系統
appEvents.emit(AppEvent.ConsoleOutput, {
level: method,
message: args.join(' '),
timestamp: Date.now(),
});
// 🔄 調用原始方法
this.originalMethods.get(method)!.apply(console, args);
};
});
}
// 🔄 補丁移除
unpatch(): void {
this.originalMethods.forEach((originalMethod, method) => {
console[method] = originalMethod;
});
this.originalMethods.clear();
}
}
📊 性能監控初始化
遙測系統設置
📍 遙測配置:packages/cli/src/gemini.tsx
// 📊 遙測設置解析
let telemetrySettings;
try {
telemetrySettings = await resolveTelemetrySettings({
env: process.env as unknown as Record<string, string | undefined>,
settings: settings.telemetry,
});
} catch (err) {
if (err instanceof FatalConfigError) {
throw new FatalConfigError(
`Invalid telemetry configuration: ${err.message}.`,
);
}
throw err;
}
// 📈 會話統計初始化
const sessionStats = {
startTime: Date.now(),
sessionId,
nodeVersion: process.version,
platform: os.platform(),
arch: os.arch(),
};
內存監控服務
📍 內存監控Hook:packages/cli/src/ui/hooks/useMemoryMonitor.ts
export function useMemoryMonitor(config: Config) {
useEffect(() => {
if (!config.isDebugMode()) return;
const memoryMonitor = new MemoryMonitor();
// 🔄 定期內存檢查
const interval = setInterval(() => {
const memoryUsage = process.memoryUsage();
// 📊 記錄內存指標
memoryMonitor.recordMetric('rss', memoryUsage.rss);
memoryMonitor.recordMetric('heapUsed', memoryUsage.heapUsed);
memoryMonitor.recordMetric('heapTotal', memoryUsage.heapTotal);
memoryMonitor.recordMetric('external', memoryUsage.external);
// ⚠️ 內存警告閾值
if (memoryUsage.heapUsed > 500 * 1024 * 1024) {
// 500MB
console.warn('High memory usage detected:', memoryUsage);
}
}, 5000); // 每5秒檢查一次
return () => clearInterval(interval);
}, [config]);
}
性能指標收集
// 📍 性能指標:packages/core/src/services/performance-monitor.ts
export class PerformanceMonitor {
private metrics: Map<string, MetricData[]> = new Map();
// 📏 操作計時
async measureOperation<T>(
operationName: string,
operation: () => Promise<T>,
): Promise<T> {
const startTime = performance.now();
const startMemory = process.memoryUsage();
try {
const result = await operation();
// 📊 成功指標記錄
this.recordMetric(operationName, {
duration: performance.now() - startTime,
memoryDelta: process.memoryUsage().heapUsed - startMemory.heapUsed,
status: 'success',
timestamp: Date.now(),
});
return result;
} catch (error) {
// 📉 錯誤指標記錄
this.recordMetric(operationName, {
duration: performance.now() - startTime,
status: 'error',
error: error.message,
timestamp: Date.now(),
});
throw error;
}
}
}
🔍 依賴檢查環境準備
環境檢查清單
📍 依賴驗證:packages/cli/src/gemini.tsx
// 🔍 環境檢查函數
function validateEnvironment(): string[] {
const warnings: string[] = [];
// 1️⃣ Node.js版本檢查
const nodeVersion = process.version;
const requiredVersion = '20.0.0';
if (!semver.gte(nodeVersion, requiredVersion)) {
warnings.push(
`Node.js ${requiredVersion} or higher is required. Current: ${nodeVersion}`,
);
}
// 2️⃣ 終端能力檢查
if (!process.stdout.isTTY && process.argv.includes('--interactive')) {
warnings.push('Interactive mode requested but stdout is not a TTY');
}
// 3️⃣ 顏色支持檢查
if (process.env['NO_COLOR'] === undefined && !supportsColor.stdout) {
process.env['NO_COLOR'] = '1';
}
// 4️⃣ 權限檢查
try {
fs.accessSync(USER_SETTINGS_DIR, fs.constants.W_OK);
} catch (error) {
warnings.push(`Cannot write to settings directory: ${USER_SETTINGS_DIR}`);
}
return warnings;
}
// 🌐 DNS解析順序驗證
function validateDnsResolutionOrder(order?: string): 'ipv4first' | 'verbatim' {
const validOrders = ['ipv4first', 'verbatim'];
if (order && validOrders.includes(order)) {
return order as 'ipv4first' | 'verbatim';
}
return 'ipv4first'; // 默認優先IPv4
}
命令可用性檢查
// 📍 命令存在性檢查:packages/cli/src/utils/command-check.ts
import commandExists from 'command-exists';
export async function checkRequiredCommands(): Promise<{
available: string[];
missing: string[];
}> {
const commands = ['git', 'node', 'npm'];
const available: string[] = [];
const missing: string[] = [];
// 🔄 並行檢查所有命令
await Promise.all(
commands.map(async (cmd) => {
try {
await commandExists(cmd);
available.push(cmd);
} catch (error) {
missing.push(cmd);
}
}),
);
return { available, missing };
}
// 🐳 容器引擎檢查
export async function checkContainerEngines(): Promise<{
docker: boolean;
podman: boolean;
sandboxExec: boolean;
}> {
const [docker, podman, sandboxExec] = await Promise.all([
commandExists('docker')
.then(() => true)
.catch(() => false),
commandExists('podman')
.then(() => true)
.catch(() => false),
commandExists('sandbox-exec')
.then(() => true)
.catch(() => false),
]);
return { docker, podman, sandboxExec };
}
📈 完整啓動時序圖
📍 Entry Point
🚀 Main Function
⚙️ Config System
🔐 Auth System
🛠️ Tool Registry
🖥️ UI System
🔧 Services
🔥 Global error handling
📋 Load settings & migrate
🧹 Cleanup checkpoints
📝 Parse arguments
🔍 Environment validation
🔄 Restart in sandbox
alt
[🛡️ Sandbox
required]
🏗️ Build CLI config
📦 Initialize extension manager
🔍 Load extensions
📊 Load memory hierarchy
🔐 Perform initial auth
✅ Auth success/failure
🎨 Start interactive UI
🖱️ Enable mouse events
⌨️ Detect Kitty protocol
🔗 Setup React providers
🚀 Initialize config
📢 Create message bus
💭 Initialize IDE context
🛠️ Create tool registry
🔍 Discover all tools
🧰 Register core tools
🌐 Connect MCP servers
🤖 Initialize Gemini client
✅ Initialization complete
🎉 Render main application
📍 Entry Point
🚀 Main Function
⚙️ Config System
🔐 Auth System
🛠️ Tool Registry
🖥️ UI System
🔧 Services
🎯 總結
🌟 啓動流程特點
Gemini CLI的啓動流程展現了現代CLI應用的工程傑作:
- 🔄 漸進式初始化: 分階段、有序的組件初始化
- 🛡️ 全面錯誤處理: 多層次的錯誤捕獲和處理機制
- ⚙️ 智能配置系統: 多源配置合併和遷移機制
- 🔐 靈活認證策略: 多種認證方式的自動檢測和配置
- 🛠️ 可擴展工具系統: 內置工具+MCP工具+自定義工具
- 🖥️ 現代UI體驗: React+Ink構建的豐富終端界面
- 🛡️ 安全沙箱執行: 多平台沙箱環境的智能檢測
- 📊 完善監控體系: 性能監控和遙測數據收集
💡 設計亮點
- 模塊化架構: 清晰的職責分離和依賴關係
- 異步優化: 並行初始化和非阻塞操作
- 容錯機制: 優雅的降級和錯誤恢復
- 用户體驗: 智能默認配置和友好錯誤提示
- 擴展性: 插件化的工具和擴展系統
這個啓動流程不僅保證了應用的穩定運行,更為用户提供了快速、可靠、功能豐富的AI輔助體驗。每個初始化步驟都經過精心設計,體現了現代軟件工程的最佳實踐。