Merge remote-tracking branch 'origin/main' into feat/remove-smart-edit-tool

# Conflicts:
#	packages/core/index.ts
#	packages/core/src/index.ts
This commit is contained in:
tanzhenxin 2026-02-05 18:08:22 +08:00
commit 6324863008
313 changed files with 18224 additions and 1327 deletions

View file

@ -21,21 +21,26 @@ export const AutoAcceptIndicator: React.FC<AutoAcceptIndicatorProps> = ({
let textContent = '';
let subText = '';
const cycleText =
process.platform === 'win32'
? ` ${t('(tab to cycle)')}`
: ` ${t('(shift + tab to cycle)')}`;
switch (approvalMode) {
case ApprovalMode.PLAN:
textColor = theme.status.success;
textContent = t('plan mode');
subText = ` ${t('(shift + tab to cycle)')}`;
subText = cycleText;
break;
case ApprovalMode.AUTO_EDIT:
textColor = theme.status.warning;
textContent = t('auto-accept edits');
subText = ` ${t('(shift + tab to cycle)')}`;
subText = cycleText;
break;
case ApprovalMode.YOLO:
textColor = theme.status.error;
textContent = t('YOLO mode');
subText = ` ${t('(shift + tab to cycle)')}`;
subText = cycleText;
break;
case ApprovalMode.DEFAULT:
default:

View file

@ -56,14 +56,16 @@ export const Composer = () => {
<Box flexDirection="column" marginTop={1}>
{!uiState.embeddedShellFocused && (
<LoadingIndicator
// Hide loading phrases when enableLoadingPhrases is explicitly false.
// Using === false ensures phrases show by default when undefined.
thought={
uiState.streamingState === StreamingState.WaitingForConfirmation ||
config.getAccessibility()?.disableLoadingPhrases
config.getAccessibility()?.enableLoadingPhrases === false
? undefined
: uiState.thought
}
currentLoadingPhrase={
config.getAccessibility()?.disableLoadingPhrases
config.getAccessibility()?.enableLoadingPhrases === false
? undefined
: uiState.currentLoadingPhrase
}

View file

@ -46,6 +46,18 @@ const mockCommands: readonly SlashCommand[] = [
];
describe('Help Component', () => {
it('should render platform-specific keyboard shortcuts', () => {
const { lastFrame } = render(<Help commands={mockCommands} />);
const output = lastFrame();
if (process.platform === 'win32') {
expect(output).toContain('Tab');
expect(output).not.toContain('Shift+Tab');
} else {
expect(output).toContain('Shift+Tab');
}
});
it('should not render hidden commands', () => {
const { lastFrame } = render(<Help commands={mockCommands} />);
const output = lastFrame();

View file

@ -154,7 +154,7 @@ export const Help: React.FC<Help> = ({ commands, width }) => (
</Text>
<Text color={theme.text.primary}>
<Text bold color={theme.text.accent}>
Shift+Tab
{process.platform === 'win32' ? 'Tab' : 'Shift+Tab'}
</Text>{' '}
- {t('Cycle approval modes')}
</Text>

View file

@ -28,7 +28,10 @@ const getShortcuts = (): Shortcut[] => [
{ key: '/', description: t('for commands') },
{ key: '@', description: t('for file paths') },
{ key: 'esc esc', description: t('to clear input') },
{ key: 'shift+tab', description: t('to cycle approvals') },
{
key: process.platform === 'win32' ? 'tab' : 'shift+tab',
description: t('to cycle approvals'),
},
{ key: 'ctrl+c', description: t('to quit') },
{ key: getNewlineKey(), description: t('for newline') + ' ⏎' },
{ key: 'ctrl+l', description: t('to clear screen') },

View file

@ -17,7 +17,9 @@ const startupTips = [
'You can run any shell commands from Qwen Code using ! (e.g. !ls).',
'Type / to open the command popup; Tab autocompletes slash commands and saved prompts.',
'You can resume a previous conversation by running qwen --continue or qwen --resume.',
'You can switch permission mode quickly with Shift+Tab or /approval-mode.',
process.platform === 'win32'
? 'You can switch permission mode quickly with Tab or /approval-mode.'
: 'You can switch permission mode quickly with Shift+Tab or /approval-mode.',
] as const;
export const Tips: React.FC = () => {