mirror of
https://github.com/QwenLM/qwen-code.git
synced 2025-12-20 16:57:46 +00:00
Merge tag 'v0.3.0' into chore/sync-gemini-cli-v0.3.0
This commit is contained in:
@@ -11,7 +11,7 @@ import { createMockCommandContext } from '../../test-utils/mockCommandContext.js
|
||||
import * as versionUtils from '../../utils/version.js';
|
||||
import { MessageType } from '../types.js';
|
||||
|
||||
import { IdeClient } from '../../../../core/src/ide/ide-client.js';
|
||||
import type { IdeClient } from '../../../../core/src/ide/ide-client.js';
|
||||
|
||||
vi.mock('../../utils/version.js', () => ({
|
||||
getCliVersion: vi.fn(),
|
||||
@@ -32,7 +32,11 @@ describe('aboutCommand', () => {
|
||||
},
|
||||
settings: {
|
||||
merged: {
|
||||
selectedAuthType: 'test-auth',
|
||||
security: {
|
||||
auth: {
|
||||
selectedType: 'test-auth',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -5,7 +5,8 @@
|
||||
*/
|
||||
|
||||
import { getCliVersion } from '../../utils/version.js';
|
||||
import { CommandKind, SlashCommand } from './types.js';
|
||||
import type { SlashCommand } from './types.js';
|
||||
import { CommandKind } from './types.js';
|
||||
import process from 'node:process';
|
||||
import { MessageType, type HistoryItemAbout } from '../types.js';
|
||||
|
||||
@@ -26,7 +27,7 @@ export const aboutCommand: SlashCommand = {
|
||||
const modelVersion = context.services.config?.getModel() || 'Unknown';
|
||||
const cliVersion = await getCliVersion();
|
||||
const selectedAuthType =
|
||||
context.services.settings.merged.selectedAuthType || '';
|
||||
context.services.settings.merged.security?.auth?.selectedType || '';
|
||||
const gcpProject = process.env['GOOGLE_CLOUD_PROJECT'] || '';
|
||||
const ideClient =
|
||||
(context.services.config?.getIdeMode() &&
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { CommandKind, OpenDialogActionReturn, SlashCommand } from './types.js';
|
||||
import type { OpenDialogActionReturn, SlashCommand } from './types.js';
|
||||
import { CommandKind } from './types.js';
|
||||
|
||||
export const authCommand: SlashCommand = {
|
||||
name: 'auth',
|
||||
|
||||
@@ -4,29 +4,22 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import {
|
||||
vi,
|
||||
describe,
|
||||
it,
|
||||
expect,
|
||||
beforeEach,
|
||||
afterEach,
|
||||
Mocked,
|
||||
} from 'vitest';
|
||||
import type { Mocked } from 'vitest';
|
||||
import { vi, describe, it, expect, beforeEach, afterEach } from 'vitest';
|
||||
|
||||
import {
|
||||
type CommandContext,
|
||||
import type {
|
||||
MessageActionReturn,
|
||||
SlashCommand,
|
||||
CommandContext,
|
||||
} from './types.js';
|
||||
import { createMockCommandContext } from '../../test-utils/mockCommandContext.js';
|
||||
import { Content } from '@google/genai';
|
||||
import { GeminiClient } from '@qwen-code/qwen-code-core';
|
||||
import type { Content } from '@google/genai';
|
||||
import type { GeminiClient } from '@qwen-code/qwen-code-core';
|
||||
|
||||
import * as fsPromises from 'fs/promises';
|
||||
import * as fsPromises from 'node:fs/promises';
|
||||
import { chatCommand } from './chatCommand.js';
|
||||
import { Stats } from 'fs';
|
||||
import { HistoryItemWithoutId } from '../types.js';
|
||||
import type { Stats } from 'node:fs';
|
||||
import type { HistoryItemWithoutId } from '../types.js';
|
||||
|
||||
vi.mock('fs/promises', () => ({
|
||||
stat: vi.fn(),
|
||||
@@ -67,11 +60,14 @@ describe('chatCommand', () => {
|
||||
mockContext = createMockCommandContext({
|
||||
services: {
|
||||
config: {
|
||||
getProjectTempDir: () => '/tmp/gemini',
|
||||
getProjectRoot: () => '/project/root',
|
||||
getGeminiClient: () =>
|
||||
({
|
||||
getChat: mockGetChat,
|
||||
}) as unknown as GeminiClient,
|
||||
storage: {
|
||||
getProjectTempDir: () => '/project/root/.gemini/tmp/mockhash',
|
||||
},
|
||||
},
|
||||
logger: {
|
||||
saveCheckpoint: mockSaveCheckpoint,
|
||||
|
||||
@@ -4,20 +4,21 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import * as fsPromises from 'fs/promises';
|
||||
import * as fsPromises from 'node:fs/promises';
|
||||
import React from 'react';
|
||||
import { Text } from 'ink';
|
||||
import { Colors } from '../colors.js';
|
||||
import {
|
||||
import type {
|
||||
CommandContext,
|
||||
SlashCommand,
|
||||
MessageActionReturn,
|
||||
CommandKind,
|
||||
SlashCommandActionReturn,
|
||||
} from './types.js';
|
||||
import { CommandKind } from './types.js';
|
||||
import { decodeTagName } from '@qwen-code/qwen-code-core';
|
||||
import path from 'path';
|
||||
import { HistoryItemWithoutId, MessageType } from '../types.js';
|
||||
import path from 'node:path';
|
||||
import type { HistoryItemWithoutId } from '../types.js';
|
||||
import { MessageType } from '../types.js';
|
||||
|
||||
interface ChatDetail {
|
||||
name: string;
|
||||
@@ -28,7 +29,8 @@ const getSavedChatTags = async (
|
||||
context: CommandContext,
|
||||
mtSortDesc: boolean,
|
||||
): Promise<ChatDetail[]> => {
|
||||
const geminiDir = context.services.config?.getProjectTempDir();
|
||||
const cfg = context.services.config;
|
||||
const geminiDir = cfg?.storage?.getProjectTempDir();
|
||||
if (!geminiDir) {
|
||||
return [];
|
||||
}
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { vi, describe, it, expect, beforeEach, Mock } from 'vitest';
|
||||
import type { Mock } from 'vitest';
|
||||
import { vi, describe, it, expect, beforeEach } from 'vitest';
|
||||
import { clearCommand } from './clearCommand.js';
|
||||
import { type CommandContext } from './types.js';
|
||||
import { createMockCommandContext } from '../../test-utils/mockCommandContext.js';
|
||||
@@ -20,7 +21,8 @@ vi.mock('@qwen-code/qwen-code-core', async () => {
|
||||
};
|
||||
});
|
||||
|
||||
import { GeminiClient, uiTelemetryService } from '@qwen-code/qwen-code-core';
|
||||
import type { GeminiClient } from '@qwen-code/qwen-code-core';
|
||||
import { uiTelemetryService } from '@qwen-code/qwen-code-core';
|
||||
|
||||
describe('clearCommand', () => {
|
||||
let mockContext: CommandContext;
|
||||
|
||||
@@ -5,7 +5,8 @@
|
||||
*/
|
||||
|
||||
import { uiTelemetryService } from '@qwen-code/qwen-code-core';
|
||||
import { CommandKind, SlashCommand } from './types.js';
|
||||
import type { SlashCommand } from './types.js';
|
||||
import { CommandKind } from './types.js';
|
||||
|
||||
export const clearCommand: SlashCommand = {
|
||||
name: 'clear',
|
||||
|
||||
@@ -4,7 +4,11 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { GeminiClient } from '@qwen-code/qwen-code-core';
|
||||
import {
|
||||
CompressionStatus,
|
||||
type ChatCompressionInfo,
|
||||
type GeminiClient,
|
||||
} from '@qwen-code/qwen-code-core';
|
||||
import { vi, describe, it, expect, beforeEach } from 'vitest';
|
||||
import { compressCommand } from './compressCommand.js';
|
||||
import { createMockCommandContext } from '../../test-utils/mockCommandContext.js';
|
||||
@@ -35,6 +39,7 @@ describe('compressCommand', () => {
|
||||
isPending: true,
|
||||
originalTokenCount: null,
|
||||
newTokenCount: null,
|
||||
compressionStatus: null,
|
||||
},
|
||||
};
|
||||
await compressCommand.action!(context, '');
|
||||
@@ -50,25 +55,24 @@ describe('compressCommand', () => {
|
||||
});
|
||||
|
||||
it('should set pending item, call tryCompressChat, and add result on success', async () => {
|
||||
const compressedResult = {
|
||||
const compressedResult: ChatCompressionInfo = {
|
||||
originalTokenCount: 200,
|
||||
compressionStatus: CompressionStatus.COMPRESSED,
|
||||
newTokenCount: 100,
|
||||
};
|
||||
mockTryCompressChat.mockResolvedValue(compressedResult);
|
||||
|
||||
await compressCommand.action!(context, '');
|
||||
|
||||
expect(context.ui.setPendingItem).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
expect.objectContaining({
|
||||
type: MessageType.COMPRESSION,
|
||||
compression: {
|
||||
isPending: true,
|
||||
originalTokenCount: null,
|
||||
newTokenCount: null,
|
||||
},
|
||||
}),
|
||||
);
|
||||
expect(context.ui.setPendingItem).toHaveBeenNthCalledWith(1, {
|
||||
type: MessageType.COMPRESSION,
|
||||
compression: {
|
||||
isPending: true,
|
||||
compressionStatus: null,
|
||||
originalTokenCount: null,
|
||||
newTokenCount: null,
|
||||
},
|
||||
});
|
||||
|
||||
expect(mockTryCompressChat).toHaveBeenCalledWith(
|
||||
expect.stringMatching(/^compress-\d+$/),
|
||||
@@ -76,14 +80,15 @@ describe('compressCommand', () => {
|
||||
);
|
||||
|
||||
expect(context.ui.addItem).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
{
|
||||
type: MessageType.COMPRESSION,
|
||||
compression: {
|
||||
isPending: false,
|
||||
compressionStatus: CompressionStatus.COMPRESSED,
|
||||
originalTokenCount: 200,
|
||||
newTokenCount: 100,
|
||||
},
|
||||
}),
|
||||
},
|
||||
expect.any(Number),
|
||||
);
|
||||
|
||||
|
||||
@@ -4,8 +4,10 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { HistoryItemCompression, MessageType } from '../types.js';
|
||||
import { CommandKind, SlashCommand } from './types.js';
|
||||
import type { HistoryItemCompression } from '../types.js';
|
||||
import { MessageType } from '../types.js';
|
||||
import type { SlashCommand } from './types.js';
|
||||
import { CommandKind } from './types.js';
|
||||
|
||||
export const compressCommand: SlashCommand = {
|
||||
name: 'compress',
|
||||
@@ -31,6 +33,7 @@ export const compressCommand: SlashCommand = {
|
||||
isPending: true,
|
||||
originalTokenCount: null,
|
||||
newTokenCount: null,
|
||||
compressionStatus: null,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -48,6 +51,7 @@ export const compressCommand: SlashCommand = {
|
||||
isPending: false,
|
||||
originalTokenCount: compressed.originalTokenCount,
|
||||
newTokenCount: compressed.newTokenCount,
|
||||
compressionStatus: compressed.compressionStatus,
|
||||
},
|
||||
} as HistoryItemCompression,
|
||||
Date.now(),
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { vi, describe, it, expect, beforeEach, Mock } from 'vitest';
|
||||
import type { Mock } from 'vitest';
|
||||
import { vi, describe, it, expect, beforeEach } from 'vitest';
|
||||
import { copyCommand } from './copyCommand.js';
|
||||
import { type CommandContext } from './types.js';
|
||||
import { createMockCommandContext } from '../../test-utils/mockCommandContext.js';
|
||||
@@ -227,7 +228,7 @@ describe('copyCommand', () => {
|
||||
expect(result).toEqual({
|
||||
type: 'message',
|
||||
messageType: 'error',
|
||||
content: 'Failed to copy to the clipboard.',
|
||||
content: `Failed to copy to the clipboard. ${clipboardError.message}`,
|
||||
});
|
||||
});
|
||||
|
||||
@@ -242,14 +243,15 @@ describe('copyCommand', () => {
|
||||
];
|
||||
|
||||
mockGetHistory.mockReturnValue(historyWithAiMessage);
|
||||
mockCopyToClipboard.mockRejectedValue('String error');
|
||||
const rejectedValue = 'String error';
|
||||
mockCopyToClipboard.mockRejectedValue(rejectedValue);
|
||||
|
||||
const result = await copyCommand.action(mockContext, '');
|
||||
|
||||
expect(result).toEqual({
|
||||
type: 'message',
|
||||
messageType: 'error',
|
||||
content: 'Failed to copy to the clipboard.',
|
||||
content: `Failed to copy to the clipboard. ${rejectedValue}`,
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -5,11 +5,8 @@
|
||||
*/
|
||||
|
||||
import { copyToClipboard } from '../utils/commandUtils.js';
|
||||
import {
|
||||
CommandKind,
|
||||
SlashCommand,
|
||||
SlashCommandActionReturn,
|
||||
} from './types.js';
|
||||
import type { SlashCommand, SlashCommandActionReturn } from './types.js';
|
||||
import { CommandKind } from './types.js';
|
||||
|
||||
export const copyCommand: SlashCommand = {
|
||||
name: 'copy',
|
||||
@@ -53,7 +50,7 @@ export const copyCommand: SlashCommand = {
|
||||
return {
|
||||
type: 'message',
|
||||
messageType: 'error',
|
||||
content: 'Failed to copy to the clipboard.',
|
||||
content: `Failed to copy to the clipboard. ${message}`,
|
||||
};
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -6,11 +6,11 @@
|
||||
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import { directoryCommand, expandHomeDir } from './directoryCommand.js';
|
||||
import { Config, WorkspaceContext } from '@qwen-code/qwen-code-core';
|
||||
import { CommandContext } from './types.js';
|
||||
import type { Config, WorkspaceContext } from '@qwen-code/qwen-code-core';
|
||||
import type { CommandContext } from './types.js';
|
||||
import { MessageType } from '../types.js';
|
||||
import * as os from 'os';
|
||||
import * as path from 'path';
|
||||
import * as os from 'node:os';
|
||||
import * as path from 'node:path';
|
||||
|
||||
describe('directoryCommand', () => {
|
||||
let mockContext: CommandContext;
|
||||
|
||||
@@ -4,10 +4,11 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { SlashCommand, CommandContext, CommandKind } from './types.js';
|
||||
import type { SlashCommand, CommandContext } from './types.js';
|
||||
import { CommandKind } from './types.js';
|
||||
import { MessageType } from '../types.js';
|
||||
import * as os from 'os';
|
||||
import * as path from 'path';
|
||||
import * as os from 'node:os';
|
||||
import * as path from 'node:path';
|
||||
import { loadServerHierarchicalMemory } from '@qwen-code/qwen-code-core';
|
||||
|
||||
export function expandHomeDir(p: string): string {
|
||||
@@ -91,34 +92,36 @@ export const directoryCommand: SlashCommand = {
|
||||
}
|
||||
}
|
||||
|
||||
if (added.length > 0) {
|
||||
try {
|
||||
if (config.shouldLoadMemoryFromIncludeDirectories()) {
|
||||
const { memoryContent, fileCount } =
|
||||
await loadServerHierarchicalMemory(
|
||||
config.getWorkingDir(),
|
||||
[...config.getWorkspaceContext().getDirectories()],
|
||||
config.getDebugMode(),
|
||||
config.getFileService(),
|
||||
config.getExtensionContextFilePaths(),
|
||||
context.services.settings.merged.memoryImportFormat || 'tree', // Use setting or default to 'tree'
|
||||
config.getFileFilteringOptions(),
|
||||
context.services.settings.merged.memoryDiscoveryMaxDirs,
|
||||
);
|
||||
config.setUserMemory(memoryContent);
|
||||
config.setGeminiMdFileCount(fileCount);
|
||||
context.ui.setGeminiMdFileCount(fileCount);
|
||||
}
|
||||
addItem(
|
||||
{
|
||||
type: MessageType.INFO,
|
||||
text: `Successfully added memory files from the following directories if there are:\n- ${added.join('\n- ')}`,
|
||||
},
|
||||
Date.now(),
|
||||
);
|
||||
} catch (error) {
|
||||
errors.push(`Error refreshing memory: ${(error as Error).message}`);
|
||||
try {
|
||||
if (config.shouldLoadMemoryFromIncludeDirectories()) {
|
||||
const { memoryContent, fileCount } =
|
||||
await loadServerHierarchicalMemory(
|
||||
config.getWorkingDir(),
|
||||
[
|
||||
...config.getWorkspaceContext().getDirectories(),
|
||||
...pathsToAdd,
|
||||
],
|
||||
config.getDebugMode(),
|
||||
config.getFileService(),
|
||||
config.getExtensionContextFilePaths(),
|
||||
context.services.settings.merged.context?.importFormat ||
|
||||
'tree', // Use setting or default to 'tree'
|
||||
config.getFileFilteringOptions(),
|
||||
context.services.settings.merged.context?.discoveryMaxDirs,
|
||||
);
|
||||
config.setUserMemory(memoryContent);
|
||||
config.setGeminiMdFileCount(fileCount);
|
||||
context.ui.setGeminiMdFileCount(fileCount);
|
||||
}
|
||||
addItem(
|
||||
{
|
||||
type: MessageType.INFO,
|
||||
text: `Successfully added GEMINI.md files from the following directories if there are:\n- ${added.join('\n- ')}`,
|
||||
},
|
||||
Date.now(),
|
||||
);
|
||||
} catch (error) {
|
||||
errors.push(`Error refreshing memory: ${(error as Error).message}`);
|
||||
}
|
||||
|
||||
if (added.length > 0) {
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { CommandKind, SlashCommand } from './types.js';
|
||||
import type { SlashCommand } from './types.js';
|
||||
import { CommandKind } from './types.js';
|
||||
import { MessageType, type HistoryItemHelp } from '../types.js';
|
||||
|
||||
export const helpCommand: SlashCommand = {
|
||||
|
||||
@@ -4,15 +4,8 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import {
|
||||
MockInstance,
|
||||
vi,
|
||||
describe,
|
||||
it,
|
||||
expect,
|
||||
beforeEach,
|
||||
afterEach,
|
||||
} from 'vitest';
|
||||
import type { MockInstance } from 'vitest';
|
||||
import { vi, describe, it, expect, beforeEach, afterEach } from 'vitest';
|
||||
import { ideCommand } from './ideCommand.js';
|
||||
import { type CommandContext } from './types.js';
|
||||
import { type Config, DetectedIde } from '@qwen-code/qwen-code-core';
|
||||
@@ -20,7 +13,14 @@ import * as core from '@qwen-code/qwen-code-core';
|
||||
|
||||
vi.mock('child_process');
|
||||
vi.mock('glob');
|
||||
vi.mock('@qwen-code/qwen-code-core');
|
||||
vi.mock('@qwen-code/qwen-code-core', async (importOriginal) => {
|
||||
const original = await importOriginal<typeof core>();
|
||||
return {
|
||||
...original,
|
||||
getOauthClient: vi.fn(original.getOauthClient),
|
||||
getIdeInstaller: vi.fn(original.getIdeInstaller),
|
||||
};
|
||||
});
|
||||
|
||||
describe('ideCommand', () => {
|
||||
let mockContext: CommandContext;
|
||||
|
||||
@@ -4,24 +4,20 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import type { Config, IdeClient, File } from '@qwen-code/qwen-code-core';
|
||||
import {
|
||||
Config,
|
||||
DetectedIde,
|
||||
QWEN_CODE_COMPANION_EXTENSION_NAME,
|
||||
IDEConnectionStatus,
|
||||
getIdeInfo,
|
||||
getIdeInstaller,
|
||||
IdeClient,
|
||||
type File,
|
||||
IDEConnectionStatus,
|
||||
ideContext,
|
||||
} from '@qwen-code/qwen-code-core';
|
||||
import path from 'node:path';
|
||||
import {
|
||||
import type {
|
||||
CommandContext,
|
||||
SlashCommand,
|
||||
SlashCommandActionReturn,
|
||||
CommandKind,
|
||||
} from './types.js';
|
||||
import { CommandKind } from './types.js';
|
||||
import { SettingScope } from '../../config/settings.js';
|
||||
|
||||
function getIdeStatusMessage(ideClient: IdeClient): {
|
||||
@@ -130,11 +126,7 @@ export const ideCommand = (config: Config | null): SlashCommand | null => {
|
||||
({
|
||||
type: 'message',
|
||||
messageType: 'error',
|
||||
content: `IDE integration is not supported in your current environment. To use this feature, run Qwen Code in one of these supported IDEs: ${Object.values(
|
||||
DetectedIde,
|
||||
)
|
||||
.map((ide) => getIdeInfo(ide).displayName)
|
||||
.join(', ')}`,
|
||||
content: `IDE integration is not supported in your current environment. To use this feature, run Qwen Code in one of these supported IDEs: VS Code or VS Code forks.`,
|
||||
}) as const,
|
||||
};
|
||||
}
|
||||
@@ -195,7 +187,11 @@ export const ideCommand = (config: Config | null): SlashCommand | null => {
|
||||
Date.now(),
|
||||
);
|
||||
if (result.success) {
|
||||
context.services.settings.setValue(SettingScope.User, 'ideMode', true);
|
||||
context.services.settings.setValue(
|
||||
SettingScope.User,
|
||||
'ide.enabled',
|
||||
true,
|
||||
);
|
||||
// Poll for up to 5 seconds for the extension to activate.
|
||||
for (let i = 0; i < 10; i++) {
|
||||
await config.setIdeModeAndSyncConnection(true);
|
||||
@@ -235,7 +231,11 @@ export const ideCommand = (config: Config | null): SlashCommand | null => {
|
||||
description: 'enable IDE integration',
|
||||
kind: CommandKind.BUILT_IN,
|
||||
action: async (context: CommandContext) => {
|
||||
context.services.settings.setValue(SettingScope.User, 'ideMode', true);
|
||||
context.services.settings.setValue(
|
||||
SettingScope.User,
|
||||
'ide.enabled',
|
||||
true,
|
||||
);
|
||||
await config.setIdeModeAndSyncConnection(true);
|
||||
const { messageType, content } = getIdeStatusMessage(ideClient);
|
||||
context.ui.addItem(
|
||||
@@ -253,7 +253,11 @@ export const ideCommand = (config: Config | null): SlashCommand | null => {
|
||||
description: 'disable IDE integration',
|
||||
kind: CommandKind.BUILT_IN,
|
||||
action: async (context: CommandContext) => {
|
||||
context.services.settings.setValue(SettingScope.User, 'ideMode', false);
|
||||
context.services.settings.setValue(
|
||||
SettingScope.User,
|
||||
'ide.enabled',
|
||||
false,
|
||||
);
|
||||
await config.setIdeModeAndSyncConnection(false);
|
||||
const { messageType, content } = getIdeStatusMessage(ideClient);
|
||||
context.ui.addItem(
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
*/
|
||||
|
||||
import { vi, describe, it, expect, beforeEach, afterEach } from 'vitest';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import * as fs from 'node:fs';
|
||||
import * as path from 'node:path';
|
||||
import { initCommand } from './initCommand.js';
|
||||
import { createMockCommandContext } from '../../test-utils/mockCommandContext.js';
|
||||
import { type CommandContext } from './types.js';
|
||||
|
||||
@@ -4,15 +4,15 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import {
|
||||
import * as fs from 'node:fs';
|
||||
import * as path from 'node:path';
|
||||
import type {
|
||||
CommandContext,
|
||||
SlashCommand,
|
||||
SlashCommandActionReturn,
|
||||
CommandKind,
|
||||
} from './types.js';
|
||||
import { getCurrentGeminiMdFilename } from '@qwen-code/qwen-code-core';
|
||||
import { CommandKind } from './types.js';
|
||||
|
||||
export const initCommand: SlashCommand = {
|
||||
name: 'init',
|
||||
|
||||
@@ -15,8 +15,9 @@ import {
|
||||
DiscoveredMCPTool,
|
||||
} from '@qwen-code/qwen-code-core';
|
||||
|
||||
import { MessageActionReturn } from './types.js';
|
||||
import { Type, CallableTool } from '@google/genai';
|
||||
import type { MessageActionReturn } from './types.js';
|
||||
import type { CallableTool } from '@google/genai';
|
||||
import { Type } from '@google/genai';
|
||||
|
||||
vi.mock('@qwen-code/qwen-code-core', async (importOriginal) => {
|
||||
const actual =
|
||||
|
||||
@@ -4,15 +4,15 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import {
|
||||
import type {
|
||||
SlashCommand,
|
||||
SlashCommandActionReturn,
|
||||
CommandContext,
|
||||
CommandKind,
|
||||
MessageActionReturn,
|
||||
} from './types.js';
|
||||
import { CommandKind } from './types.js';
|
||||
import type { DiscoveredMCPPrompt } from '@qwen-code/qwen-code-core';
|
||||
import {
|
||||
DiscoveredMCPPrompt,
|
||||
DiscoveredMCPTool,
|
||||
getMCPDiscoveryState,
|
||||
getMCPServerStatus,
|
||||
|
||||
@@ -4,12 +4,13 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { vi, describe, it, expect, beforeEach, Mock } from 'vitest';
|
||||
import type { Mock } from 'vitest';
|
||||
import { vi, describe, it, expect, beforeEach } from 'vitest';
|
||||
import { memoryCommand } from './memoryCommand.js';
|
||||
import { type CommandContext, SlashCommand } from './types.js';
|
||||
import type { SlashCommand, type CommandContext } from './types.js';
|
||||
import { createMockCommandContext } from '../../test-utils/mockCommandContext.js';
|
||||
import { MessageType } from '../types.js';
|
||||
import { LoadedSettings } from '../../config/settings.js';
|
||||
import type { LoadedSettings } from '../../config/settings.js';
|
||||
import {
|
||||
getErrorMessage,
|
||||
loadServerHierarchicalMemory,
|
||||
|
||||
@@ -13,11 +13,8 @@ import path from 'node:path';
|
||||
import os from 'os';
|
||||
import fs from 'fs/promises';
|
||||
import { MessageType } from '../types.js';
|
||||
import {
|
||||
CommandKind,
|
||||
SlashCommand,
|
||||
SlashCommandActionReturn,
|
||||
} from './types.js';
|
||||
import type { SlashCommand, SlashCommandActionReturn } from './types.js';
|
||||
import { CommandKind } from './types.js';
|
||||
|
||||
export const memoryCommand: SlashCommand = {
|
||||
name: 'memory',
|
||||
@@ -269,9 +266,10 @@ export const memoryCommand: SlashCommand = {
|
||||
config.getDebugMode(),
|
||||
config.getFileService(),
|
||||
config.getExtensionContextFilePaths(),
|
||||
context.services.settings.merged.memoryImportFormat || 'tree', // Use setting or default to 'tree'
|
||||
context.services.settings.merged.context?.importFormat ||
|
||||
'tree', // Use setting or default to 'tree'
|
||||
config.getFileFilteringOptions(),
|
||||
context.services.settings.merged.memoryDiscoveryMaxDirs,
|
||||
context.services.settings.merged.context?.discoveryMaxDirs,
|
||||
);
|
||||
config.setUserMemory(memoryContent);
|
||||
config.setGeminiMdFileCount(fileCount);
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { CommandKind, OpenDialogActionReturn, SlashCommand } from './types.js';
|
||||
import type { OpenDialogActionReturn, SlashCommand } from './types.js';
|
||||
import { CommandKind } from './types.js';
|
||||
|
||||
export const privacyCommand: SlashCommand = {
|
||||
name: 'privacy',
|
||||
|
||||
@@ -5,13 +5,13 @@
|
||||
*/
|
||||
|
||||
import { vi, describe, it, expect, beforeEach, afterEach } from 'vitest';
|
||||
import * as fs from 'fs/promises';
|
||||
import * as os from 'os';
|
||||
import * as path from 'path';
|
||||
import * as fs from 'node:fs/promises';
|
||||
import * as os from 'node:os';
|
||||
import * as path from 'node:path';
|
||||
import { restoreCommand } from './restoreCommand.js';
|
||||
import { type CommandContext } from './types.js';
|
||||
import { createMockCommandContext } from '../../test-utils/mockCommandContext.js';
|
||||
import { Config, GitService } from '@qwen-code/qwen-code-core';
|
||||
import type { Config, GitService } from '@qwen-code/qwen-code-core';
|
||||
|
||||
describe('restoreCommand', () => {
|
||||
let mockContext: CommandContext;
|
||||
@@ -39,7 +39,10 @@ describe('restoreCommand', () => {
|
||||
|
||||
mockConfig = {
|
||||
getCheckpointingEnabled: vi.fn().mockReturnValue(true),
|
||||
getProjectTempDir: vi.fn().mockReturnValue(geminiTempDir),
|
||||
storage: {
|
||||
getProjectTempCheckpointsDir: vi.fn().mockReturnValue(checkpointsDir),
|
||||
getProjectTempDir: vi.fn().mockReturnValue(geminiTempDir),
|
||||
},
|
||||
getGeminiClient: vi.fn().mockReturnValue({
|
||||
setHistory: mockSetHistory,
|
||||
}),
|
||||
@@ -77,7 +80,9 @@ describe('restoreCommand', () => {
|
||||
|
||||
describe('action', () => {
|
||||
it('should return an error if temp dir is not found', async () => {
|
||||
vi.mocked(mockConfig.getProjectTempDir).mockReturnValue('');
|
||||
vi.mocked(
|
||||
mockConfig.storage.getProjectTempCheckpointsDir,
|
||||
).mockReturnValue('');
|
||||
|
||||
expect(
|
||||
await restoreCommand(mockConfig)?.action?.(mockContext, ''),
|
||||
@@ -219,7 +224,7 @@ describe('restoreCommand', () => {
|
||||
|
||||
describe('completion', () => {
|
||||
it('should return an empty array if temp dir is not found', async () => {
|
||||
vi.mocked(mockConfig.getProjectTempDir).mockReturnValue('');
|
||||
vi.mocked(mockConfig.storage.getProjectTempDir).mockReturnValue('');
|
||||
const command = restoreCommand(mockConfig);
|
||||
|
||||
expect(await command?.completion?.(mockContext, '')).toEqual([]);
|
||||
|
||||
@@ -4,15 +4,15 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import * as fs from 'fs/promises';
|
||||
import path from 'path';
|
||||
import * as fs from 'node:fs/promises';
|
||||
import path from 'node:path';
|
||||
import {
|
||||
type CommandContext,
|
||||
type SlashCommand,
|
||||
type SlashCommandActionReturn,
|
||||
CommandKind,
|
||||
} from './types.js';
|
||||
import { Config } from '@qwen-code/qwen-code-core';
|
||||
import type { Config } from '@qwen-code/qwen-code-core';
|
||||
|
||||
async function restoreAction(
|
||||
context: CommandContext,
|
||||
@@ -22,9 +22,7 @@ async function restoreAction(
|
||||
const { config, git: gitService } = services;
|
||||
const { addItem, loadHistory } = ui;
|
||||
|
||||
const checkpointDir = config?.getProjectTempDir()
|
||||
? path.join(config.getProjectTempDir(), 'checkpoints')
|
||||
: undefined;
|
||||
const checkpointDir = config?.storage.getProjectTempCheckpointsDir();
|
||||
|
||||
if (!checkpointDir) {
|
||||
return {
|
||||
@@ -125,9 +123,7 @@ async function completion(
|
||||
): Promise<string[]> {
|
||||
const { services } = context;
|
||||
const { config } = services;
|
||||
const checkpointDir = config?.getProjectTempDir()
|
||||
? path.join(config.getProjectTempDir(), 'checkpoints')
|
||||
: undefined;
|
||||
const checkpointDir = config?.storage.getProjectTempCheckpointsDir();
|
||||
if (!checkpointDir) {
|
||||
return [];
|
||||
}
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { CommandKind, OpenDialogActionReturn, SlashCommand } from './types.js';
|
||||
import type { OpenDialogActionReturn, SlashCommand } from './types.js';
|
||||
import { CommandKind } from './types.js';
|
||||
|
||||
export const settingsCommand: SlashCommand = {
|
||||
name: 'settings',
|
||||
|
||||
@@ -15,7 +15,7 @@ import {
|
||||
updateGitignore,
|
||||
GITHUB_WORKFLOW_PATHS,
|
||||
} from './setupGithubCommand.js';
|
||||
import { CommandContext, ToolActionReturn } from './types.js';
|
||||
import type { CommandContext, ToolActionReturn } from './types.js';
|
||||
import * as commandUtils from '../utils/commandUtils.js';
|
||||
|
||||
vi.mock('child_process');
|
||||
|
||||
@@ -9,7 +9,7 @@ import * as fs from 'node:fs';
|
||||
import { Writable } from 'node:stream';
|
||||
import { ProxyAgent } from 'undici';
|
||||
|
||||
import { CommandContext } from '../../ui/commands/types.js';
|
||||
import type { CommandContext } from '../../ui/commands/types.js';
|
||||
import {
|
||||
getGitRepoRoot,
|
||||
getLatestGitHubRelease,
|
||||
@@ -17,11 +17,8 @@ import {
|
||||
getGitHubRepoInfo,
|
||||
} from '../../utils/gitUtils.js';
|
||||
|
||||
import {
|
||||
CommandKind,
|
||||
SlashCommand,
|
||||
SlashCommandActionReturn,
|
||||
} from './types.js';
|
||||
import type { SlashCommand, SlashCommandActionReturn } from './types.js';
|
||||
import { CommandKind } from './types.js';
|
||||
import { getUrlOpenCommand } from '../../ui/utils/commandUtils.js';
|
||||
|
||||
export const GITHUB_WORKFLOW_PATHS = [
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { MessageType, HistoryItemStats } from '../types.js';
|
||||
import type { HistoryItemStats } from '../types.js';
|
||||
import { MessageType } from '../types.js';
|
||||
import { formatDuration } from '../utils/formatters.js';
|
||||
import {
|
||||
type CommandContext,
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import { terminalSetupCommand } from './terminalSetupCommand.js';
|
||||
import * as terminalSetupModule from '../utils/terminalSetup.js';
|
||||
import { CommandContext } from './types.js';
|
||||
import type { CommandContext } from './types.js';
|
||||
|
||||
vi.mock('../utils/terminalSetup.js');
|
||||
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { MessageActionReturn, SlashCommand, CommandKind } from './types.js';
|
||||
import type { MessageActionReturn, SlashCommand } from './types.js';
|
||||
import { CommandKind } from './types.js';
|
||||
import { terminalSetup } from '../utils/terminalSetup.js';
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { CommandKind, OpenDialogActionReturn, SlashCommand } from './types.js';
|
||||
import type { OpenDialogActionReturn, SlashCommand } from './types.js';
|
||||
import { CommandKind } from './types.js';
|
||||
|
||||
export const themeCommand: SlashCommand = {
|
||||
name: 'theme',
|
||||
|
||||
@@ -4,11 +4,11 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { describe, it, expect, vi } from 'vitest';
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { toolsCommand } from './toolsCommand.js';
|
||||
import { createMockCommandContext } from '../../test-utils/mockCommandContext.js';
|
||||
import { MessageType } from '../types.js';
|
||||
import { Tool } from '@qwen-code/qwen-code-core';
|
||||
import type { Tool } from '@qwen-code/qwen-code-core';
|
||||
|
||||
// Mock tools for testing
|
||||
const mockTools = [
|
||||
|
||||
@@ -13,7 +13,7 @@ import { MessageType } from '../types.js';
|
||||
|
||||
export const toolsCommand: SlashCommand = {
|
||||
name: 'tools',
|
||||
description: 'list available Qwen Codetools',
|
||||
description: 'list available Qwen Code tools. Usage: /tools [desc]',
|
||||
kind: CommandKind.BUILT_IN,
|
||||
action: async (context: CommandContext, args?: string): Promise<void> => {
|
||||
const subCommand = args?.trim();
|
||||
|
||||
@@ -5,13 +5,12 @@
|
||||
*/
|
||||
|
||||
import { type ReactNode } from 'react';
|
||||
import { Content } from '@google/genai';
|
||||
import { HistoryItemWithoutId } from '../types.js';
|
||||
import { Config, GitService, Logger } from '@qwen-code/qwen-code-core';
|
||||
import { LoadedSettings } from '../../config/settings.js';
|
||||
import { UseHistoryManagerReturn } from '../hooks/useHistoryManager.js';
|
||||
import type { HistoryItem } from '../types.js';
|
||||
import { SessionStatsState } from '../contexts/SessionContext.js';
|
||||
import type { Content, PartListUnion } from '@google/genai';
|
||||
import type { HistoryItemWithoutId, HistoryItem } from '../types.js';
|
||||
import type { Config, GitService, Logger } from '@qwen-code/qwen-code-core';
|
||||
import type { LoadedSettings } from '../../config/settings.js';
|
||||
import type { UseHistoryManagerReturn } from '../hooks/useHistoryManager.js';
|
||||
import type { SessionStatsState } from '../contexts/SessionContext.js';
|
||||
|
||||
// Grouped dependencies for clarity and easier mocking
|
||||
export interface CommandContext {
|
||||
@@ -123,7 +122,7 @@ export interface LoadHistoryActionReturn {
|
||||
*/
|
||||
export interface SubmitPromptActionReturn {
|
||||
type: 'submit_prompt';
|
||||
content: string;
|
||||
content: PartListUnion;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { CommandKind, SlashCommand } from './types.js';
|
||||
import type { SlashCommand } from './types.js';
|
||||
import { CommandKind } from './types.js';
|
||||
|
||||
export const vimCommand: SlashCommand = {
|
||||
name: 'vim',
|
||||
|
||||
Reference in New Issue
Block a user