[ide-mode] Update installation logic and nudge (#6068)

This commit is contained in:
christine betts
2025-08-12 20:08:47 +00:00
committed by GitHub
parent 8524cce7b9
commit 74fd0841d0
8 changed files with 78 additions and 113 deletions

View File

@@ -6,33 +6,43 @@
export enum DetectedIde {
VSCode = 'vscode',
VSCodium = 'vscodium',
Cursor = 'cursor',
CloudShell = 'cloudshell',
Codespaces = 'codespaces',
Windsurf = 'windsurf',
FirebaseStudio = 'firebasestudio',
Trae = 'trae',
}
export function getIdeDisplayName(ide: DetectedIde): string {
export interface IdeInfo {
displayName: string;
}
export function getIdeInfo(ide: DetectedIde): IdeInfo {
switch (ide) {
case DetectedIde.VSCode:
return 'VS Code';
case DetectedIde.VSCodium:
return 'VSCodium';
return {
displayName: 'VS Code',
};
case DetectedIde.Cursor:
return 'Cursor';
return {
displayName: 'Cursor',
};
case DetectedIde.CloudShell:
return 'Cloud Shell';
return {
displayName: 'Cloud Shell',
};
case DetectedIde.Codespaces:
return 'GitHub Codespaces';
case DetectedIde.Windsurf:
return 'Windsurf';
return {
displayName: 'GitHub Codespaces',
};
case DetectedIde.FirebaseStudio:
return 'Firebase Studio';
return {
displayName: 'Firebase Studio',
};
case DetectedIde.Trae:
return 'Trae';
return {
displayName: 'Trae',
};
default: {
// This ensures that if a new IDE is added to the enum, we get a compile-time error.
const exhaustiveCheck: never = ide;

View File

@@ -6,11 +6,7 @@
import * as fs from 'node:fs';
import * as path from 'node:path';
import {
detectIde,
DetectedIde,
getIdeDisplayName,
} from '../ide/detect-ide.js';
import { detectIde, DetectedIde, getIdeInfo } from '../ide/detect-ide.js';
import {
ideContext,
IdeContextNotificationSchema,
@@ -68,7 +64,7 @@ export class IdeClient {
private constructor() {
this.currentIde = detectIde();
if (this.currentIde) {
this.currentIdeDisplayName = getIdeDisplayName(this.currentIde);
this.currentIdeDisplayName = getIdeInfo(this.currentIde).displayName;
}
}
@@ -86,7 +82,7 @@ export class IdeClient {
`IDE integration is not supported in your current environment. To use this feature, run Gemini CLI in one of these supported IDEs: ${Object.values(
DetectedIde,
)
.map((ide) => getIdeDisplayName(ide))
.map((ide) => getIdeInfo(ide).displayName)
.join(', ')}`,
false,
);

View File

@@ -23,19 +23,6 @@ describe('ide-installer', () => {
// A more specific check might be needed if we export the class
expect(installer).toBeInstanceOf(Object);
});
it('should return an OpenVSXInstaller for "vscodium"', () => {
const installer = getIdeInstaller(DetectedIde.VSCodium);
expect(installer).not.toBeNull();
expect(installer).toBeInstanceOf(Object);
});
it('should return a DefaultIDEInstaller for an unknown IDE', () => {
const installer = getIdeInstaller('unknown' as DetectedIde);
// Assuming DefaultIDEInstaller is the fallback
expect(installer).not.toBeNull();
expect(installer).toBeInstanceOf(Object);
});
});
describe('VsCodeInstaller', () => {
@@ -67,44 +54,4 @@ describe('ide-installer', () => {
});
});
});
describe('OpenVSXInstaller', () => {
let installer: IdeInstaller;
beforeEach(() => {
installer = getIdeInstaller(DetectedIde.VSCodium)!;
});
afterEach(() => {
vi.restoreAllMocks();
});
describe('install', () => {
it('should call execSync with the correct command and return success', async () => {
const execSyncSpy = vi
.spyOn(child_process, 'execSync')
.mockImplementation(() => '');
const result = await installer.install();
expect(execSyncSpy).toHaveBeenCalledWith(
'npx ovsx get google.gemini-cli-vscode-ide-companion',
{ stdio: 'pipe' },
);
expect(result.success).toBe(true);
expect(result.message).toContain(
'VS Code companion extension was installed successfully from OpenVSX',
);
});
it('should return a failure message on failed installation', async () => {
vi.spyOn(child_process, 'execSync').mockImplementation(() => {
throw new Error('Command failed');
});
const result = await installer.install();
expect(result.success).toBe(false);
expect(result.message).toContain(
'Failed to install VS Code companion extension from OpenVSX',
);
});
});
});
});

View File

@@ -147,31 +147,11 @@ class VsCodeInstaller implements IdeInstaller {
}
}
class OpenVSXInstaller implements IdeInstaller {
async install(): Promise<InstallResult> {
// TODO: Use the correct extension path.
const command = `npx ovsx get google.gemini-cli-vscode-ide-companion`;
try {
child_process.execSync(command, { stdio: 'pipe' });
return {
success: true,
message:
'VS Code companion extension was installed successfully from OpenVSX. Please restart your terminal to complete the setup.',
};
} catch (_error) {
return {
success: false,
message: `Failed to install VS Code companion extension from OpenVSX. Please try installing it manually.`,
};
}
}
}
export function getIdeInstaller(ide: DetectedIde): IdeInstaller | null {
switch (ide) {
case DetectedIde.VSCode:
return new VsCodeInstaller();
default:
return new OpenVSXInstaller();
return null;
}
}

View File

@@ -50,7 +50,7 @@ export * from './services/gitService.js';
export * from './ide/ide-client.js';
export * from './ide/ideContext.js';
export * from './ide/ide-installer.js';
export { getIdeDisplayName, DetectedIde } from './ide/detect-ide.js';
export { getIdeInfo, DetectedIde, IdeInfo } from './ide/detect-ide.js';
// Export Shell Execution Service
export * from './services/shellExecutionService.js';