summaryrefslogtreecommitdiff
path: root/packages/cli/src/ui/commands/ideCommand.ts
diff options
context:
space:
mode:
authorShreya Keshive <[email protected]>2025-07-16 18:36:14 -0400
committerGitHub <[email protected]>2025-07-16 22:36:14 +0000
commitab9eb9377fdfe7823be8ea0c7c394c5368b28951 (patch)
treead7f0ebf45902513d129d4eb09897a5345cad195 /packages/cli/src/ui/commands/ideCommand.ts
parent69a8ae6a89918f4255304975f8653ff808264bc8 (diff)
Add /ide status & /ide install commands to manage IDE integration (#4265)
Diffstat (limited to 'packages/cli/src/ui/commands/ideCommand.ts')
-rw-r--r--packages/cli/src/ui/commands/ideCommand.ts165
1 files changed, 165 insertions, 0 deletions
diff --git a/packages/cli/src/ui/commands/ideCommand.ts b/packages/cli/src/ui/commands/ideCommand.ts
new file mode 100644
index 00000000..0251e619
--- /dev/null
+++ b/packages/cli/src/ui/commands/ideCommand.ts
@@ -0,0 +1,165 @@
+/**
+ * @license
+ * Copyright 2025 Google LLC
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { fileURLToPath } from 'url';
+import {
+ Config,
+ getMCPDiscoveryState,
+ getMCPServerStatus,
+ IDE_SERVER_NAME,
+ MCPDiscoveryState,
+ MCPServerStatus,
+} from '@google/gemini-cli-core';
+import {
+ CommandContext,
+ SlashCommand,
+ SlashCommandActionReturn,
+} from './types.js';
+import * as child_process from 'child_process';
+import * as process from 'process';
+import { glob } from 'glob';
+import * as path from 'path';
+
+const VSCODE_COMMAND = process.platform === 'win32' ? 'code.cmd' : 'code';
+const VSCODE_COMPANION_EXTENSION_FOLDER = 'vscode-ide-companion';
+
+function isVSCodeInstalled(): boolean {
+ try {
+ child_process.execSync(
+ process.platform === 'win32'
+ ? `where.exe ${VSCODE_COMMAND}`
+ : `command -v ${VSCODE_COMMAND}`,
+ { stdio: 'ignore' },
+ );
+ return true;
+ } catch {
+ return false;
+ }
+}
+
+export const ideCommand = (config: Config | null): SlashCommand | null => {
+ if (!config?.getIdeMode()) {
+ return null;
+ }
+
+ return {
+ name: 'ide',
+ description: 'manage IDE integration',
+ subCommands: [
+ {
+ name: 'status',
+ description: 'check status of IDE integration',
+ action: (_context: CommandContext): SlashCommandActionReturn => {
+ const status = getMCPServerStatus(IDE_SERVER_NAME);
+ const discoveryState = getMCPDiscoveryState();
+ switch (status) {
+ case MCPServerStatus.CONNECTED:
+ return {
+ type: 'message',
+ messageType: 'info',
+ content: `🟢 Connected`,
+ };
+ case MCPServerStatus.CONNECTING:
+ return {
+ type: 'message',
+ messageType: 'info',
+ content: `🔄 Initializing...`,
+ };
+ case MCPServerStatus.DISCONNECTED:
+ default:
+ if (discoveryState === MCPDiscoveryState.IN_PROGRESS) {
+ return {
+ type: 'message',
+ messageType: 'info',
+ content: `🔄 Initializing...`,
+ };
+ } else {
+ return {
+ type: 'message',
+ messageType: 'error',
+ content: `🔴 Disconnected`,
+ };
+ }
+ }
+ },
+ },
+ {
+ name: 'install',
+ description: 'install required VS Code companion extension',
+ action: async (context) => {
+ if (!isVSCodeInstalled()) {
+ context.ui.addItem(
+ {
+ type: 'error',
+ text: `VS Code command-line tool "${VSCODE_COMMAND}" not found in your PATH.`,
+ },
+ Date.now(),
+ );
+ return;
+ }
+
+ const bundleDir = path.dirname(fileURLToPath(import.meta.url));
+ // The VSIX file is copied to the bundle directory as part of the build.
+ let vsixFiles = glob.sync(path.join(bundleDir, '*.vsix'));
+ if (vsixFiles.length === 0) {
+ // If the VSIX file is not in the bundle, it might be a dev
+ // environment running with `npm start`. Look for it in the original
+ // package location, relative to the bundle dir.
+ const devPath = path.join(
+ bundleDir,
+ '..',
+ '..',
+ '..',
+ '..',
+ '..',
+ VSCODE_COMPANION_EXTENSION_FOLDER,
+ '*.vsix',
+ );
+ vsixFiles = glob.sync(devPath);
+ }
+ if (vsixFiles.length === 0) {
+ context.ui.addItem(
+ {
+ type: 'error',
+ text: 'Could not find the required VS Code companion extension. Please file a bug via /bug.',
+ },
+ Date.now(),
+ );
+ return;
+ }
+
+ const vsixPath = vsixFiles[0];
+ const command = `${VSCODE_COMMAND} --install-extension ${vsixPath} --force`;
+ context.ui.addItem(
+ {
+ type: 'info',
+ text: `Installing VS Code companion extension...`,
+ },
+ Date.now(),
+ );
+ try {
+ child_process.execSync(command, { stdio: 'pipe' });
+ context.ui.addItem(
+ {
+ type: 'info',
+ text: 'VS Code companion extension installed successfully. Restart gemini-cli in a fresh terminal window.',
+ },
+ Date.now(),
+ );
+ } catch (_error) {
+ context.ui.addItem(
+ {
+ type: 'error',
+ text: `Failed to install VS Code companion extension.`,
+ },
+ Date.now(),
+ );
+ }
+ },
+ },
+ ],
+ };
+};