mirror of
https://github.com/QwenLM/qwen-code.git
synced 2025-12-20 16:57:46 +00:00
Launch VS Code IDE Integration (#6063)
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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> = {
|
||||
|
||||
@@ -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,
|
||||
);
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
});
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user