Merge tag 'v0.3.0' into chore/sync-gemini-cli-v0.3.0

This commit is contained in:
mingholy.lmh
2025-09-10 21:01:40 +08:00
583 changed files with 30160 additions and 10770 deletions

View File

@@ -16,12 +16,11 @@ import {
import { renderHook, act } from '@testing-library/react';
import { useAutoAcceptIndicator } from './useAutoAcceptIndicator.js';
import {
Config,
Config as ActualConfigType,
ApprovalMode,
} from '@qwen-code/qwen-code-core';
import { useKeypress, Key } from './useKeypress.js';
import type { Config as ActualConfigType } from '@qwen-code/qwen-code-core';
import { Config, ApprovalMode } from '@qwen-code/qwen-code-core';
import type { Key } from './useKeypress.js';
import { useKeypress } from './useKeypress.js';
import { MessageType } from '../types.js';
vi.mock('./useKeypress.js');
@@ -38,6 +37,7 @@ vi.mock('@qwen-code/qwen-code-core', async () => {
interface MockConfigInstanceShape {
getApprovalMode: Mock<() => ApprovalMode>;
setApprovalMode: Mock<(value: ApprovalMode) => void>;
isTrustedFolder: Mock<() => boolean>;
getCoreTools: Mock<() => string[]>;
getToolDiscoveryCommand: Mock<() => string | undefined>;
getTargetDir: Mock<() => string>;
@@ -76,6 +76,7 @@ describe('useAutoAcceptIndicator', () => {
setApprovalMode: instanceSetApprovalModeMock as Mock<
(value: ApprovalMode) => void
>,
isTrustedFolder: vi.fn().mockReturnValue(true) as Mock<() => boolean>,
getCoreTools: vi.fn().mockReturnValue([]) as Mock<() => string[]>,
getToolDiscoveryCommand: vi.fn().mockReturnValue(undefined) as Mock<
() => string | undefined
@@ -126,6 +127,7 @@ describe('useAutoAcceptIndicator', () => {
const { result } = renderHook(() =>
useAutoAcceptIndicator({
config: mockConfigInstance as unknown as ActualConfigType,
addItem: vi.fn(),
}),
);
expect(result.current).toBe(ApprovalMode.AUTO_EDIT);
@@ -137,6 +139,7 @@ describe('useAutoAcceptIndicator', () => {
const { result } = renderHook(() =>
useAutoAcceptIndicator({
config: mockConfigInstance as unknown as ActualConfigType,
addItem: vi.fn(),
}),
);
expect(result.current).toBe(ApprovalMode.DEFAULT);
@@ -148,6 +151,7 @@ describe('useAutoAcceptIndicator', () => {
const { result } = renderHook(() =>
useAutoAcceptIndicator({
config: mockConfigInstance as unknown as ActualConfigType,
addItem: vi.fn(),
}),
);
expect(result.current).toBe(ApprovalMode.YOLO);
@@ -159,6 +163,7 @@ describe('useAutoAcceptIndicator', () => {
const { result } = renderHook(() =>
useAutoAcceptIndicator({
config: mockConfigInstance as unknown as ActualConfigType,
addItem: vi.fn(),
}),
);
expect(result.current).toBe(ApprovalMode.DEFAULT);
@@ -226,6 +231,7 @@ describe('useAutoAcceptIndicator', () => {
renderHook(() =>
useAutoAcceptIndicator({
config: mockConfigInstance as unknown as ActualConfigType,
addItem: vi.fn(),
}),
);
@@ -282,10 +288,12 @@ describe('useAutoAcceptIndicator', () => {
it('should update indicator when config value changes externally (useEffect dependency)', () => {
mockConfigInstance.getApprovalMode.mockReturnValue(ApprovalMode.DEFAULT);
const { result, rerender } = renderHook(
(props: { config: ActualConfigType }) => useAutoAcceptIndicator(props),
(props: { config: ActualConfigType; addItem: () => void }) =>
useAutoAcceptIndicator(props),
{
initialProps: {
config: mockConfigInstance as unknown as ActualConfigType,
addItem: vi.fn(),
},
},
);
@@ -293,8 +301,173 @@ describe('useAutoAcceptIndicator', () => {
mockConfigInstance.getApprovalMode.mockReturnValue(ApprovalMode.AUTO_EDIT);
rerender({ config: mockConfigInstance as unknown as ActualConfigType });
rerender({
config: mockConfigInstance as unknown as ActualConfigType,
addItem: vi.fn(),
});
expect(result.current).toBe(ApprovalMode.AUTO_EDIT);
expect(mockConfigInstance.getApprovalMode).toHaveBeenCalledTimes(3);
});
describe('in untrusted folders', () => {
beforeEach(() => {
mockConfigInstance.isTrustedFolder.mockReturnValue(false);
});
it('should not enable YOLO mode when Ctrl+Y is pressed', () => {
mockConfigInstance.getApprovalMode.mockReturnValue(ApprovalMode.DEFAULT);
mockConfigInstance.setApprovalMode.mockImplementation(() => {
throw new Error(
'Cannot enable privileged approval modes in an untrusted folder.',
);
});
const mockAddItem = vi.fn();
const { result } = renderHook(() =>
useAutoAcceptIndicator({
config: mockConfigInstance as unknown as ActualConfigType,
addItem: mockAddItem,
}),
);
expect(result.current).toBe(ApprovalMode.DEFAULT);
act(() => {
capturedUseKeypressHandler({ name: 'y', ctrl: true } as Key);
});
// We expect setApprovalMode to be called, and the error to be caught.
expect(mockConfigInstance.setApprovalMode).toHaveBeenCalledWith(
ApprovalMode.YOLO,
);
expect(mockAddItem).toHaveBeenCalled();
// Verify the underlying config value was not changed
expect(mockConfigInstance.getApprovalMode()).toBe(ApprovalMode.DEFAULT);
});
it('should not enable AUTO_EDIT mode when Shift+Tab is pressed', () => {
mockConfigInstance.getApprovalMode.mockReturnValue(ApprovalMode.DEFAULT);
mockConfigInstance.setApprovalMode.mockImplementation(() => {
throw new Error(
'Cannot enable privileged approval modes in an untrusted folder.',
);
});
const mockAddItem = vi.fn();
const { result } = renderHook(() =>
useAutoAcceptIndicator({
config: mockConfigInstance as unknown as ActualConfigType,
addItem: mockAddItem,
}),
);
expect(result.current).toBe(ApprovalMode.DEFAULT);
act(() => {
capturedUseKeypressHandler({
name: 'tab',
shift: true,
} as Key);
});
// We expect setApprovalMode to be called, and the error to be caught.
expect(mockConfigInstance.setApprovalMode).toHaveBeenCalledWith(
ApprovalMode.AUTO_EDIT,
);
expect(mockAddItem).toHaveBeenCalled();
// Verify the underlying config value was not changed
expect(mockConfigInstance.getApprovalMode()).toBe(ApprovalMode.DEFAULT);
});
it('should disable YOLO mode when Ctrl+Y is pressed', () => {
mockConfigInstance.getApprovalMode.mockReturnValue(ApprovalMode.YOLO);
const mockAddItem = vi.fn();
renderHook(() =>
useAutoAcceptIndicator({
config: mockConfigInstance as unknown as ActualConfigType,
addItem: mockAddItem,
}),
);
act(() => {
capturedUseKeypressHandler({ name: 'y', ctrl: true } as Key);
});
expect(mockConfigInstance.setApprovalMode).toHaveBeenCalledWith(
ApprovalMode.DEFAULT,
);
expect(mockConfigInstance.getApprovalMode()).toBe(ApprovalMode.DEFAULT);
});
it('should disable AUTO_EDIT mode when Shift+Tab is pressed', () => {
mockConfigInstance.getApprovalMode.mockReturnValue(
ApprovalMode.AUTO_EDIT,
);
const mockAddItem = vi.fn();
renderHook(() =>
useAutoAcceptIndicator({
config: mockConfigInstance as unknown as ActualConfigType,
addItem: mockAddItem,
}),
);
act(() => {
capturedUseKeypressHandler({
name: 'tab',
shift: true,
} as Key);
});
expect(mockConfigInstance.setApprovalMode).toHaveBeenCalledWith(
ApprovalMode.DEFAULT,
);
expect(mockConfigInstance.getApprovalMode()).toBe(ApprovalMode.DEFAULT);
});
it('should show a warning when trying to enable privileged modes', () => {
// Mock the error thrown by setApprovalMode
const errorMessage =
'Cannot enable privileged approval modes in an untrusted folder.';
mockConfigInstance.setApprovalMode.mockImplementation(() => {
throw new Error(errorMessage);
});
const mockAddItem = vi.fn();
renderHook(() =>
useAutoAcceptIndicator({
config: mockConfigInstance as unknown as ActualConfigType,
addItem: mockAddItem,
}),
);
// Try to enable YOLO mode
act(() => {
capturedUseKeypressHandler({ name: 'y', ctrl: true } as Key);
});
expect(mockAddItem).toHaveBeenCalledWith(
{
type: MessageType.INFO,
text: errorMessage,
},
expect.any(Number),
);
// Try to enable AUTO_EDIT mode
act(() => {
capturedUseKeypressHandler({
name: 'tab',
shift: true,
} as Key);
});
expect(mockAddItem).toHaveBeenCalledWith(
{
type: MessageType.INFO,
text: errorMessage,
},
expect.any(Number),
);
expect(mockAddItem).toHaveBeenCalledTimes(2);
});
});
});