Download packages/core/src/ide/ide-installer.ts from SaylorTwift/gemini-cli: direct link, hf CLI and curl.
- Browser
- Download file 9.87 kB
-
https://huggingface.co/SaylorTwift/gemini-cli/resolve/main/packages/core/src/ide/ide-installer.ts
- Command line
-
hf download hf://SaylorTwift/gemini-cli/packages/core/src/ide/ide-installer.ts
-
curl -L -o ide-installer.ts https://huggingface.co/SaylorTwift/gemini-cli/resolve/main/packages/core/src/ide/ide-installer.ts
9.87 kB
| /** | |
| * @license | |
| * Copyright 2025 Google LLC | |
| * SPDX-License-Identifier: Apache-2.0 | |
| */ | |
| import * as child_process from 'node:child_process'; | |
| import * as process from 'node:process'; | |
| import * as path from 'node:path'; | |
| import * as fs from 'node:fs'; | |
| import { IDE_DEFINITIONS, type IdeInfo } from './detect-ide.js'; | |
| import { GEMINI_CLI_COMPANION_EXTENSION_NAME } from './constants.js'; | |
| import { homedir } from '../utils/paths.js'; | |
| export interface IdeInstaller { | |
| install(): Promise<InstallResult>; | |
| } | |
| export interface InstallResult { | |
| success: boolean; | |
| message: string; | |
| } | |
| async function findCommand( | |
| command: string, | |
| platform: NodeJS.Platform = process.platform, | |
| ): Promise<string | null> { | |
| // 1. Check PATH first. | |
| try { | |
| if (platform === 'win32') { | |
| const result = child_process | |
| .execSync(`where.exe ${command}`) | |
| .toString() | |
| .trim(); | |
| // `where.exe` can return multiple paths. Return the first one. | |
| const firstPath = result.split(/\r?\n/)[0]; | |
| if (firstPath) { | |
| return firstPath; | |
| } | |
| } else { | |
| child_process.execSync(`command -v ${command}`, { | |
| stdio: 'ignore', | |
| }); | |
| return command; | |
| } | |
| } catch { | |
| // Not in PATH, continue to check common locations. | |
| } | |
| // 2. Check common installation locations. | |
| const locations: string[] = []; | |
| const homeDir = homedir(); | |
| interface AppConfigEntry { | |
| mac?: { appName: string; supportDirName: string }; | |
| win?: { appName: string; appBinary: string }; | |
| linux?: { appBinary: string }; | |
| } | |
| interface AppConfigs { | |
| code: AppConfigEntry; | |
| positron: AppConfigEntry; | |
| } | |
| const appConfigs: AppConfigs = { | |
| code: { | |
| mac: { appName: 'Visual Studio Code', supportDirName: 'Code' }, | |
| win: { appName: 'Microsoft VS Code', appBinary: 'code.cmd' }, | |
| linux: { appBinary: 'code' }, | |
| }, | |
| positron: { | |
| mac: { appName: 'Positron', supportDirName: 'Positron' }, | |
| win: { appName: 'Positron', appBinary: 'positron.cmd' }, | |
| linux: { appBinary: 'positron' }, | |
| }, | |
| }; | |
| type AppName = keyof typeof appConfigs; | |
| let appname: AppName | undefined; | |
| if (command === 'code' || command === 'code.cmd') { | |
| appname = 'code'; | |
| } else if (command === 'positron' || command === 'positron.cmd') { | |
| appname = 'positron'; | |
| } | |
| if (appname) { | |
| if (platform === 'darwin') { | |
| // macOS | |
| const macConfig = appConfigs[appname].mac; | |
| if (macConfig) { | |
| locations.push( | |
| `/Applications/${macConfig.appName}.app/Contents/Resources/app/bin/${appname}`, | |
| path.join( | |
| homeDir, | |
| `Library/Application Support/${macConfig.supportDirName}/bin/${appname}`, | |
| ), | |
| ); | |
| } | |
| } else if (platform === 'linux') { | |
| // Linux | |
| const linuxConfig = appConfigs[appname]?.linux; | |
| if (linuxConfig) { | |
| locations.push( | |
| `/usr/share/${linuxConfig.appBinary}/bin/${linuxConfig.appBinary}`, | |
| `/snap/bin/${linuxConfig.appBinary}`, | |
| path.join( | |
| homeDir, | |
| `.local/share/${linuxConfig.appBinary}/bin/${linuxConfig.appBinary}`, | |
| ), | |
| ); | |
| } | |
| } else if (platform === 'win32') { | |
| // Windows | |
| const winConfig = appConfigs[appname].win; | |
| if (winConfig) { | |
| const winAppName = winConfig.appName; | |
| locations.push( | |
| path.join( | |
| process.env['ProgramFiles'] || 'C:\\Program Files', | |
| winAppName, | |
| 'bin', | |
| winConfig.appBinary, | |
| ), | |
| path.join( | |
| homeDir, | |
| 'AppData', | |
| 'Local', | |
| 'Programs', | |
| winAppName, | |
| 'bin', | |
| winConfig.appBinary, | |
| ), | |
| ); | |
| } | |
| } | |
| } | |
| for (const location of locations) { | |
| if (fs.existsSync(location)) { | |
| return location; | |
| } | |
| } | |
| return null; | |
| } | |
| class VsCodeInstaller implements IdeInstaller { | |
| private vsCodeCommand: Promise<string | null>; | |
| constructor( | |
| readonly ideInfo: IdeInfo, | |
| readonly platform = process.platform, | |
| ) { | |
| const command = platform === 'win32' ? 'code.cmd' : 'code'; | |
| this.vsCodeCommand = findCommand(command, platform); | |
| } | |
| async install(): Promise<InstallResult> { | |
| const commandPath = await this.vsCodeCommand; | |
| if (!commandPath) { | |
| return { | |
| success: false, | |
| message: `${this.ideInfo.displayName} CLI not found. Please ensure 'code' is in your system's PATH. For help, see https://code.visualstudio.com/docs/configure/command-line#_code-is-not-recognized-as-an-internal-or-external-command. You can also install the '${GEMINI_CLI_COMPANION_EXTENSION_NAME}' extension manually from the VS Code marketplace.`, | |
| }; | |
| } | |
| try { | |
| const result = child_process.spawnSync( | |
| commandPath, | |
| [ | |
| '--install-extension', | |
| 'google.gemini-cli-vscode-ide-companion', | |
| '--force', | |
| ], | |
| { stdio: 'pipe', shell: this.platform === 'win32' }, | |
| ); | |
| if (result.status !== 0) { | |
| throw new Error( | |
| `Failed to install extension: ${result.stderr?.toString()}`, | |
| ); | |
| } | |
| return { | |
| success: true, | |
| message: `${this.ideInfo.displayName} companion extension was installed successfully.`, | |
| }; | |
| } catch { | |
| return { | |
| success: false, | |
| message: `Failed to install ${this.ideInfo.displayName} companion extension. Please try installing '${GEMINI_CLI_COMPANION_EXTENSION_NAME}' manually from the ${this.ideInfo.displayName} extension marketplace.`, | |
| }; | |
| } | |
| } | |
| } | |
| class PositronInstaller implements IdeInstaller { | |
| private vsCodeCommand: Promise<string | null>; | |
| constructor( | |
| readonly ideInfo: IdeInfo, | |
| readonly platform = process.platform, | |
| ) { | |
| const command = platform === 'win32' ? 'positron.cmd' : 'positron'; | |
| this.vsCodeCommand = findCommand(command, platform); | |
| } | |
| async install(): Promise<InstallResult> { | |
| const commandPath = await this.vsCodeCommand; | |
| if (!commandPath) { | |
| return { | |
| success: false, | |
| message: `${this.ideInfo.displayName} CLI not found. Please ensure 'positron' is in your system's PATH. For help, see https://positron.posit.co/add-to-path.html. You can also install the '${GEMINI_CLI_COMPANION_EXTENSION_NAME}' extension manually from the VS Code marketplace / Open VSX registry.`, | |
| }; | |
| } | |
| try { | |
| const result = child_process.spawnSync( | |
| commandPath, | |
| [ | |
| '--install-extension', | |
| 'google.gemini-cli-vscode-ide-companion', | |
| '--force', | |
| ], | |
| { stdio: 'pipe', shell: this.platform === 'win32' }, | |
| ); | |
| if (result.status !== 0) { | |
| throw new Error( | |
| `Failed to install extension: ${result.stderr?.toString()}`, | |
| ); | |
| } | |
| return { | |
| success: true, | |
| message: `${this.ideInfo.displayName} companion extension was installed successfully.`, | |
| }; | |
| } catch { | |
| return { | |
| success: false, | |
| message: `Failed to install ${this.ideInfo.displayName} companion extension. Please try installing '${GEMINI_CLI_COMPANION_EXTENSION_NAME}' manually from the ${this.ideInfo.displayName} extension marketplace.`, | |
| }; | |
| } | |
| } | |
| } | |
| class AntigravityInstaller implements IdeInstaller { | |
| constructor( | |
| readonly ideInfo: IdeInfo, | |
| readonly platform = process.platform, | |
| ) {} | |
| async install(): Promise<InstallResult> { | |
| const envCommand = process.env['ANTIGRAVITY_CLI_ALIAS']; | |
| const safeCommandPattern = /^[a-zA-Z0-9.\-_/\\]+$/; | |
| const sanitizedEnvCommand = | |
| envCommand && safeCommandPattern.test(envCommand) | |
| ? envCommand | |
| : undefined; | |
| const fallbackCommands = | |
| this.platform === 'win32' | |
| ? ['agy.cmd', 'antigravity.cmd'] | |
| : ['agy', 'antigravity']; | |
| const commands = [ | |
| ...(sanitizedEnvCommand ? [sanitizedEnvCommand] : []), | |
| ...fallbackCommands, | |
| ].filter( | |
| (command, index, allCommands) => allCommands.indexOf(command) === index, | |
| ); | |
| let commandPath: string | null = null; | |
| for (const command of commands) { | |
| commandPath = await findCommand(command, this.platform); | |
| if (commandPath) { | |
| break; | |
| } | |
| } | |
| if (!commandPath) { | |
| const supportedCommands = fallbackCommands.join(', '); | |
| return { | |
| success: false, | |
| message: `Antigravity CLI not found. Please ensure one of these commands is in your system's PATH: ${supportedCommands}.`, | |
| }; | |
| } | |
| try { | |
| const result = child_process.spawnSync( | |
| commandPath, | |
| [ | |
| '--install-extension', | |
| 'google.gemini-cli-vscode-ide-companion', | |
| '--force', | |
| ], | |
| { stdio: 'pipe', shell: this.platform === 'win32' }, | |
| ); | |
| if (result.status !== 0) { | |
| throw new Error( | |
| `Failed to install extension: ${result.stderr?.toString()}`, | |
| ); | |
| } | |
| return { | |
| success: true, | |
| message: `${this.ideInfo.displayName} companion extension was installed successfully.`, | |
| }; | |
| } catch { | |
| return { | |
| success: false, | |
| message: `Failed to install ${this.ideInfo.displayName} companion extension. Please try installing '${GEMINI_CLI_COMPANION_EXTENSION_NAME}' manually from the ${this.ideInfo.displayName} extension marketplace.`, | |
| }; | |
| } | |
| } | |
| } | |
| export function getIdeInstaller( | |
| ide: IdeInfo, | |
| platform = process.platform, | |
| ): IdeInstaller | null { | |
| switch (ide.name) { | |
| case IDE_DEFINITIONS.vscode.name: | |
| case IDE_DEFINITIONS.firebasestudio.name: | |
| return new VsCodeInstaller(ide, platform); | |
| case IDE_DEFINITIONS.positron.name: | |
| return new PositronInstaller(ide, platform); | |
| case IDE_DEFINITIONS.antigravity.name: | |
| return new AntigravityInstaller(ide, platform); | |
| default: | |
| return null; | |
| } | |
| } | |