summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/cli/src/ui/App.tsx3
-rw-r--r--packages/cli/src/ui/IdeIntegrationNudge.tsx12
-rw-r--r--packages/core/src/ide/detect-ide.ts43
-rw-r--r--packages/core/src/ide/ide-installer.test.ts52
-rw-r--r--packages/core/src/ide/ide-installer.ts22
5 files changed, 118 insertions, 14 deletions
diff --git a/packages/cli/src/ui/App.tsx b/packages/cli/src/ui/App.tsx
index aff3fac3..c4f67294 100644
--- a/packages/cli/src/ui/App.tsx
+++ b/packages/cli/src/ui/App.tsx
@@ -939,8 +939,7 @@ const App = ({ config, settings, startupWarnings = [], version }: AppProps) => {
{shouldShowIdePrompt ? (
<IdeIntegrationNudge
- question="Do you want to connect your VS Code editor to Gemini CLI?"
- description="If you select Yes, we'll install an extension that allows the CLI to access your open files and display diffs directly in VS Code."
+ ideName={config.getIdeClient().getDetectedIdeDisplayName()}
onComplete={handleIdePromptComplete}
/>
) : isFolderTrustDialogOpen ? (
diff --git a/packages/cli/src/ui/IdeIntegrationNudge.tsx b/packages/cli/src/ui/IdeIntegrationNudge.tsx
index 72cd1756..f0c6172d 100644
--- a/packages/cli/src/ui/IdeIntegrationNudge.tsx
+++ b/packages/cli/src/ui/IdeIntegrationNudge.tsx
@@ -13,14 +13,12 @@ import {
export type IdeIntegrationNudgeResult = 'yes' | 'no' | 'dismiss';
interface IdeIntegrationNudgeProps {
- question: string;
- description?: string;
+ ideName?: string;
onComplete: (result: IdeIntegrationNudgeResult) => void;
}
export function IdeIntegrationNudge({
- question,
- description,
+ ideName,
onComplete,
}: IdeIntegrationNudgeProps) {
useInput((_input, key) => {
@@ -56,9 +54,11 @@ export function IdeIntegrationNudge({
<Box marginBottom={1} flexDirection="column">
<Text>
<Text color="yellow">{'> '}</Text>
- {question}
+ {`Do you want to connect your ${ideName ?? 'your'} editor to Gemini CLI?`}
</Text>
- {description && <Text dimColor>{description}</Text>}
+ <Text
+ dimColor
+ >{`If you select Yes, we'll install an extension that allows the CLI to access your open files and display diffs directly in ${ideName ?? 'your editor'}.`}</Text>
</Box>
<RadioButtonSelect
items={OPTIONS}
diff --git a/packages/core/src/ide/detect-ide.ts b/packages/core/src/ide/detect-ide.ts
index f3d8cc63..759c4103 100644
--- a/packages/core/src/ide/detect-ide.ts
+++ b/packages/core/src/ide/detect-ide.ts
@@ -6,12 +6,33 @@
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 {
switch (ide) {
case DetectedIde.VSCode:
return 'VS Code';
+ case DetectedIde.VSCodium:
+ return 'VSCodium';
+ case DetectedIde.Cursor:
+ return 'Cursor';
+ case DetectedIde.CloudShell:
+ return 'Cloud Shell';
+ case DetectedIde.Codespaces:
+ return 'GitHub Codespaces';
+ case DetectedIde.Windsurf:
+ return 'Windsurf';
+ case DetectedIde.FirebaseStudio:
+ return 'Firebase Studio';
+ case DetectedIde.Trae:
+ return 'Trae';
default: {
// This ensures that if a new IDE is added to the enum, we get a compile-time error.
const exhaustiveCheck: never = ide;
@@ -21,8 +42,24 @@ export function getIdeDisplayName(ide: DetectedIde): string {
}
export function detectIde(): DetectedIde | undefined {
- if (process.env.TERM_PROGRAM === 'vscode') {
- return DetectedIde.VSCode;
+ // Only VSCode-based integrations are currently supported.
+ if (process.env.TERM_PROGRAM !== 'vscode') {
+ return undefined;
}
- return undefined;
+ if (process.env.CURSOR_TRACE_ID) {
+ return DetectedIde.Cursor;
+ }
+ if (process.env.CODESPACES) {
+ return DetectedIde.Codespaces;
+ }
+ if (process.env.EDITOR_IN_CLOUD_SHELL) {
+ return DetectedIde.CloudShell;
+ }
+ if (process.env.TERM_PRODUCT === 'Trae') {
+ return DetectedIde.Trae;
+ }
+ if (process.env.FIREBASE_DEPLOY_AGENT) {
+ return DetectedIde.FirebaseStudio;
+ }
+ return DetectedIde.VSCode;
}
diff --git a/packages/core/src/ide/ide-installer.test.ts b/packages/core/src/ide/ide-installer.test.ts
index 698c3173..1afd7a36 100644
--- a/packages/core/src/ide/ide-installer.test.ts
+++ b/packages/core/src/ide/ide-installer.test.ts
@@ -24,9 +24,17 @@ describe('ide-installer', () => {
expect(installer).toBeInstanceOf(Object);
});
- it('should return null for an unknown IDE', () => {
+ 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);
- expect(installer).toBeNull();
+ // Assuming DefaultIDEInstaller is the fallback
+ expect(installer).not.toBeNull();
+ expect(installer).toBeInstanceOf(Object);
});
});
@@ -59,4 +67,44 @@ 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',
+ );
+ });
+ });
+ });
});
diff --git a/packages/core/src/ide/ide-installer.ts b/packages/core/src/ide/ide-installer.ts
index 7db8e2d2..e6192bfa 100644
--- a/packages/core/src/ide/ide-installer.ts
+++ b/packages/core/src/ide/ide-installer.ts
@@ -147,11 +147,31 @@ 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 null;
+ return new OpenVSXInstaller();
}
}