Gemini CLI 項目啓動和初始化流程深度解析

📋 目錄

  1. 啓動流程概覽
  2. 主入口點分析
  3. 配置系統初始化
  4. 服務組件初始化
  5. 認證系統初始化
  6. 工具系統發現註冊
  7. UI系統啓動
  8. 沙箱環境配置
  9. 錯誤處理設置
  10. 性能監控初始化
  11. 依賴檢查環境準備
  12. 完整啓動時序圖

🚀 啓動流程概覽

Gemini
CLI的啓動過程是一個精心設計的多階段初始化流程,涉及環境檢查、配置加載、服務初始化、認證設置等多個關鍵步驟。

核心啓動階段


Gemini cli 源碼分析之-Gemini CLI 項目啓動和初始化流程_#Gemini

Gemini cli 源碼分析之-Gemini CLI 項目啓動和初始化流程_#命令模式_02

Gemini cli 源碼分析之-Gemini CLI 項目啓動和初始化流程_#AI編碼_03

Gemini cli 源碼分析之-Gemini CLI 項目啓動和初始化流程_#交互_04

Gemini cli 源碼分析之-Gemini CLI 項目啓動和初始化流程_#AI編碼_05

Gemini cli 源碼分析之-Gemini CLI 項目啓動和初始化流程_#AI編程_06

Gemini cli 源碼分析之-Gemini CLI 項目啓動和初始化流程_#Gemini_07

Gemini cli 源碼分析之-Gemini CLI 項目啓動和初始化流程_#AI編碼_08

Gemini cli 源碼分析之-Gemini CLI 項目啓動和初始化流程_#Gemini_09

Gemini cli 源碼分析之-Gemini CLI 項目啓動和初始化流程_#AI編程_10

Gemini cli 源碼分析之-Gemini CLI 項目啓動和初始化流程_#交互_11

Gemini cli 源碼分析之-Gemini CLI 項目啓動和初始化流程_#交互_12

Gemini cli 源碼分析之-Gemini CLI 項目啓動和初始化流程_#AI編程_13



🎯 主入口點分析

入口文件結構

📍 全局入口點: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;
  }
}

服務依賴關係圖


Gemini cli 源碼分析之-Gemini CLI 項目啓動和初始化流程_#命令模式_14

Gemini cli 源碼分析之-Gemini CLI 項目啓動和初始化流程_#命令模式_15



🔐 認證系統初始化

認證流程分析

📍 認證初始化: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應用的工程傑作

  1. 🔄 漸進式初始化: 分階段、有序的組件初始化
  2. 🛡️ 全面錯誤處理: 多層次的錯誤捕獲和處理機制
  3. ⚙️ 智能配置系統: 多源配置合併和遷移機制
  4. 🔐 靈活認證策略: 多種認證方式的自動檢測和配置
  5. 🛠️ 可擴展工具系統: 內置工具+MCP工具+自定義工具
  6. 🖥️ 現代UI體驗: React+Ink構建的豐富終端界面
  7. 🛡️ 安全沙箱執行: 多平台沙箱環境的智能檢測
  8. 📊 完善監控體系: 性能監控和遙測數據收集

💡 設計亮點

  • 模塊化架構: 清晰的職責分離和依賴關係
  • 異步優化: 並行初始化和非阻塞操作
  • 容錯機制: 優雅的降級和錯誤恢復
  • 用户體驗: 智能默認配置和友好錯誤提示
  • 擴展性: 插件化的工具和擴展系統

這個啓動流程不僅保證了應用的穩定運行,更為用户提供了快速、可靠、功能豐富的AI輔助體驗。每個初始化步驟都經過精心設計,體現了現代軟件工程的最佳實踐。