Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/cli/src/i18n/locales/ca.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export default {
'@src/myFile.ts': '@src/myFile.ts',
'Shell mode': 'Mode shell',
'YOLO mode': 'Mode YOLO',
'Auto mode': 'Mode auto',
'plan mode': 'mode de planificació',
'auto-accept edits': 'acceptació automàtica de canvis',
'Accepting edits': 'Acceptant canvis',
Expand Down
1 change: 1 addition & 0 deletions packages/cli/src/i18n/locales/de.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export default {
'@src/myFile.ts': '@src/myFile.ts',
'Shell mode': 'Shell-Modus',
'YOLO mode': 'YOLO-Modus',
'Auto mode': 'Auto-Modus',
'plan mode': 'Planungsmodus',
'auto-accept edits': 'Änderungen automatisch akzeptieren',
'Accepting edits': 'Änderungen werden akzeptiert',
Expand Down
1 change: 1 addition & 0 deletions packages/cli/src/i18n/locales/en.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export default {
'@src/myFile.ts': '@src/myFile.ts',
'Shell mode': 'Shell mode',
'YOLO mode': 'YOLO mode',
'Auto mode': 'Auto mode',
'plan mode': 'plan mode',
'auto-accept edits': 'auto-accept edits',
'Accepting edits': 'Accepting edits',
Expand Down
1 change: 1 addition & 0 deletions packages/cli/src/i18n/locales/fr.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export default {
'@src/myFile.ts': '@src/myFile.ts',
'Shell mode': 'Mode shell',
'YOLO mode': 'Mode YOLO',
'Auto mode': 'Mode auto',
'plan mode': 'mode plan',
'auto-accept edits': 'acceptation automatique des modifications',
'Accepting edits': 'Acceptation des modifications',
Expand Down
1 change: 1 addition & 0 deletions packages/cli/src/i18n/locales/ja.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export default {
'@src/myFile.ts': '@src/myFile.ts',
'Shell mode': 'シェルモード',
'YOLO mode': 'YOLOモード',
'Auto mode': 'Autoモード',
'plan mode': 'プランモード',
'auto-accept edits': '編集を自動承認',
'Accepting edits': '編集を承認中',
Expand Down
1 change: 1 addition & 0 deletions packages/cli/src/i18n/locales/pt.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export default {
'@src/myFile.ts': '@src/myFile.ts',
'Shell mode': 'Modo shell',
'YOLO mode': 'Modo YOLO',
'Auto mode': 'Modo auto',
'plan mode': 'modo planejamento',
'auto-accept edits': 'aceitar edições automaticamente',
'Accepting edits': 'Aceitando edições',
Expand Down
1 change: 1 addition & 0 deletions packages/cli/src/i18n/locales/ru.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export default {
'@src/myFile.ts': '@src/myFile.ts',
'Shell mode': 'Режим терминала',
'YOLO mode': 'Режим YOLO',
'Auto mode': 'Автоматический режим',
'plan mode': 'Режим планирования',
'auto-accept edits': 'Режим принятия правок',
'Accepting edits': 'Принятие правок',
Expand Down
1 change: 1 addition & 0 deletions packages/cli/src/i18n/locales/zh-TW.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export default {
'@src/myFile.ts': '@src/myFile.ts',
'Shell mode': 'Shell 模式',
'YOLO mode': 'YOLO 模式',
'Auto mode': 'Auto 模式',
'plan mode': '規劃模式',
'auto-accept edits': '自動接受編輯',
'Accepting edits': '接受編輯',
Expand Down
1 change: 1 addition & 0 deletions packages/cli/src/i18n/locales/zh.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export default {
'@src/myFile.ts': '@src/myFile.ts',
'Shell mode': 'Shell 模式',
'YOLO mode': 'YOLO 模式',
'Auto mode': 'Auto 模式',
'plan mode': '规划模式',
'auto-accept edits': '自动接受编辑',
'Accepting edits': '接受编辑',
Expand Down
7 changes: 2 additions & 5 deletions packages/cli/src/ui/components/AutoAcceptIndicator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { Text } from 'ink';
import { theme } from '../semantic-colors.js';
import { ApprovalMode } from '@qwen-code/qwen-code-core';
import { t } from '../../i18n/index.js';
import { getApprovalModeIndicatorColor } from './approvalModeVisuals.js';

interface AutoAcceptIndicatorProps {
approvalMode: ApprovalMode;
Expand All @@ -17,7 +18,7 @@ interface AutoAcceptIndicatorProps {
export const AutoAcceptIndicator: React.FC<AutoAcceptIndicatorProps> = ({
approvalMode,
}) => {
let textColor = '';
const textColor = getApprovalModeIndicatorColor(approvalMode) ?? '';
let textContent = '';
let subText = '';

Expand All @@ -28,22 +29,18 @@ export const AutoAcceptIndicator: React.FC<AutoAcceptIndicatorProps> = ({

switch (approvalMode) {
case ApprovalMode.PLAN:
textColor = theme.status.success;
textContent = t('plan mode');
subText = cycleText;
break;
case ApprovalMode.AUTO_EDIT:
textColor = theme.status.warning;
textContent = t('auto-accept edits');
subText = cycleText;
break;
case ApprovalMode.AUTO:
textColor = theme.status.warning;
textContent = t('auto mode (classifier-evaluated)');
subText = cycleText;
break;
case ApprovalMode.YOLO:
textColor = theme.status.error;
textContent = t('YOLO mode');
subText = cycleText;
break;
Expand Down
29 changes: 16 additions & 13 deletions packages/cli/src/ui/components/InputPrompt.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@ import { useReverseSearchCompletion } from '../hooks/useReverseSearchCompletion.
import { useCommandCompletion } from '../hooks/useCommandCompletion.js';
import { useExportCompletion } from '../hooks/useExportCompletion.js';
import { useFollowupSuggestionsCLI } from '../hooks/useFollowupSuggestions.js';
import type { Config } from '@qwen-code/qwen-code-core';
import type { Key } from '../hooks/useKeypress.js';
import { keyMatchers, Command } from '../keyMatchers.js';
import type { CommandContext, SlashCommand } from '../commands/types.js';
import {
ApprovalMode,
type Config,
Storage,
createDebugLogger,
} from '@qwen-code/qwen-code-core';
Expand Down Expand Up @@ -56,6 +56,7 @@ import {
import { FEEDBACK_DIALOG_KEYS } from '../FeedbackDialog.js';
import { BaseTextInput } from './BaseTextInput.js';
import type { RenderLineOptions } from './BaseTextInput.js';
import { getApprovalModePromptStyle } from './approvalModeVisuals.js';

/**
* Represents an attachment (e.g., pasted image) displayed above the input prompt
Expand Down Expand Up @@ -1529,22 +1530,24 @@ export const InputPrompt: React.FC<InputPromptProps> = ({
// eslint-disable-next-line react-hooks/exhaustive-deps -- only trigger on prop change
}, [promptSuggestion]);

const showAutoAcceptStyling =
!shellModeActive && approvalMode === ApprovalMode.AUTO_EDIT;
const showYoloStyling =
!shellModeActive && approvalMode === ApprovalMode.YOLO;
const approvalModePromptStyle = !shellModeActive
? getApprovalModePromptStyle(approvalMode)
: undefined;

let statusColor: string | undefined;
let statusText = '';
if (shellModeActive) {
statusColor = theme.ui.symbol;
statusText = t('Shell mode');
} else if (showYoloStyling) {
statusColor = theme.status.errorDim;
statusText = t('YOLO mode');
} else if (showAutoAcceptStyling) {
statusColor = theme.status.warningDim;
statusText = t('Accepting edits');
} else if (approvalModePromptStyle?.color) {
statusColor = approvalModePromptStyle.color;
if (approvalMode === ApprovalMode.YOLO) {
statusText = t('YOLO mode');
} else if (approvalMode === ApprovalMode.AUTO_EDIT) {
statusText = t('Accepting edits');
} else if (approvalMode === ApprovalMode.AUTO) {
statusText = t('Auto mode');

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Suggestion] The 'Auto mode' key is missing from all locale files under packages/cli/src/i18n/locales/ (zh, fr, ca, ja, etc.) and from mustTranslateKeys.ts. All peer status-text keys ('Shell mode', 'YOLO mode', 'Accepting edits') are properly translated. Non-English users will see the raw English string "Auto mode" in the prompt status area.

— qwen3.7-max via Qwen Code /review

}
}

const borderColor =
Expand All @@ -1567,8 +1570,8 @@ export const InputPrompt: React.FC<InputPromptProps> = ({
)
) : commandSearchActive ? (
<Text color={theme.text.accent}>(r:) </Text>
) : showYoloStyling ? (
'*'
) : approvalModePromptStyle ? (
approvalModePromptStyle.prefix
) : (
'>'

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Suggestion] The : '>' fallback here is dead code. getApprovalModePromptStyle() always returns at least { prefix: '>' }, so approvalModePromptStyle is always truthy when this branch is reached (shell mode is handled above). The fallback can never execute.

Suggested change
'>'
) : (
approvalModePromptStyle.prefix
)}{' '}

— qwen3.7-max via Qwen Code /review

)}{' '}
Expand Down
15 changes: 6 additions & 9 deletions packages/cli/src/ui/components/agent-view/AgentComposer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ import { keyMatchers, Command } from '../../keyMatchers.js';
import { theme } from '../../semantic-colors.js';
import { usePreferredEditor } from '../../hooks/usePreferredEditor.js';
import { t } from '../../../i18n/index.js';
import { getApprovalModePromptStyle } from '../approvalModeVisuals.js';

// ─── Types ──────────────────────────────────────────────────

Expand Down Expand Up @@ -243,22 +244,18 @@ export const AgentComposer: React.FC<AgentComposerProps> = ({ agentId }) => {

// ── Approval-mode styling (mirrors main InputPrompt) ──

const isYolo = agentApprovalMode === ApprovalMode.YOLO;
const isAutoAccept = agentApprovalMode !== ApprovalMode.DEFAULT;

const statusColor = isYolo
? theme.status.errorDim
: isAutoAccept
? theme.status.warningDim
: undefined;
const approvalModePromptStyle = getApprovalModePromptStyle(agentApprovalMode);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Suggestion] PLAN mode silently loses visual styling in sub-agent views — behavioral regression.

The old code used agentApprovalMode !== ApprovalMode.DEFAULT as the guard, which gave PLAN mode theme.status.warningDim for both border and prefix. The new getApprovalModePromptStyle(PLAN) returns { prefix: '>' } with no color, making PLAN visually identical to DEFAULT in AgentComposer. Meanwhile, AutoAcceptIndicator still shows PLAN as green (theme.status.success), creating conflicting visual signals.

If this is intentional (PLAN shouldn't have warning-style coloring), consider adding a test that asserts getApprovalModePromptStyle(ApprovalMode.PLAN) has no color to lock in the intent. Otherwise, add PLAN to the shared function:

Suggested change
const approvalModePromptStyle = getApprovalModePromptStyle(agentApprovalMode);
const approvalModePromptStyle = getApprovalModePromptStyle(agentApprovalMode);
const statusColor = approvalModePromptStyle.color;
// Note: PLAN mode now renders identically to DEFAULT — confirm this is intended.

— qwen3.7-max via Qwen Code /review

const statusColor = approvalModePromptStyle.color;

const inputBorderColor =
!isInputActive || agentTabBarFocused
? theme.border.default
: (statusColor ?? theme.border.focused);

const prefixNode = (
<Text color={statusColor ?? theme.text.accent}>{isYolo ? '*' : '>'} </Text>
<Text color={statusColor ?? theme.text.accent}>
{approvalModePromptStyle.prefix}{' '}
</Text>
);

return (
Expand Down
42 changes: 42 additions & 0 deletions packages/cli/src/ui/components/approvalModeVisuals.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/**
* @license
* Copyright 2025 Qwen Team
* SPDX-License-Identifier: Apache-2.0
*/

import { describe, expect, it } from 'vitest';
import { ApprovalMode } from '@qwen-code/qwen-code-core';
import { theme } from '../semantic-colors.js';
import {
getApprovalModeIndicatorColor,
getApprovalModePromptStyle,
} from './approvalModeVisuals.js';

describe('approval mode visuals', () => {
it('uses distinct colors for auto-edit and classifier auto mode', () => {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Suggestion] Several ApprovalMode branches are untested:

  • getApprovalModeIndicatorColor: missing assertions for PLAN (theme.status.success), YOLO (theme.status.error), and DEFAULT (undefined)
  • getApprovalModePromptStyle: the PLAN/DEFAULT/default fallthrough (which returns { prefix: '>' } with no color/label) is completely untested

Adding these would guard against accidental styling regressions, especially for the PLAN/DEFAULT path which is the exact code path that changes behavior in AgentComposer.

— qwen3.7-max via Qwen Code /review

expect(getApprovalModeIndicatorColor(ApprovalMode.AUTO_EDIT)).toBe(
theme.status.warning,
);
expect(getApprovalModeIndicatorColor(ApprovalMode.AUTO)).toBe(
theme.text.link,
);
});

it('gives classifier auto mode its own input styling', () => {
expect(getApprovalModePromptStyle(ApprovalMode.AUTO_EDIT)).toEqual({
color: theme.status.warningDim,
prefix: '>',
});
expect(getApprovalModePromptStyle(ApprovalMode.AUTO)).toEqual({
color: theme.text.link,
prefix: '>',
});
});

it('keeps yolo visually separate from both auto modes', () => {
expect(getApprovalModePromptStyle(ApprovalMode.YOLO)).toEqual({
color: theme.status.errorDim,
prefix: '*',
});
});
});
44 changes: 44 additions & 0 deletions packages/cli/src/ui/components/approvalModeVisuals.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/**
* @license
* Copyright 2025 Qwen Team
* SPDX-License-Identifier: Apache-2.0
*/

import { ApprovalMode } from '@qwen-code/qwen-code-core';
import { theme } from '../semantic-colors.js';

export function getApprovalModeIndicatorColor(
approvalMode: ApprovalMode,
): string | undefined {
switch (approvalMode) {
case ApprovalMode.PLAN:
return theme.status.success;
case ApprovalMode.AUTO_EDIT:
return theme.status.warning;
case ApprovalMode.AUTO:
return theme.text.link;
case ApprovalMode.YOLO:
return theme.status.error;
case ApprovalMode.DEFAULT:
default:
return undefined;
}
}

export function getApprovalModePromptStyle(approvalMode: ApprovalMode): {
color?: string;
prefix: '>' | '*';
} {
switch (approvalMode) {
case ApprovalMode.AUTO_EDIT:
return { color: theme.status.warningDim, prefix: '>' };
case ApprovalMode.AUTO:
return { color: theme.text.link, prefix: '>' };

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Suggestion] AUTO uses full-brightness theme.text.link (AccentBlue) for the prompt, breaking the dim-for-prompt / bright-for-indicator pattern and colliding with border.focused.

Every other mode uses dim tokens for prompts: AUTO_EDIT → status.warningDim (AccentYellowDim), YOLO → status.errorDim (AccentRedDim). AUTO uses text.link which resolves to the same AccentBlue as border.focused across all three themes. This makes the AUTO-mode input border visually indistinguishable from the DEFAULT-mode focused border.

Consider adding an AccentBlueDim token to the theme palette and using it here for consistency:

case ApprovalMode.AUTO:
  return { color: theme.status.infoDim /* new AccentBlueDim token */, prefix: '>' };

— qwen3.7-max via Qwen Code /review

case ApprovalMode.YOLO:
return { color: theme.status.errorDim, prefix: '*' };
case ApprovalMode.PLAN:
case ApprovalMode.DEFAULT:
default:
return { prefix: '>' };
}
}
Loading