mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-03-10 22:21:22 -07:00
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> Co-authored-by: Shreya Keshive <shreyakeshive@google.com>
This commit is contained in:
@@ -28,6 +28,7 @@ describe('detectIde', () => {
|
||||
vi.stubEnv('TERM_PRODUCT', '');
|
||||
vi.stubEnv('MONOSPACE_ENV', '');
|
||||
vi.stubEnv('REPLIT_USER', '');
|
||||
vi.stubEnv('POSITRON', '');
|
||||
vi.stubEnv('__COG_BASHRC_SOURCED', '');
|
||||
vi.stubEnv('TERMINAL_EMULATOR', '');
|
||||
});
|
||||
@@ -100,6 +101,7 @@ describe('detectIde', () => {
|
||||
vi.stubEnv('TERM_PROGRAM', 'vscode');
|
||||
vi.stubEnv('MONOSPACE_ENV', '');
|
||||
vi.stubEnv('CURSOR_TRACE_ID', '');
|
||||
vi.stubEnv('POSITRON', '');
|
||||
expect(detectIde(ideProcessInfo)).toBe(IDE_DEFINITIONS.vscode);
|
||||
});
|
||||
|
||||
@@ -107,11 +109,21 @@ describe('detectIde', () => {
|
||||
vi.stubEnv('TERM_PROGRAM', 'vscode');
|
||||
vi.stubEnv('MONOSPACE_ENV', '');
|
||||
vi.stubEnv('CURSOR_TRACE_ID', '');
|
||||
vi.stubEnv('POSITRON', '');
|
||||
expect(detectIde(ideProcessInfoNoCode)).toBe(IDE_DEFINITIONS.vscodefork);
|
||||
});
|
||||
|
||||
it('should detect positron when POSITRON is set', () => {
|
||||
vi.stubEnv('TERM_PROGRAM', 'vscode');
|
||||
vi.stubEnv('MONOSPACE_ENV', '');
|
||||
vi.stubEnv('CURSOR_TRACE_ID', '');
|
||||
vi.stubEnv('POSITRON', '1');
|
||||
expect(detectIde(ideProcessInfoNoCode)).toBe(IDE_DEFINITIONS.positron);
|
||||
});
|
||||
|
||||
it('should detect AntiGravity', () => {
|
||||
vi.stubEnv('TERM_PROGRAM', 'vscode');
|
||||
vi.stubEnv('POSITRON', '');
|
||||
vi.stubEnv('ANTIGRAVITY_CLI_ALIAS', 'agy');
|
||||
expect(detectIde(ideProcessInfo)).toBe(IDE_DEFINITIONS.antigravity);
|
||||
});
|
||||
@@ -196,6 +208,7 @@ describe('detectIde with ideInfoFromFile', () => {
|
||||
vi.stubEnv('TERM_PRODUCT', '');
|
||||
vi.stubEnv('MONOSPACE_ENV', '');
|
||||
vi.stubEnv('REPLIT_USER', '');
|
||||
vi.stubEnv('POSITRON', '');
|
||||
vi.stubEnv('__COG_BASHRC_SOURCED', '');
|
||||
vi.stubEnv('TERMINAL_EMULATOR', '');
|
||||
});
|
||||
@@ -212,6 +225,7 @@ describe('detectIde with ideInfoFromFile', () => {
|
||||
const ideInfoFromFile = { displayName: 'Custom IDE' };
|
||||
vi.stubEnv('TERM_PROGRAM', 'vscode');
|
||||
vi.stubEnv('CURSOR_TRACE_ID', '');
|
||||
vi.stubEnv('POSITRON', '');
|
||||
expect(detectIde(ideProcessInfo, ideInfoFromFile)).toBe(
|
||||
IDE_DEFINITIONS.vscode,
|
||||
);
|
||||
@@ -221,6 +235,7 @@ describe('detectIde with ideInfoFromFile', () => {
|
||||
const ideInfoFromFile = { name: 'custom-ide' };
|
||||
vi.stubEnv('TERM_PROGRAM', 'vscode');
|
||||
vi.stubEnv('CURSOR_TRACE_ID', '');
|
||||
vi.stubEnv('POSITRON', '');
|
||||
expect(detectIde(ideProcessInfo, ideInfoFromFile)).toBe(
|
||||
IDE_DEFINITIONS.vscode,
|
||||
);
|
||||
|
||||
@@ -14,6 +14,7 @@ export const IDE_DEFINITIONS = {
|
||||
trae: { name: 'trae', displayName: 'Trae' },
|
||||
vscode: { name: 'vscode', displayName: 'VS Code' },
|
||||
vscodefork: { name: 'vscodefork', displayName: 'IDE' },
|
||||
positron: { name: 'positron', displayName: 'Positron' },
|
||||
antigravity: { name: 'antigravity', displayName: 'Antigravity' },
|
||||
sublimetext: { name: 'sublimetext', displayName: 'Sublime Text' },
|
||||
jetbrains: { name: 'jetbrains', displayName: 'JetBrains IDE' },
|
||||
@@ -68,6 +69,9 @@ export function detectIdeFromEnv(): IdeInfo {
|
||||
if (process.env['MONOSPACE_ENV']) {
|
||||
return IDE_DEFINITIONS.firebasestudio;
|
||||
}
|
||||
if (process.env['POSITRON'] === '1') {
|
||||
return IDE_DEFINITIONS.positron;
|
||||
}
|
||||
if (process.env['TERM_PROGRAM'] === 'sublime') {
|
||||
return IDE_DEFINITIONS.sublimetext;
|
||||
}
|
||||
|
||||
@@ -202,6 +202,53 @@ describe('ide-installer', () => {
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('PositronInstaller', () => {
|
||||
function setup({
|
||||
execSync = () => '',
|
||||
platform = 'linux' as NodeJS.Platform,
|
||||
existsResult = false,
|
||||
}: {
|
||||
execSync?: () => string;
|
||||
platform?: NodeJS.Platform;
|
||||
existsResult?: boolean;
|
||||
} = {}) {
|
||||
vi.spyOn(child_process, 'execSync').mockImplementation(execSync);
|
||||
vi.spyOn(fs, 'existsSync').mockReturnValue(existsResult);
|
||||
const installer = getIdeInstaller(IDE_DEFINITIONS.positron, platform)!;
|
||||
|
||||
return { installer };
|
||||
}
|
||||
|
||||
it('installs the extension', async () => {
|
||||
vi.stubEnv('POSITRON', '1');
|
||||
const { installer } = setup({});
|
||||
const result = await installer.install();
|
||||
|
||||
expect(result.success).toBe(true);
|
||||
expect(child_process.spawnSync).toHaveBeenCalledWith(
|
||||
'positron',
|
||||
[
|
||||
'--install-extension',
|
||||
'google.gemini-cli-vscode-ide-companion',
|
||||
'--force',
|
||||
],
|
||||
{ stdio: 'pipe', shell: false },
|
||||
);
|
||||
});
|
||||
|
||||
it('returns a failure message if the cli is not found', async () => {
|
||||
const { installer } = setup({
|
||||
execSync: () => {
|
||||
throw new Error('Command not found');
|
||||
},
|
||||
});
|
||||
const result = await installer.install();
|
||||
|
||||
expect(result.success).toBe(false);
|
||||
expect(result.message).toContain('Positron CLI not found');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('AntigravityInstaller', () => {
|
||||
|
||||
@@ -51,39 +51,88 @@ async function findCommand(
|
||||
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
|
||||
locations.push(
|
||||
'/Applications/Visual Studio Code.app/Contents/Resources/app/bin/code',
|
||||
path.join(homeDir, 'Library/Application Support/Code/bin/code'),
|
||||
);
|
||||
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
|
||||
locations.push(
|
||||
'/usr/share/code/bin/code',
|
||||
'/snap/bin/code',
|
||||
path.join(homeDir, '.local/share/code/bin/code'),
|
||||
);
|
||||
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
|
||||
locations.push(
|
||||
path.join(
|
||||
process.env['ProgramFiles'] || 'C:\\Program Files',
|
||||
'Microsoft VS Code',
|
||||
'bin',
|
||||
'code.cmd',
|
||||
),
|
||||
path.join(
|
||||
homeDir,
|
||||
'AppData',
|
||||
'Local',
|
||||
'Programs',
|
||||
'Microsoft VS Code',
|
||||
'bin',
|
||||
'code.cmd',
|
||||
),
|
||||
);
|
||||
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,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,6 +195,56 @@ class VsCodeInstaller implements IdeInstaller {
|
||||
}
|
||||
}
|
||||
|
||||
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 (_error) {
|
||||
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,
|
||||
@@ -207,6 +306,8 @@ export function getIdeInstaller(
|
||||
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:
|
||||
|
||||
@@ -462,9 +462,20 @@ describe('ClearcutLogger', () => {
|
||||
TERM_PROGRAM: 'vscode',
|
||||
GITHUB_SHA: undefined,
|
||||
MONOSPACE_ENV: '',
|
||||
POSITRON: '',
|
||||
},
|
||||
expected: 'vscode',
|
||||
},
|
||||
{
|
||||
name: 'Positron via TERM_PROGRAM',
|
||||
env: {
|
||||
TERM_PROGRAM: 'vscode',
|
||||
GITHUB_SHA: undefined,
|
||||
MONOSPACE_ENV: '',
|
||||
POSITRON: '1',
|
||||
},
|
||||
expected: 'positron',
|
||||
},
|
||||
{
|
||||
name: 'SURFACE env var',
|
||||
env: { SURFACE: 'ide-1234' },
|
||||
|
||||
Reference in New Issue
Block a user