Launch VS Code IDE Integration (#6063)

This commit is contained in:
Shreya Keshive
2025-08-12 17:08:07 -04:00
committed by GitHub
parent d219f90132
commit 3a87712c1a
19 changed files with 21 additions and 121 deletions

View File

@@ -191,7 +191,6 @@ export interface ConfigParameters {
blockedMcpServers?: Array<{ name: string; extensionName: string }>;
noBrowser?: boolean;
summarizeToolOutput?: Record<string, SummarizeToolOutputSettings>;
ideModeFeature?: boolean;
folderTrustFeature?: boolean;
folderTrust?: boolean;
ideMode?: boolean;
@@ -240,7 +239,6 @@ export class Config {
private readonly model: string;
private readonly extensionContextFilePaths: string[];
private readonly noBrowser: boolean;
private readonly ideModeFeature: boolean;
private readonly folderTrustFeature: boolean;
private readonly folderTrust: boolean;
private ideMode: boolean;
@@ -317,7 +315,6 @@ export class Config {
this._blockedMcpServers = params.blockedMcpServers ?? [];
this.noBrowser = params.noBrowser ?? false;
this.summarizeToolOutput = params.summarizeToolOutput;
this.ideModeFeature = params.ideModeFeature ?? false;
this.folderTrustFeature = params.folderTrustFeature ?? false;
this.folderTrust = params.folderTrust ?? false;
this.ideMode = params.ideMode ?? false;
@@ -654,10 +651,6 @@ export class Config {
return this.summarizeToolOutput;
}
getIdeModeFeature(): boolean {
return this.ideModeFeature;
}
getIdeMode(): boolean {
return this.ideMode;
}

View File

@@ -667,7 +667,7 @@ describe('Gemini Client (client.ts)', () => {
});
describe('sendMessageStream', () => {
it('should include editor context when ideModeFeature is enabled', async () => {
it('should include editor context when ideMode is enabled', async () => {
// Arrange
vi.mocked(ideContext.getIdeContext).mockReturnValue({
workspaceState: {
@@ -691,7 +691,7 @@ describe('Gemini Client (client.ts)', () => {
},
});
vi.spyOn(client['config'], 'getIdeModeFeature').mockReturnValue(true);
vi.spyOn(client['config'], 'getIdeMode').mockReturnValue(true);
const mockStream = (async function* () {
yield { type: 'content', value: 'Hello' };
@@ -751,7 +751,7 @@ ${JSON.stringify(
});
});
it('should not add context if ideModeFeature is enabled but no open files', async () => {
it('should not add context if ideMode is enabled but no open files', async () => {
// Arrange
vi.mocked(ideContext.getIdeContext).mockReturnValue({
workspaceState: {
@@ -759,7 +759,7 @@ ${JSON.stringify(
},
});
vi.spyOn(client['config'], 'getIdeModeFeature').mockReturnValue(true);
vi.spyOn(client['config'], 'getIdeMode').mockReturnValue(true);
const mockStream = (async function* () {
yield { type: 'content', value: 'Hello' };
@@ -798,7 +798,7 @@ ${JSON.stringify(
);
});
it('should add context if ideModeFeature is enabled and there is one active file', async () => {
it('should add context if ideMode is enabled and there is one active file', async () => {
// Arrange
vi.mocked(ideContext.getIdeContext).mockReturnValue({
workspaceState: {
@@ -814,7 +814,7 @@ ${JSON.stringify(
},
});
vi.spyOn(client['config'], 'getIdeModeFeature').mockReturnValue(true);
vi.spyOn(client['config'], 'getIdeMode').mockReturnValue(true);
const mockStream = (async function* () {
yield { type: 'content', value: 'Hello' };
@@ -873,7 +873,7 @@ ${JSON.stringify(
});
});
it('should add context if ideModeFeature is enabled and there are open files but no active file', async () => {
it('should add context if ideMode is enabled and there are open files but no active file', async () => {
// Arrange
vi.mocked(ideContext.getIdeContext).mockReturnValue({
workspaceState: {
@@ -890,7 +890,7 @@ ${JSON.stringify(
},
});
vi.spyOn(client['config'], 'getIdeModeFeature').mockReturnValue(true);
vi.spyOn(client['config'], 'getIdeMode').mockReturnValue(true);
const mockStream = (async function* () {
yield { type: 'content', value: 'Hello' };
@@ -1226,7 +1226,7 @@ ${JSON.stringify(
beforeEach(() => {
client['forceFullIdeContext'] = false; // Reset before each delta test
vi.spyOn(client, 'tryCompressChat').mockResolvedValue(null);
vi.spyOn(client['config'], 'getIdeModeFeature').mockReturnValue(true);
vi.spyOn(client['config'], 'getIdeMode').mockReturnValue(true);
mockTurnRunFn.mockReturnValue(mockStream);
const mockChat: Partial<GeminiChat> = {

View File

@@ -444,7 +444,7 @@ export class GeminiClient {
yield { type: GeminiEventType.ChatCompressed, value: compressed };
}
if (this.config.getIdeModeFeature() && this.config.getIdeMode()) {
if (this.config.getIdeMode()) {
const { contextParts, newIdeContext } = this.getIdeContextParts(
this.forceFullIdeContext || this.getHistory().length === 0,
);

View File

@@ -6,15 +6,12 @@
import * as child_process from 'child_process';
import * as process from 'process';
import { glob } from 'glob';
import * as path from 'path';
import * as fs from 'fs';
import * as os from 'os';
import { fileURLToPath } from 'url';
import { DetectedIde } from './detect-ide.js';
const VSCODE_COMMAND = process.platform === 'win32' ? 'code.cmd' : 'code';
const VSCODE_COMPANION_EXTENSION_FOLDER = 'vscode-ide-companion';
export interface IdeInstaller {
install(): Promise<InstallResult>;
@@ -103,34 +100,7 @@ class VsCodeInstaller implements IdeInstaller {
};
}
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, // .../packages/core/dist/src/ide
'..', // .../packages/core/dist/src
'..', // .../packages/core/dist
'..', // .../packages/core
'..', // .../packages
VSCODE_COMPANION_EXTENSION_FOLDER,
'*.vsix',
);
vsixFiles = glob.sync(devPath);
}
if (vsixFiles.length === 0) {
return {
success: false,
message:
'Could not find the required VS Code companion extension. Please file a bug via /bug.',
};
}
const vsixPath = vsixFiles[0];
const command = `"${commandPath}" --install-extension "${vsixPath}" --force`;
const command = `"${commandPath}" --install-extension google.gemini-cli-vscode-ide-companion --force`;
try {
child_process.execSync(command, { stdio: 'pipe' });
return {

View File

@@ -62,7 +62,6 @@ describe('EditTool', () => {
getWorkspaceContext: () => createMockWorkspaceContext(rootDir),
getIdeClient: () => undefined,
getIdeMode: () => false,
getIdeModeFeature: () => false,
// getGeminiConfig: () => ({ apiKey: 'test-api-key' }), // This was not a real Config method
// Add other properties/methods of Config if EditTool uses them
// Minimal other methods to satisfy Config type if needed by EditTool constructor or other direct uses:
@@ -810,7 +809,6 @@ describe('EditTool', () => {
}),
};
(mockConfig as any).getIdeMode = () => true;
(mockConfig as any).getIdeModeFeature = () => true;
(mockConfig as any).getIdeClient = () => ideClient;
});

View File

@@ -250,7 +250,6 @@ class EditToolInvocation implements ToolInvocation<EditToolParams, ToolResult> {
);
const ideClient = this.config.getIdeClient();
const ideConfirmation =
this.config.getIdeModeFeature() &&
this.config.getIdeMode() &&
ideClient?.getConnectionStatus().status === IDEConnectionStatus.Connected
? ideClient.openDiff(this.params.file_path, editData.newContent)

View File

@@ -58,7 +58,6 @@ const mockConfigInternal = {
getGeminiClient: vi.fn(), // Initialize as a plain mock function
getIdeClient: vi.fn(),
getIdeMode: vi.fn(() => false),
getIdeModeFeature: vi.fn(() => false),
getWorkspaceContext: () => createMockWorkspaceContext(rootDir),
getApiKey: () => 'test-key',
getModel: () => 'test-model',

View File

@@ -195,7 +195,6 @@ export class WriteFileTool
const ideClient = this.config.getIdeClient();
const ideConfirmation =
this.config.getIdeModeFeature() &&
this.config.getIdeMode() &&
ideClient.getConnectionStatus().status === IDEConnectionStatus.Connected
? ideClient.openDiff(params.file_path, correctedContent)