mirror of
https://github.com/QwenLM/qwen-code.git
synced 2025-12-20 16:57:46 +00:00
Add toggleable IDE mode setting (#5146)
This commit is contained in:
@@ -32,11 +32,19 @@ describe('ideCommand', () => {
|
||||
ui: {
|
||||
addItem: vi.fn(),
|
||||
},
|
||||
services: {
|
||||
settings: {
|
||||
setValue: vi.fn(),
|
||||
},
|
||||
},
|
||||
} as unknown as CommandContext;
|
||||
|
||||
mockConfig = {
|
||||
getIdeModeFeature: vi.fn(),
|
||||
getIdeMode: vi.fn(),
|
||||
getIdeClient: vi.fn(),
|
||||
setIdeMode: vi.fn(),
|
||||
setIdeClientDisconnected: vi.fn(),
|
||||
} as unknown as Config;
|
||||
|
||||
platformSpy = vi.spyOn(process, 'platform', 'get');
|
||||
@@ -46,13 +54,14 @@ describe('ideCommand', () => {
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
it('should return null if ideMode is not enabled', () => {
|
||||
vi.mocked(mockConfig.getIdeMode).mockReturnValue(false);
|
||||
it('should return null if ideModeFeature is not enabled', () => {
|
||||
vi.mocked(mockConfig.getIdeModeFeature).mockReturnValue(false);
|
||||
const command = ideCommand(mockConfig);
|
||||
expect(command).toBeNull();
|
||||
});
|
||||
|
||||
it('should return the ide command if ideMode is enabled', () => {
|
||||
it('should return the ide command if ideModeFeature is enabled', () => {
|
||||
vi.mocked(mockConfig.getIdeModeFeature).mockReturnValue(true);
|
||||
vi.mocked(mockConfig.getIdeMode).mockReturnValue(true);
|
||||
vi.mocked(mockConfig.getIdeClient).mockReturnValue({
|
||||
getCurrentIde: () => DetectedIde.VSCode,
|
||||
@@ -60,19 +69,20 @@ describe('ideCommand', () => {
|
||||
const command = ideCommand(mockConfig);
|
||||
expect(command).not.toBeNull();
|
||||
expect(command?.name).toBe('ide');
|
||||
expect(command?.subCommands).toHaveLength(2);
|
||||
expect(command?.subCommands?.[0].name).toBe('status');
|
||||
expect(command?.subCommands?.[1].name).toBe('install');
|
||||
expect(command?.subCommands).toHaveLength(3);
|
||||
expect(command?.subCommands?.[0].name).toBe('disable');
|
||||
expect(command?.subCommands?.[1].name).toBe('status');
|
||||
expect(command?.subCommands?.[2].name).toBe('install');
|
||||
});
|
||||
|
||||
describe('status subcommand', () => {
|
||||
const mockGetConnectionStatus = vi.fn();
|
||||
beforeEach(() => {
|
||||
vi.mocked(mockConfig.getIdeMode).mockReturnValue(true);
|
||||
vi.mocked(mockConfig.getIdeModeFeature).mockReturnValue(true);
|
||||
vi.mocked(mockConfig.getIdeClient).mockReturnValue({
|
||||
getConnectionStatus: mockGetConnectionStatus,
|
||||
getCurrentIde: () => DetectedIde.VSCode,
|
||||
} as ReturnType<Config['getIdeClient']>);
|
||||
} as unknown as ReturnType<Config['getIdeClient']>);
|
||||
});
|
||||
|
||||
it('should show connected status', () => {
|
||||
@@ -80,7 +90,8 @@ describe('ideCommand', () => {
|
||||
status: core.IDEConnectionStatus.Connected,
|
||||
});
|
||||
const command = ideCommand(mockConfig);
|
||||
const result = command!.subCommands![0].action!(mockContext, '');
|
||||
const result = command!.subCommands!.find((c) => c.name === 'status')!
|
||||
.action!(mockContext, '');
|
||||
expect(mockGetConnectionStatus).toHaveBeenCalled();
|
||||
expect(result).toEqual({
|
||||
type: 'message',
|
||||
@@ -94,7 +105,8 @@ describe('ideCommand', () => {
|
||||
status: core.IDEConnectionStatus.Connecting,
|
||||
});
|
||||
const command = ideCommand(mockConfig);
|
||||
const result = command!.subCommands![0].action!(mockContext, '');
|
||||
const result = command!.subCommands!.find((c) => c.name === 'status')!
|
||||
.action!(mockContext, '');
|
||||
expect(mockGetConnectionStatus).toHaveBeenCalled();
|
||||
expect(result).toEqual({
|
||||
type: 'message',
|
||||
@@ -107,7 +119,8 @@ describe('ideCommand', () => {
|
||||
status: core.IDEConnectionStatus.Disconnected,
|
||||
});
|
||||
const command = ideCommand(mockConfig);
|
||||
const result = command!.subCommands![0].action!(mockContext, '');
|
||||
const result = command!.subCommands!.find((c) => c.name === 'status')!
|
||||
.action!(mockContext, '');
|
||||
expect(mockGetConnectionStatus).toHaveBeenCalled();
|
||||
expect(result).toEqual({
|
||||
type: 'message',
|
||||
@@ -123,7 +136,8 @@ describe('ideCommand', () => {
|
||||
details,
|
||||
});
|
||||
const command = ideCommand(mockConfig);
|
||||
const result = command!.subCommands![0].action!(mockContext, '');
|
||||
const result = command!.subCommands!.find((c) => c.name === 'status')!
|
||||
.action!(mockContext, '');
|
||||
expect(mockGetConnectionStatus).toHaveBeenCalled();
|
||||
expect(result).toEqual({
|
||||
type: 'message',
|
||||
@@ -136,10 +150,12 @@ describe('ideCommand', () => {
|
||||
describe('install subcommand', () => {
|
||||
const mockInstall = vi.fn();
|
||||
beforeEach(() => {
|
||||
vi.mocked(mockConfig.getIdeModeFeature).mockReturnValue(true);
|
||||
vi.mocked(mockConfig.getIdeMode).mockReturnValue(true);
|
||||
vi.mocked(mockConfig.getIdeClient).mockReturnValue({
|
||||
getCurrentIde: () => DetectedIde.VSCode,
|
||||
} as ReturnType<Config['getIdeClient']>);
|
||||
getConnectionStatus: vi.fn(),
|
||||
} as unknown as ReturnType<Config['getIdeClient']>);
|
||||
vi.mocked(core.getIdeInstaller).mockReturnValue({
|
||||
install: mockInstall,
|
||||
isInstalled: vi.fn(),
|
||||
@@ -154,7 +170,10 @@ describe('ideCommand', () => {
|
||||
});
|
||||
|
||||
const command = ideCommand(mockConfig);
|
||||
await command!.subCommands![1].action!(mockContext, '');
|
||||
await command!.subCommands!.find((c) => c.name === 'install')!.action!(
|
||||
mockContext,
|
||||
'',
|
||||
);
|
||||
|
||||
expect(core.getIdeInstaller).toHaveBeenCalledWith('vscode');
|
||||
expect(mockInstall).toHaveBeenCalled();
|
||||
@@ -181,7 +200,10 @@ describe('ideCommand', () => {
|
||||
});
|
||||
|
||||
const command = ideCommand(mockConfig);
|
||||
await command!.subCommands![1].action!(mockContext, '');
|
||||
await command!.subCommands!.find((c) => c.name === 'install')!.action!(
|
||||
mockContext,
|
||||
'',
|
||||
);
|
||||
|
||||
expect(core.getIdeInstaller).toHaveBeenCalledWith('vscode');
|
||||
expect(mockInstall).toHaveBeenCalled();
|
||||
|
||||
@@ -6,9 +6,9 @@
|
||||
|
||||
import {
|
||||
Config,
|
||||
IDEConnectionStatus,
|
||||
getIdeDisplayName,
|
||||
getIdeInstaller,
|
||||
IDEConnectionStatus,
|
||||
} from '@google/gemini-cli-core';
|
||||
import {
|
||||
CommandContext,
|
||||
@@ -16,91 +16,130 @@ import {
|
||||
SlashCommandActionReturn,
|
||||
CommandKind,
|
||||
} from './types.js';
|
||||
import { SettingScope } from '../../config/settings.js';
|
||||
|
||||
export const ideCommand = (config: Config | null): SlashCommand | null => {
|
||||
if (!config?.getIdeMode()) {
|
||||
if (!config?.getIdeModeFeature()) {
|
||||
return null;
|
||||
}
|
||||
const currentIDE = config.getIdeClient().getCurrentIde();
|
||||
if (!currentIDE) {
|
||||
throw new Error(
|
||||
'IDE slash command should not be available if not running in an IDE',
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
const ideSlashCommand: SlashCommand = {
|
||||
name: 'ide',
|
||||
description: 'manage IDE integration',
|
||||
kind: CommandKind.BUILT_IN,
|
||||
subCommands: [
|
||||
{
|
||||
name: 'status',
|
||||
description: 'check status of IDE integration',
|
||||
kind: CommandKind.BUILT_IN,
|
||||
action: (_context: CommandContext): SlashCommandActionReturn => {
|
||||
const connection = config.getIdeClient().getConnectionStatus();
|
||||
switch (connection?.status) {
|
||||
case IDEConnectionStatus.Connected:
|
||||
return {
|
||||
type: 'message',
|
||||
messageType: 'info',
|
||||
content: `🟢 Connected`,
|
||||
} as const;
|
||||
case IDEConnectionStatus.Connecting:
|
||||
return {
|
||||
type: 'message',
|
||||
messageType: 'info',
|
||||
content: `🟡 Connecting...`,
|
||||
} as const;
|
||||
default: {
|
||||
let content = `🔴 Disconnected`;
|
||||
if (connection?.details) {
|
||||
content += `: ${connection.details}`;
|
||||
}
|
||||
return {
|
||||
type: 'message',
|
||||
messageType: 'error',
|
||||
content,
|
||||
} as const;
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'install',
|
||||
description: `install required IDE companion ${getIdeDisplayName(currentIDE)} extension `,
|
||||
kind: CommandKind.BUILT_IN,
|
||||
action: async (context) => {
|
||||
const installer = getIdeInstaller(currentIDE);
|
||||
if (!installer) {
|
||||
context.ui.addItem(
|
||||
{
|
||||
type: 'error',
|
||||
text: 'No installer available for your configured IDE.',
|
||||
},
|
||||
Date.now(),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
context.ui.addItem(
|
||||
{
|
||||
type: 'info',
|
||||
text: `Installing IDE companion extension...`,
|
||||
},
|
||||
Date.now(),
|
||||
);
|
||||
|
||||
const result = await installer.install();
|
||||
context.ui.addItem(
|
||||
{
|
||||
type: result.success ? 'info' : 'error',
|
||||
text: result.message,
|
||||
},
|
||||
Date.now(),
|
||||
);
|
||||
},
|
||||
},
|
||||
],
|
||||
subCommands: [],
|
||||
};
|
||||
|
||||
const statusCommand: SlashCommand = {
|
||||
name: 'status',
|
||||
description: 'check status of IDE integration',
|
||||
kind: CommandKind.BUILT_IN,
|
||||
action: (_context: CommandContext): SlashCommandActionReturn => {
|
||||
const connection = config.getIdeClient().getConnectionStatus();
|
||||
switch (connection?.status) {
|
||||
case IDEConnectionStatus.Connected:
|
||||
return {
|
||||
type: 'message',
|
||||
messageType: 'info',
|
||||
content: `🟢 Connected`,
|
||||
} as const;
|
||||
case IDEConnectionStatus.Connecting:
|
||||
return {
|
||||
type: 'message',
|
||||
messageType: 'info',
|
||||
content: `🟡 Connecting...`,
|
||||
} as const;
|
||||
default: {
|
||||
let content = `🔴 Disconnected`;
|
||||
if (connection?.details) {
|
||||
content += `: ${connection.details}`;
|
||||
}
|
||||
return {
|
||||
type: 'message',
|
||||
messageType: 'error',
|
||||
content,
|
||||
} as const;
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
const installCommand: SlashCommand = {
|
||||
name: 'install',
|
||||
description: `install required IDE companion ${getIdeDisplayName(currentIDE)} extension `,
|
||||
kind: CommandKind.BUILT_IN,
|
||||
action: async (context) => {
|
||||
const installer = getIdeInstaller(currentIDE);
|
||||
if (!installer) {
|
||||
context.ui.addItem(
|
||||
{
|
||||
type: 'error',
|
||||
text: 'No installer available for your configured IDE.',
|
||||
},
|
||||
Date.now(),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
context.ui.addItem(
|
||||
{
|
||||
type: 'info',
|
||||
text: `Installing IDE companion extension...`,
|
||||
},
|
||||
Date.now(),
|
||||
);
|
||||
|
||||
const result = await installer.install();
|
||||
context.ui.addItem(
|
||||
{
|
||||
type: result.success ? 'info' : 'error',
|
||||
text: result.message,
|
||||
},
|
||||
Date.now(),
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
const enableCommand: SlashCommand = {
|
||||
name: 'enable',
|
||||
description: 'enable IDE integration',
|
||||
kind: CommandKind.BUILT_IN,
|
||||
action: async (context: CommandContext) => {
|
||||
context.services.settings.setValue(SettingScope.User, 'ideMode', true);
|
||||
config.setIdeMode(true);
|
||||
config.setIdeClientConnected();
|
||||
},
|
||||
};
|
||||
|
||||
const disableCommand: SlashCommand = {
|
||||
name: 'disable',
|
||||
description: 'disable IDE integration',
|
||||
kind: CommandKind.BUILT_IN,
|
||||
action: async (context: CommandContext) => {
|
||||
context.services.settings.setValue(SettingScope.User, 'ideMode', false);
|
||||
config.setIdeMode(false);
|
||||
config.setIdeClientDisconnected();
|
||||
},
|
||||
};
|
||||
|
||||
const ideModeEnabled = config.getIdeMode();
|
||||
if (ideModeEnabled) {
|
||||
ideSlashCommand.subCommands = [
|
||||
disableCommand,
|
||||
statusCommand,
|
||||
installCommand,
|
||||
];
|
||||
} else {
|
||||
ideSlashCommand.subCommands = [
|
||||
enableCommand,
|
||||
statusCommand,
|
||||
installCommand,
|
||||
];
|
||||
}
|
||||
|
||||
return ideSlashCommand;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user