Launch VS Code IDE Integration (#6063)
This commit is contained in:
parent
d219f90132
commit
3a87712c1a
|
@ -1010,33 +1010,6 @@ describe('loadCliConfig model selection', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('loadCliConfig ideModeFeature', () => {
|
|
||||||
const originalArgv = process.argv;
|
|
||||||
const originalEnv = { ...process.env };
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
vi.resetAllMocks();
|
|
||||||
vi.mocked(os.homedir).mockReturnValue('/mock/home/user');
|
|
||||||
process.env.GEMINI_API_KEY = 'test-api-key';
|
|
||||||
delete process.env.SANDBOX;
|
|
||||||
delete process.env.GEMINI_CLI_IDE_SERVER_PORT;
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
process.argv = originalArgv;
|
|
||||||
process.env = originalEnv;
|
|
||||||
vi.restoreAllMocks();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should be false by default', async () => {
|
|
||||||
process.argv = ['node', 'script.js'];
|
|
||||||
const settings: Settings = {};
|
|
||||||
const argv = await parseArguments();
|
|
||||||
const config = await loadCliConfig(settings, [], 'test-session', argv);
|
|
||||||
expect(config.getIdeModeFeature()).toBe(false);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('loadCliConfig folderTrustFeature', () => {
|
describe('loadCliConfig folderTrustFeature', () => {
|
||||||
const originalArgv = process.argv;
|
const originalArgv = process.argv;
|
||||||
const originalEnv = { ...process.env };
|
const originalEnv = { ...process.env };
|
||||||
|
|
|
@ -67,7 +67,6 @@ export interface CliArgs {
|
||||||
experimentalAcp: boolean | undefined;
|
experimentalAcp: boolean | undefined;
|
||||||
extensions: string[] | undefined;
|
extensions: string[] | undefined;
|
||||||
listExtensions: boolean | undefined;
|
listExtensions: boolean | undefined;
|
||||||
ideModeFeature: boolean | undefined;
|
|
||||||
proxy: string | undefined;
|
proxy: string | undefined;
|
||||||
includeDirectories: string[] | undefined;
|
includeDirectories: string[] | undefined;
|
||||||
}
|
}
|
||||||
|
@ -200,10 +199,6 @@ export async function parseArguments(): Promise<CliArgs> {
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
description: 'List all available extensions and exit.',
|
description: 'List all available extensions and exit.',
|
||||||
})
|
})
|
||||||
.option('ide-mode-feature', {
|
|
||||||
type: 'boolean',
|
|
||||||
description: 'Run in IDE mode?',
|
|
||||||
})
|
|
||||||
.option('proxy', {
|
.option('proxy', {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
description:
|
description:
|
||||||
|
@ -307,8 +302,6 @@ export async function loadCliConfig(
|
||||||
const memoryImportFormat = settings.memoryImportFormat || 'tree';
|
const memoryImportFormat = settings.memoryImportFormat || 'tree';
|
||||||
|
|
||||||
const ideMode = settings.ideMode ?? false;
|
const ideMode = settings.ideMode ?? false;
|
||||||
const ideModeFeature =
|
|
||||||
argv.ideModeFeature ?? settings.ideModeFeature ?? false;
|
|
||||||
|
|
||||||
const folderTrustFeature = settings.folderTrustFeature ?? false;
|
const folderTrustFeature = settings.folderTrustFeature ?? false;
|
||||||
const folderTrustSetting = settings.folderTrust ?? false;
|
const folderTrustSetting = settings.folderTrust ?? false;
|
||||||
|
@ -474,7 +467,6 @@ export async function loadCliConfig(
|
||||||
noBrowser: !!process.env.NO_BROWSER,
|
noBrowser: !!process.env.NO_BROWSER,
|
||||||
summarizeToolOutput: settings.summarizeToolOutput,
|
summarizeToolOutput: settings.summarizeToolOutput,
|
||||||
ideMode,
|
ideMode,
|
||||||
ideModeFeature,
|
|
||||||
chatCompression: settings.chatCompression,
|
chatCompression: settings.chatCompression,
|
||||||
folderTrustFeature,
|
folderTrustFeature,
|
||||||
folderTrust,
|
folderTrust,
|
||||||
|
|
|
@ -44,7 +44,6 @@ describe('SettingsSchema', () => {
|
||||||
'telemetry',
|
'telemetry',
|
||||||
'bugCommand',
|
'bugCommand',
|
||||||
'summarizeToolOutput',
|
'summarizeToolOutput',
|
||||||
'ideModeFeature',
|
|
||||||
'dnsResolutionOrder',
|
'dnsResolutionOrder',
|
||||||
'excludedProjectEnvVars',
|
'excludedProjectEnvVars',
|
||||||
'disableUpdateNag',
|
'disableUpdateNag',
|
||||||
|
|
|
@ -395,15 +395,7 @@ export const SETTINGS_SCHEMA = {
|
||||||
description: 'Settings for summarizing tool output.',
|
description: 'Settings for summarizing tool output.',
|
||||||
showInDialog: false,
|
showInDialog: false,
|
||||||
},
|
},
|
||||||
ideModeFeature: {
|
|
||||||
type: 'boolean',
|
|
||||||
label: 'IDE Mode Feature Flag',
|
|
||||||
category: 'Advanced',
|
|
||||||
requiresRestart: true,
|
|
||||||
default: undefined as boolean | undefined,
|
|
||||||
description: 'Internal feature flag for IDE mode.',
|
|
||||||
showInDialog: false,
|
|
||||||
},
|
|
||||||
dnsResolutionOrder: {
|
dnsResolutionOrder: {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
label: 'DNS Resolution Order',
|
label: 'DNS Resolution Order',
|
||||||
|
|
|
@ -191,7 +191,7 @@ export async function main() {
|
||||||
|
|
||||||
await config.initialize();
|
await config.initialize();
|
||||||
|
|
||||||
if (config.getIdeMode() && config.getIdeModeFeature()) {
|
if (config.getIdeMode()) {
|
||||||
await config.getIdeClient().connect();
|
await config.getIdeClient().connect();
|
||||||
logIdeConnection(config, new IdeConnectionEvent(IdeConnectionType.START));
|
logIdeConnection(config, new IdeConnectionEvent(IdeConnectionType.START));
|
||||||
}
|
}
|
||||||
|
|
|
@ -155,13 +155,13 @@ vi.mock('@google/gemini-cli-core', async (importOriginal) => {
|
||||||
setFlashFallbackHandler: vi.fn(),
|
setFlashFallbackHandler: vi.fn(),
|
||||||
getSessionId: vi.fn(() => 'test-session-id'),
|
getSessionId: vi.fn(() => 'test-session-id'),
|
||||||
getUserTier: vi.fn().mockResolvedValue(undefined),
|
getUserTier: vi.fn().mockResolvedValue(undefined),
|
||||||
getIdeModeFeature: vi.fn(() => false),
|
getIdeMode: vi.fn(() => true),
|
||||||
getIdeMode: vi.fn(() => false),
|
|
||||||
getWorkspaceContext: vi.fn(() => ({
|
getWorkspaceContext: vi.fn(() => ({
|
||||||
getDirectories: vi.fn(() => []),
|
getDirectories: vi.fn(() => []),
|
||||||
})),
|
})),
|
||||||
getIdeClient: vi.fn(() => ({
|
getIdeClient: vi.fn(() => ({
|
||||||
getCurrentIde: vi.fn(() => 'vscode'),
|
getCurrentIde: vi.fn(() => 'vscode'),
|
||||||
|
getDetectedIdeDisplayName: vi.fn(() => 'VSCode'),
|
||||||
})),
|
})),
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
|
@ -130,7 +130,6 @@ const App = ({ config, settings, startupWarnings = [], version }: AppProps) => {
|
||||||
registerCleanup(() => config.getIdeClient().disconnect());
|
registerCleanup(() => config.getIdeClient().disconnect());
|
||||||
}, [config]);
|
}, [config]);
|
||||||
const shouldShowIdePrompt =
|
const shouldShowIdePrompt =
|
||||||
config.getIdeModeFeature() &&
|
|
||||||
currentIDE &&
|
currentIDE &&
|
||||||
!config.getIdeMode() &&
|
!config.getIdeMode() &&
|
||||||
!settings.merged.hasSeenIdeIntegrationNudge &&
|
!settings.merged.hasSeenIdeIntegrationNudge &&
|
||||||
|
|
|
@ -40,7 +40,6 @@ describe('ideCommand', () => {
|
||||||
} as unknown as CommandContext;
|
} as unknown as CommandContext;
|
||||||
|
|
||||||
mockConfig = {
|
mockConfig = {
|
||||||
getIdeModeFeature: vi.fn(),
|
|
||||||
getIdeMode: vi.fn(),
|
getIdeMode: vi.fn(),
|
||||||
getIdeClient: vi.fn(() => ({
|
getIdeClient: vi.fn(() => ({
|
||||||
reconnect: vi.fn(),
|
reconnect: vi.fn(),
|
||||||
|
@ -60,14 +59,12 @@ describe('ideCommand', () => {
|
||||||
vi.restoreAllMocks();
|
vi.restoreAllMocks();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return null if ideModeFeature is not enabled', () => {
|
it('should return null if config is not provided', () => {
|
||||||
vi.mocked(mockConfig.getIdeModeFeature).mockReturnValue(false);
|
const command = ideCommand(null);
|
||||||
const command = ideCommand(mockConfig);
|
|
||||||
expect(command).toBeNull();
|
expect(command).toBeNull();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return the ide command if ideModeFeature is enabled', () => {
|
it('should return the ide command', () => {
|
||||||
vi.mocked(mockConfig.getIdeModeFeature).mockReturnValue(true);
|
|
||||||
vi.mocked(mockConfig.getIdeMode).mockReturnValue(true);
|
vi.mocked(mockConfig.getIdeMode).mockReturnValue(true);
|
||||||
vi.mocked(mockConfig.getIdeClient).mockReturnValue({
|
vi.mocked(mockConfig.getIdeClient).mockReturnValue({
|
||||||
getCurrentIde: () => DetectedIde.VSCode,
|
getCurrentIde: () => DetectedIde.VSCode,
|
||||||
|
@ -85,7 +82,6 @@ describe('ideCommand', () => {
|
||||||
describe('status subcommand', () => {
|
describe('status subcommand', () => {
|
||||||
const mockGetConnectionStatus = vi.fn();
|
const mockGetConnectionStatus = vi.fn();
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
vi.mocked(mockConfig.getIdeModeFeature).mockReturnValue(true);
|
|
||||||
vi.mocked(mockConfig.getIdeClient).mockReturnValue({
|
vi.mocked(mockConfig.getIdeClient).mockReturnValue({
|
||||||
getConnectionStatus: mockGetConnectionStatus,
|
getConnectionStatus: mockGetConnectionStatus,
|
||||||
getCurrentIde: () => DetectedIde.VSCode,
|
getCurrentIde: () => DetectedIde.VSCode,
|
||||||
|
@ -162,7 +158,6 @@ describe('ideCommand', () => {
|
||||||
describe('install subcommand', () => {
|
describe('install subcommand', () => {
|
||||||
const mockInstall = vi.fn();
|
const mockInstall = vi.fn();
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
vi.mocked(mockConfig.getIdeModeFeature).mockReturnValue(true);
|
|
||||||
vi.mocked(mockConfig.getIdeMode).mockReturnValue(true);
|
vi.mocked(mockConfig.getIdeMode).mockReturnValue(true);
|
||||||
vi.mocked(mockConfig.getIdeClient).mockReturnValue({
|
vi.mocked(mockConfig.getIdeClient).mockReturnValue({
|
||||||
getCurrentIde: () => DetectedIde.VSCode,
|
getCurrentIde: () => DetectedIde.VSCode,
|
||||||
|
|
|
@ -115,7 +115,7 @@ async function getIdeStatusMessageWithFiles(ideClient: IdeClient): Promise<{
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ideCommand = (config: Config | null): SlashCommand | null => {
|
export const ideCommand = (config: Config | null): SlashCommand | null => {
|
||||||
if (!config || !config.getIdeModeFeature()) {
|
if (!config) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
const ideClient = config.getIdeClient();
|
const ideClient = config.getIdeClient();
|
||||||
|
|
|
@ -45,7 +45,7 @@ export const ToolConfirmationMessage: React.FC<
|
||||||
const handleConfirm = async (outcome: ToolConfirmationOutcome) => {
|
const handleConfirm = async (outcome: ToolConfirmationOutcome) => {
|
||||||
if (confirmationDetails.type === 'edit') {
|
if (confirmationDetails.type === 'edit') {
|
||||||
const ideClient = config?.getIdeClient();
|
const ideClient = config?.getIdeClient();
|
||||||
if (config?.getIdeMode() && config?.getIdeModeFeature()) {
|
if (config?.getIdeMode()) {
|
||||||
const cliOutcome =
|
const cliOutcome =
|
||||||
outcome === ToolConfirmationOutcome.Cancel ? 'rejected' : 'accepted';
|
outcome === ToolConfirmationOutcome.Cancel ? 'rejected' : 'accepted';
|
||||||
await ideClient?.resolveDiffFromCli(
|
await ideClient?.resolveDiffFromCli(
|
||||||
|
@ -136,7 +136,7 @@ export const ToolConfirmationMessage: React.FC<
|
||||||
value: ToolConfirmationOutcome.ProceedAlways,
|
value: ToolConfirmationOutcome.ProceedAlways,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
if (config?.getIdeMode() && config?.getIdeModeFeature()) {
|
if (config?.getIdeMode()) {
|
||||||
options.push({
|
options.push({
|
||||||
label: 'No (esc)',
|
label: 'No (esc)',
|
||||||
value: ToolConfirmationOutcome.Cancel,
|
value: ToolConfirmationOutcome.Cancel,
|
||||||
|
|
|
@ -191,7 +191,6 @@ export interface ConfigParameters {
|
||||||
blockedMcpServers?: Array<{ name: string; extensionName: string }>;
|
blockedMcpServers?: Array<{ name: string; extensionName: string }>;
|
||||||
noBrowser?: boolean;
|
noBrowser?: boolean;
|
||||||
summarizeToolOutput?: Record<string, SummarizeToolOutputSettings>;
|
summarizeToolOutput?: Record<string, SummarizeToolOutputSettings>;
|
||||||
ideModeFeature?: boolean;
|
|
||||||
folderTrustFeature?: boolean;
|
folderTrustFeature?: boolean;
|
||||||
folderTrust?: boolean;
|
folderTrust?: boolean;
|
||||||
ideMode?: boolean;
|
ideMode?: boolean;
|
||||||
|
@ -240,7 +239,6 @@ export class Config {
|
||||||
private readonly model: string;
|
private readonly model: string;
|
||||||
private readonly extensionContextFilePaths: string[];
|
private readonly extensionContextFilePaths: string[];
|
||||||
private readonly noBrowser: boolean;
|
private readonly noBrowser: boolean;
|
||||||
private readonly ideModeFeature: boolean;
|
|
||||||
private readonly folderTrustFeature: boolean;
|
private readonly folderTrustFeature: boolean;
|
||||||
private readonly folderTrust: boolean;
|
private readonly folderTrust: boolean;
|
||||||
private ideMode: boolean;
|
private ideMode: boolean;
|
||||||
|
@ -317,7 +315,6 @@ export class Config {
|
||||||
this._blockedMcpServers = params.blockedMcpServers ?? [];
|
this._blockedMcpServers = params.blockedMcpServers ?? [];
|
||||||
this.noBrowser = params.noBrowser ?? false;
|
this.noBrowser = params.noBrowser ?? false;
|
||||||
this.summarizeToolOutput = params.summarizeToolOutput;
|
this.summarizeToolOutput = params.summarizeToolOutput;
|
||||||
this.ideModeFeature = params.ideModeFeature ?? false;
|
|
||||||
this.folderTrustFeature = params.folderTrustFeature ?? false;
|
this.folderTrustFeature = params.folderTrustFeature ?? false;
|
||||||
this.folderTrust = params.folderTrust ?? false;
|
this.folderTrust = params.folderTrust ?? false;
|
||||||
this.ideMode = params.ideMode ?? false;
|
this.ideMode = params.ideMode ?? false;
|
||||||
|
@ -654,10 +651,6 @@ export class Config {
|
||||||
return this.summarizeToolOutput;
|
return this.summarizeToolOutput;
|
||||||
}
|
}
|
||||||
|
|
||||||
getIdeModeFeature(): boolean {
|
|
||||||
return this.ideModeFeature;
|
|
||||||
}
|
|
||||||
|
|
||||||
getIdeMode(): boolean {
|
getIdeMode(): boolean {
|
||||||
return this.ideMode;
|
return this.ideMode;
|
||||||
}
|
}
|
||||||
|
|
|
@ -667,7 +667,7 @@ describe('Gemini Client (client.ts)', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('sendMessageStream', () => {
|
describe('sendMessageStream', () => {
|
||||||
it('should include editor context when ideModeFeature is enabled', async () => {
|
it('should include editor context when ideMode is enabled', async () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
vi.mocked(ideContext.getIdeContext).mockReturnValue({
|
vi.mocked(ideContext.getIdeContext).mockReturnValue({
|
||||||
workspaceState: {
|
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* () {
|
const mockStream = (async function* () {
|
||||||
yield { type: 'content', value: 'Hello' };
|
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
|
// Arrange
|
||||||
vi.mocked(ideContext.getIdeContext).mockReturnValue({
|
vi.mocked(ideContext.getIdeContext).mockReturnValue({
|
||||||
workspaceState: {
|
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* () {
|
const mockStream = (async function* () {
|
||||||
yield { type: 'content', value: 'Hello' };
|
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
|
// Arrange
|
||||||
vi.mocked(ideContext.getIdeContext).mockReturnValue({
|
vi.mocked(ideContext.getIdeContext).mockReturnValue({
|
||||||
workspaceState: {
|
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* () {
|
const mockStream = (async function* () {
|
||||||
yield { type: 'content', value: 'Hello' };
|
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
|
// Arrange
|
||||||
vi.mocked(ideContext.getIdeContext).mockReturnValue({
|
vi.mocked(ideContext.getIdeContext).mockReturnValue({
|
||||||
workspaceState: {
|
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* () {
|
const mockStream = (async function* () {
|
||||||
yield { type: 'content', value: 'Hello' };
|
yield { type: 'content', value: 'Hello' };
|
||||||
|
@ -1226,7 +1226,7 @@ ${JSON.stringify(
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
client['forceFullIdeContext'] = false; // Reset before each delta test
|
client['forceFullIdeContext'] = false; // Reset before each delta test
|
||||||
vi.spyOn(client, 'tryCompressChat').mockResolvedValue(null);
|
vi.spyOn(client, 'tryCompressChat').mockResolvedValue(null);
|
||||||
vi.spyOn(client['config'], 'getIdeModeFeature').mockReturnValue(true);
|
vi.spyOn(client['config'], 'getIdeMode').mockReturnValue(true);
|
||||||
mockTurnRunFn.mockReturnValue(mockStream);
|
mockTurnRunFn.mockReturnValue(mockStream);
|
||||||
|
|
||||||
const mockChat: Partial<GeminiChat> = {
|
const mockChat: Partial<GeminiChat> = {
|
||||||
|
|
|
@ -444,7 +444,7 @@ export class GeminiClient {
|
||||||
yield { type: GeminiEventType.ChatCompressed, value: compressed };
|
yield { type: GeminiEventType.ChatCompressed, value: compressed };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.config.getIdeModeFeature() && this.config.getIdeMode()) {
|
if (this.config.getIdeMode()) {
|
||||||
const { contextParts, newIdeContext } = this.getIdeContextParts(
|
const { contextParts, newIdeContext } = this.getIdeContextParts(
|
||||||
this.forceFullIdeContext || this.getHistory().length === 0,
|
this.forceFullIdeContext || this.getHistory().length === 0,
|
||||||
);
|
);
|
||||||
|
|
|
@ -6,15 +6,12 @@
|
||||||
|
|
||||||
import * as child_process from 'child_process';
|
import * as child_process from 'child_process';
|
||||||
import * as process from 'process';
|
import * as process from 'process';
|
||||||
import { glob } from 'glob';
|
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import * as os from 'os';
|
import * as os from 'os';
|
||||||
import { fileURLToPath } from 'url';
|
|
||||||
import { DetectedIde } from './detect-ide.js';
|
import { DetectedIde } from './detect-ide.js';
|
||||||
|
|
||||||
const VSCODE_COMMAND = process.platform === 'win32' ? 'code.cmd' : 'code';
|
const VSCODE_COMMAND = process.platform === 'win32' ? 'code.cmd' : 'code';
|
||||||
const VSCODE_COMPANION_EXTENSION_FOLDER = 'vscode-ide-companion';
|
|
||||||
|
|
||||||
export interface IdeInstaller {
|
export interface IdeInstaller {
|
||||||
install(): Promise<InstallResult>;
|
install(): Promise<InstallResult>;
|
||||||
|
@ -103,34 +100,7 @@ class VsCodeInstaller implements IdeInstaller {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const bundleDir = path.dirname(fileURLToPath(import.meta.url));
|
const command = `"${commandPath}" --install-extension google.gemini-cli-vscode-ide-companion --force`;
|
||||||
// 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`;
|
|
||||||
try {
|
try {
|
||||||
child_process.execSync(command, { stdio: 'pipe' });
|
child_process.execSync(command, { stdio: 'pipe' });
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -62,7 +62,6 @@ describe('EditTool', () => {
|
||||||
getWorkspaceContext: () => createMockWorkspaceContext(rootDir),
|
getWorkspaceContext: () => createMockWorkspaceContext(rootDir),
|
||||||
getIdeClient: () => undefined,
|
getIdeClient: () => undefined,
|
||||||
getIdeMode: () => false,
|
getIdeMode: () => false,
|
||||||
getIdeModeFeature: () => false,
|
|
||||||
// getGeminiConfig: () => ({ apiKey: 'test-api-key' }), // This was not a real Config method
|
// getGeminiConfig: () => ({ apiKey: 'test-api-key' }), // This was not a real Config method
|
||||||
// Add other properties/methods of Config if EditTool uses them
|
// 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:
|
// 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).getIdeMode = () => true;
|
||||||
(mockConfig as any).getIdeModeFeature = () => true;
|
|
||||||
(mockConfig as any).getIdeClient = () => ideClient;
|
(mockConfig as any).getIdeClient = () => ideClient;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -250,7 +250,6 @@ class EditToolInvocation implements ToolInvocation<EditToolParams, ToolResult> {
|
||||||
);
|
);
|
||||||
const ideClient = this.config.getIdeClient();
|
const ideClient = this.config.getIdeClient();
|
||||||
const ideConfirmation =
|
const ideConfirmation =
|
||||||
this.config.getIdeModeFeature() &&
|
|
||||||
this.config.getIdeMode() &&
|
this.config.getIdeMode() &&
|
||||||
ideClient?.getConnectionStatus().status === IDEConnectionStatus.Connected
|
ideClient?.getConnectionStatus().status === IDEConnectionStatus.Connected
|
||||||
? ideClient.openDiff(this.params.file_path, editData.newContent)
|
? ideClient.openDiff(this.params.file_path, editData.newContent)
|
||||||
|
|
|
@ -58,7 +58,6 @@ const mockConfigInternal = {
|
||||||
getGeminiClient: vi.fn(), // Initialize as a plain mock function
|
getGeminiClient: vi.fn(), // Initialize as a plain mock function
|
||||||
getIdeClient: vi.fn(),
|
getIdeClient: vi.fn(),
|
||||||
getIdeMode: vi.fn(() => false),
|
getIdeMode: vi.fn(() => false),
|
||||||
getIdeModeFeature: vi.fn(() => false),
|
|
||||||
getWorkspaceContext: () => createMockWorkspaceContext(rootDir),
|
getWorkspaceContext: () => createMockWorkspaceContext(rootDir),
|
||||||
getApiKey: () => 'test-key',
|
getApiKey: () => 'test-key',
|
||||||
getModel: () => 'test-model',
|
getModel: () => 'test-model',
|
||||||
|
|
|
@ -195,7 +195,6 @@ export class WriteFileTool
|
||||||
|
|
||||||
const ideClient = this.config.getIdeClient();
|
const ideClient = this.config.getIdeClient();
|
||||||
const ideConfirmation =
|
const ideConfirmation =
|
||||||
this.config.getIdeModeFeature() &&
|
|
||||||
this.config.getIdeMode() &&
|
this.config.getIdeMode() &&
|
||||||
ideClient.getConnectionStatus().status === IDEConnectionStatus.Connected
|
ideClient.getConnectionStatus().status === IDEConnectionStatus.Connected
|
||||||
? ideClient.openDiff(params.file_path, correctedContent)
|
? ideClient.openDiff(params.file_path, correctedContent)
|
||||||
|
|
|
@ -37,12 +37,4 @@ for (const file of sbFiles) {
|
||||||
copyFileSync(join(root, file), join(bundleDir, basename(file)));
|
copyFileSync(join(root, file), join(bundleDir, basename(file)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find and copy all .vsix files from packages to the root of the bundle directory
|
|
||||||
const vsixFiles = glob.sync('packages/vscode-ide-companion/*.vsix', {
|
|
||||||
cwd: root,
|
|
||||||
});
|
|
||||||
for (const file of vsixFiles) {
|
|
||||||
copyFileSync(join(root, file), join(bundleDir, basename(file)));
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('Assets copied to bundle/');
|
console.log('Assets copied to bundle/');
|
||||||
|
|
Loading…
Reference in New Issue