Download packages/cli/index.ts from SaylorTwift/gemini-cli: direct link, hf CLI and curl.
- Browser
- Download file 6.11 kB
-
https://huggingface.co/SaylorTwift/gemini-cli/resolve/main/packages/cli/index.ts
- Command line
-
hf download hf://SaylorTwift/gemini-cli/packages/cli/index.ts
-
curl -L -o index.ts https://huggingface.co/SaylorTwift/gemini-cli/resolve/main/packages/cli/index.ts
6.11 kB
| /** | |
| * @license | |
| * Copyright 2025 Google LLC | |
| * SPDX-License-Identifier: Apache-2.0 | |
| */ | |
| import { spawn } from 'node:child_process'; | |
| import os from 'node:os'; | |
| import v8 from 'node:v8'; | |
| import { | |
| RELAUNCH_EXIT_CODE, | |
| getSpawnConfig, | |
| getScriptArgs, | |
| } from './src/utils/processUtils.js'; | |
| // --- Global Entry Point --- | |
| // Suppress known race condition error in node-pty on Windows and Linux | |
| // Tracking bug: https://github.com/microsoft/node-pty/issues/827 | |
| process.on('uncaughtException', (error) => { | |
| if (error instanceof Error) { | |
| const message = error.message || ''; | |
| const isPtyResizeError = | |
| message === 'Cannot resize a pty that has already exited'; | |
| const isEbadfError = | |
| message.includes('EBADF') || | |
| (error as { code?: string }).code === 'EBADF'; | |
| const isFromNodePty = | |
| error.stack?.includes('node-pty') || error.stack?.includes('PtyResize'); | |
| if ((isPtyResizeError || isEbadfError) && isFromNodePty) { | |
| // This error happens with node-pty when resizing a pty that has just exited. | |
| // It is a race condition in node-pty that we cannot prevent, so we silence it. | |
| return; | |
| } | |
| } | |
| // For other errors, we rely on the default behavior, but since we attached a listener, | |
| // we must manually replicate it. | |
| if (error instanceof Error) { | |
| process.stderr.write(error.stack + '\n'); | |
| } else { | |
| process.stderr.write(String(error) + '\n'); | |
| } | |
| process.exit(1); | |
| }); | |
| async function getMemoryNodeArgs(): Promise<string[]> { | |
| let autoConfigureMemory = true; | |
| try { | |
| const { readFileSync } = await import('node:fs'); | |
| const { join } = await import('node:path'); | |
| // Respect GEMINI_CLI_HOME environment variable, falling back to os.homedir() | |
| const baseDir = | |
| process.env['GEMINI_CLI_HOME'] || join(os.homedir(), '.gemini'); | |
| const settingsPath = join(baseDir, 'settings.json'); | |
| const rawSettings = readFileSync(settingsPath, 'utf8'); | |
| const settings = JSON.parse(rawSettings); | |
| if (settings?.advanced?.autoConfigureMemory === false) { | |
| autoConfigureMemory = false; | |
| } | |
| } catch { | |
| // ignore | |
| } | |
| if (autoConfigureMemory) { | |
| const totalMemoryMB = os.totalmem() / (1024 * 1024); | |
| const heapStats = v8.getHeapStatistics(); | |
| const currentMaxOldSpaceSizeMb = Math.floor( | |
| heapStats.heap_size_limit / 1024 / 1024, | |
| ); | |
| const targetMaxOldSpaceSizeInMB = Math.floor(totalMemoryMB * 0.5); | |
| if (targetMaxOldSpaceSizeInMB > currentMaxOldSpaceSizeMb) { | |
| return [`--max-old-space-size=${targetMaxOldSpaceSizeInMB}`]; | |
| } | |
| } | |
| return []; | |
| } | |
| async function run() { | |
| if (!process.env['GEMINI_CLI_NO_RELAUNCH'] && !process.env['SANDBOX']) { | |
| // --- Lightweight Parent Process / Daemon --- | |
| // We avoid importing heavy dependencies here to save ~1.5s of startup time. | |
| const scriptArgs = getScriptArgs(); | |
| const memoryArgs = await getMemoryNodeArgs(); | |
| const { spawnArgs, env: newEnv } = getSpawnConfig(memoryArgs, scriptArgs); | |
| let latestAdminSettings: unknown = undefined; | |
| // Prevent the parent process from exiting prematurely on signals. | |
| // The child process will receive the same signals and handle its own cleanup. | |
| for (const sig of ['SIGINT', 'SIGTERM', 'SIGHUP']) { | |
| process.on(sig as NodeJS.Signals, () => {}); | |
| } | |
| const runner = () => { | |
| process.stdin.pause(); | |
| const child = spawn(process.execPath, spawnArgs, { | |
| stdio: ['inherit', 'inherit', 'inherit', 'ipc'], | |
| env: newEnv, | |
| }); | |
| if (latestAdminSettings) { | |
| child.send({ type: 'admin-settings', settings: latestAdminSettings }); | |
| } | |
| child.on('message', (msg: { type?: string; settings?: unknown }) => { | |
| if (msg.type === 'admin-settings-update' && msg.settings) { | |
| latestAdminSettings = msg.settings; | |
| } | |
| }); | |
| return new Promise<number>((resolve) => { | |
| child.on('error', (err) => { | |
| process.stderr.write( | |
| 'Error: Failed to start child process: ' + err.message + '\n', | |
| ); | |
| resolve(1); | |
| }); | |
| child.on('close', (code) => { | |
| process.stdin.resume(); | |
| resolve(code ?? 1); | |
| }); | |
| }); | |
| }; | |
| while (true) { | |
| try { | |
| const exitCode = await runner(); | |
| if (process.platform === 'android' || exitCode !== RELAUNCH_EXIT_CODE) { | |
| process.exit(exitCode); | |
| } | |
| } catch (error: unknown) { | |
| process.stdin.resume(); | |
| process.stderr.write( | |
| `Fatal error: Failed to relaunch the CLI process.\n${error instanceof Error ? (error.stack ?? error.message) : String(error)}\n`, | |
| ); | |
| process.exit(1); | |
| } | |
| } | |
| } else { | |
| // --- Heavy Child Process --- | |
| // Now we can safely import everything. | |
| const { main } = await import('./src/gemini.js'); | |
| const { FatalError, writeToStderr } = await import( | |
| '@google/gemini-cli-core' | |
| ); | |
| const { runExitCleanup } = await import('./src/utils/cleanup.js'); | |
| main().catch(async (error: unknown) => { | |
| // Set a timeout to force exit if cleanup hangs | |
| const cleanupTimeout = setTimeout(() => { | |
| writeToStderr('Cleanup timed out, forcing exit...\n'); | |
| process.exit(1); | |
| }, 5000); | |
| try { | |
| await runExitCleanup(); | |
| } catch (cleanupError: unknown) { | |
| writeToStderr( | |
| `Error during final cleanup: ${cleanupError instanceof Error ? cleanupError.message : String(cleanupError)}\n`, | |
| ); | |
| } finally { | |
| clearTimeout(cleanupTimeout); | |
| } | |
| if (error instanceof FatalError) { | |
| let errorMessage = error.message; | |
| if (!process.env['NO_COLOR']) { | |
| errorMessage = `\x1b[31m${errorMessage}\x1b[0m`; | |
| } | |
| writeToStderr(errorMessage + '\n'); | |
| process.exit(error.exitCode); | |
| } | |
| writeToStderr('An unexpected critical error occurred:'); | |
| if (error instanceof Error) { | |
| writeToStderr(error.stack + '\n'); | |
| } else { | |
| writeToStderr(String(error) + '\n'); | |
| } | |
| process.exit(1); | |
| }); | |
| } | |
| } | |
| run(); | |