Skip to content

Commit 70396d1

Browse files
chiga0秦奇claude
authored
feat: optimize compact mode UX — shortcuts, settings sync, and safety (#3100)
* feat: optimize compact mode UX — shortcuts, settings sync, and safety improvements - Add Ctrl+O to keyboard shortcuts list (?) and /help command - Sync compact mode toggle from Settings dialog with CompactModeContext - Protect tool approval prompts from being hidden in compact mode (MainContent forces live rendering during WaitingForConfirmation) - Remove snapshot freezing on toggle — treat as persistent preference, not temporary peek (differs from Claude Code's session-scoped model) - Add compact mode tip to startup Tips rotation for non-intrusive discovery - Remove compact mode indicator from footer to reduce UI clutter - Add competitive analysis design doc (EN + ZH) comparing with Claude Code - Update user docs (settings.md) and i18n translations (en/zh/ru/pt) Relates to #3047, #2767, #2770 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * refactor: remove frozenSnapshot dead code and Chinese design doc - Remove frozenSnapshot state, useEffect, and all related logic from AppContainer, MainContent, CompactModeContext, and test files - Simplify MainContent to always render live pendingHistoryItems - Delete compact-mode-design-zh.md (redundant Chinese translation) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: address PR review feedback for compact mode optimization - Add refreshStatic() call after setCompactMode in SettingsDialog so already-rendered Static history updates immediately - Fix outdated column split comment in KeyboardShortcuts (5+4+4) - Update design doc: remove all frozenSnapshot references, renumber optimization recommendations, fix file reference descriptions - Add missing i18n keys for de.js and ja.js locales - Add test for SettingsDialog compact mode sync with CompactModeContext Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: prevent subagent confirmation from being hidden in compact mode hasConfirmingTool only checks ToolCallStatus.Confirming, but subagent approvals arrive via resultDisplay.pendingConfirmation while the tool status remains Executing. Add hasSubagentPendingConfirmation to the showCompact guard so tool groups with pending subagent confirmations are always force-expanded. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: force show subagent confirmation result in compact mode The previous fix (47ee03c) correctly force-expanded the tool group wrapper when a subagent had pending confirmation, but each inner ToolMessage still hid its resultDisplay due to compactMode check, which hid the AgentExecutionDisplay containing the inline confirmation UI. Add isAgentWithPendingConfirmation to forceShowResult conditions so the inner AgentExecutionDisplay is rendered even in compact mode. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat(compact-mode): merge consecutive tool groups across hidden items In compact mode, sequential tool calls across multiple LLM turns each produced a separate bordered box, defeating the "compact" intent. The model typically emits a `gemini_thought` between consecutive tool calls, which is hidden in compact mode — so visually the boxes look adjacent, but in `history` they are separated by hidden items. This commit adds render-time merging of consecutive tool_group history items, where "consecutive" allows hidden-in-compact items (`gemini_thought`, `gemini_thought_content`) between them. Key pieces: - New `mergeCompactToolGroups` utility that merges adjacent mergeable tool_groups, skipping hidden items between them. Force-expand conditions (Confirming/Error tools, subagent pending confirmation, user-initiated, focused embedded shell) preserve group boundaries so authorization prompts, errors, and shell focus stay visible. - `MainContent.tsx` applies the merger only when `compactMode === true` (verbose mode is unchanged) and calls `refreshStatic()` when a merge consolidates items, because Ink's `<Static>` is append-only and cannot replace already-committed terminal content. - `CompactToolGroupDisplay.tsx` shows a `× N` count when a merged group contains more than one tool, matching the existing single-turn multi-tool display style. - 19 unit tests covering empty/single/multiple groups, hidden-item skipping (the 8-tool real-world scenario), force-expand boundaries, mixed tool types, and complex sequences. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: 秦奇 <gary.gq@alibaba-inc.com> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 08d3d6e commit 70396d1

File tree

22 files changed

+1091
-70
lines changed

22 files changed

+1091
-70
lines changed

docs/design/compact-mode/compact-mode-design.md

Lines changed: 284 additions & 0 deletions
Large diffs are not rendered by default.

docs/users/configuration/settings.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ Settings are organized into categories. All settings should be placed within the
106106
| `ui.showMemoryUsage` | boolean | Display memory usage information in the UI. | `false` |
107107
| `ui.showLineNumbers` | boolean | Show line numbers in code blocks in the CLI output. | `true` |
108108
| `ui.showCitations` | boolean | Show citations for generated text in the chat. | `true` |
109-
| `ui.compactMode` | boolean | Hide tool output and thinking for a cleaner view. Toggle with `Ctrl+O` during a session. When enabled, a `compact` indicator appears in the footer. The setting persists across sessions. | `false` |
109+
| `ui.compactMode` | boolean | Hide tool output and thinking for a cleaner view. Toggle with `Ctrl+O` during a session or via the Settings dialog. Tool approval prompts are never hidden, even in compact mode. The setting persists across sessions. | `false` |
110110
| `enableWelcomeBack` | boolean | Show welcome back dialog when returning to a project with conversation history. When enabled, Qwen Code will automatically detect if you're returning to a project with a previously generated project summary (`.qwen/PROJECT_SUMMARY.md`) and show a dialog allowing you to continue your previous conversation or start fresh. This feature integrates with the `/summary` command and quit confirmation dialog. | `true` |
111111
| `ui.accessibility.enableLoadingPhrases` | boolean | Enable loading phrases (disable for accessibility). | `true` |
112112
| `ui.accessibility.screenReader` | boolean | Enables screen reader mode, which adjusts the TUI for better compatibility with screen readers. | `false` |

packages/cli/src/i18n/locales/de.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1787,6 +1787,8 @@ export default {
17871787
'Sie können den Berechtigungsmodus schnell mit Tab oder /approval-mode wechseln.',
17881788
'Try /insight to generate personalized insights from your chat history.':
17891789
'Probieren Sie /insight, um personalisierte Erkenntnisse aus Ihrem Chatverlauf zu erstellen.',
1790+
'Press Ctrl+O to toggle compact mode — hide tool output and thinking for a cleaner view.':
1791+
'Strg+O drücken, um den Kompaktmodus umzuschalten — Tool-Ausgabe und Denkprozess ausblenden.',
17901792
'Add a QWEN.md file to give Qwen Code persistent project context.':
17911793
'Fügen Sie eine QWEN.md-Datei hinzu, um Qwen Code dauerhaften Projektkontext zu geben.',
17921794
'Use /btw to ask a quick side question without disrupting the conversation.':
@@ -1993,6 +1995,8 @@ export default {
19931995
'(Use ↑ ↓ arrows to navigate, Enter to select, Ctrl+C to exit)\n':
19941996
'(↑ ↓ Pfeiltasten zum Navigieren, Enter zum Auswählen, Strg+C zum Beenden)\n',
19951997
compact: 'kompakt',
1998+
'compact mode: on (Ctrl+O off)': 'Kompaktmodus: ein (Strg+O aus)',
1999+
'to toggle compact mode': 'Kompaktmodus umschalten',
19962000
'Hide tool output and thinking for a cleaner view (toggle with Ctrl+O).':
19972001
'Tool-Ausgabe und Denkprozess ausblenden für eine übersichtlichere Ansicht (mit Strg+O umschalten).',
19982002
'Press Ctrl+O to show full tool output':

packages/cli/src/i18n/locales/en.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ export default {
5959
'to search history': 'to search history',
6060
'to paste images': 'to paste images',
6161
'for external editor': 'for external editor',
62+
'to toggle compact mode': 'to toggle compact mode',
6263
'Jump through words in the input': 'Jump through words in the input',
6364
'Close dialogs, cancel requests, or quit application':
6465
'Close dialogs, cancel requests, or quit application',
@@ -1563,6 +1564,8 @@ export default {
15631564
'You can switch permission mode quickly with Tab or /approval-mode.',
15641565
'Try /insight to generate personalized insights from your chat history.':
15651566
'Try /insight to generate personalized insights from your chat history.',
1567+
'Press Ctrl+O to toggle compact mode — hide tool output and thinking for a cleaner view.':
1568+
'Press Ctrl+O to toggle compact mode — hide tool output and thinking for a cleaner view.',
15661569
'Add a QWEN.md file to give Qwen Code persistent project context.':
15671570
'Add a QWEN.md file to give Qwen Code persistent project context.',
15681571
'Use /btw to ask a quick side question without disrupting the conversation.':
@@ -2033,6 +2036,7 @@ export default {
20332036
'(Use ↑ ↓ arrows to navigate, Enter to select, Ctrl+C to exit)\n':
20342037
'(Use ↑ ↓ arrows to navigate, Enter to select, Ctrl+C to exit)\n',
20352038
compact: 'compact',
2039+
'compact mode: on (Ctrl+O off)': 'compact mode: on (Ctrl+O off)',
20362040
'Hide tool output and thinking for a cleaner view (toggle with Ctrl+O).':
20372041
'Hide tool output and thinking for a cleaner view (toggle with Ctrl+O).',
20382042
'Press Ctrl+O to show full tool output':

packages/cli/src/i18n/locales/ja.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1182,6 +1182,8 @@ export default {
11821182
'Tab または /approval-mode で権限モードをすばやく切り替えられます。',
11831183
'Try /insight to generate personalized insights from your chat history.':
11841184
'/insight でチャット履歴からパーソナライズされたインサイトを生成できます。',
1185+
'Press Ctrl+O to toggle compact mode — hide tool output and thinking for a cleaner view.':
1186+
'Ctrl+O でコンパクトモードを切り替え — ツール出力と思考を非表示にしてすっきり表示。',
11851187
'Add a QWEN.md file to give Qwen Code persistent project context.':
11861188
'QWEN.md ファイルを追加すると、Qwen Code に永続的なプロジェクトコンテキストを与えられます。',
11871189
'Use /btw to ask a quick side question without disrupting the conversation.':
@@ -1484,6 +1486,8 @@ export default {
14841486
'(Use ↑ ↓ arrows to navigate, Enter to select, Ctrl+C to exit)\n':
14851487
'(↑ ↓ 矢印キーで移動、Enter で選択、Ctrl+C で終了)\n',
14861488
compact: 'コンパクト',
1489+
'compact mode: on (Ctrl+O off)': 'コンパクトモード: オン (Ctrl+O でオフ)',
1490+
'to toggle compact mode': 'コンパクトモードの切り替え',
14871491
'Hide tool output and thinking for a cleaner view (toggle with Ctrl+O).':
14881492
'コンパクトモードでツール出力と思考を非表示にします(Ctrl+O で切り替え)。',
14891493
'Press Ctrl+O to show full tool output': 'Ctrl+O で完全なツール出力を表示',

packages/cli/src/i18n/locales/pt.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ export default {
5151
'to search history': 'para pesquisar no histórico',
5252
'to paste images': 'para colar imagens',
5353
'for external editor': 'para editor externo',
54+
'to toggle compact mode': 'alternar modo compacto',
5455
'Jump through words in the input': 'Pular palavras na entrada',
5556
'Close dialogs, cancel requests, or quit application':
5657
'Fechar diálogos, cancelar solicitações ou sair do aplicativo',
@@ -1520,6 +1521,8 @@ export default {
15201521
'Você pode alternar o modo de permissão rapidamente com Shift+Tab ou /approval-mode.',
15211522
'Try /insight to generate personalized insights from your chat history.':
15221523
'Experimente /insight para gerar insights personalizados do seu histórico de conversas.',
1524+
'Press Ctrl+O to toggle compact mode — hide tool output and thinking for a cleaner view.':
1525+
'Pressione Ctrl+O para alternar o modo compacto — ocultar saída de ferramentas e raciocínio.',
15231526
'Add a QWEN.md file to give Qwen Code persistent project context.':
15241527
'Adicione um arquivo QWEN.md para dar ao Qwen Code um contexto persistente do projeto.',
15251528
'Use /btw to ask a quick side question without disrupting the conversation.':
@@ -1983,6 +1986,7 @@ export default {
19831986
'(Use ↑ ↓ arrows to navigate, Enter to select, Ctrl+C to exit)\n':
19841987
'(Use ↑ ↓ para navegar, Enter para selecionar, Ctrl+C para sair)\n',
19851988
compact: 'compacto',
1989+
'compact mode: on (Ctrl+O off)': 'modo compacto: ligado (Ctrl+O desligar)',
19861990
'Hide tool output and thinking for a cleaner view (toggle with Ctrl+O).':
19871991
'Ocultar saída da ferramenta e raciocínio para uma visualização mais limpa (alternar com Ctrl+O).',
19881992
'Press Ctrl+O to show full tool output':

packages/cli/src/i18n/locales/ru.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ export default {
8888
'to search history': 'поиск в истории',
8989
'to paste images': 'вставить изображения',
9090
'for external editor': 'внешний редактор',
91+
'to toggle compact mode': 'переключить компактный режим',
9192

9293
// ============================================================================
9394
// Поля системной информации
@@ -1714,6 +1715,8 @@ export default {
17141715
'Вы можете быстро переключать режим разрешений с помощью Tab или /approval-mode.',
17151716
'Try /insight to generate personalized insights from your chat history.':
17161717
'Попробуйте /insight, чтобы получить персонализированные выводы из истории чатов.',
1718+
'Press Ctrl+O to toggle compact mode — hide tool output and thinking for a cleaner view.':
1719+
'Нажмите Ctrl+O для переключения компактного режима — скрыть вывод инструментов и рассуждения.',
17171720
'Add a QWEN.md file to give Qwen Code persistent project context.':
17181721
'Добавьте файл QWEN.md, чтобы предоставить Qwen Code постоянный контекст проекта.',
17191722
'Use /btw to ask a quick side question without disrupting the conversation.':
@@ -1990,6 +1993,7 @@ export default {
19901993
'(Use ↑ ↓ arrows to navigate, Enter to select, Ctrl+C to exit)\n':
19911994
'(↑ ↓ стрелки для навигации, Enter для выбора, Ctrl+C для выхода)\n',
19921995
compact: 'компактный',
1996+
'compact mode: on (Ctrl+O off)': 'компактный режим: вкл (Ctrl+O выкл)',
19931997
'Hide tool output and thinking for a cleaner view (toggle with Ctrl+O).':
19941998
'Скрывать вывод инструментов и процесс рассуждений для более чистого вида (переключить с помощью Ctrl+O).',
19951999
'Press Ctrl+O to show full tool output':

packages/cli/src/i18n/locales/zh.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ export default {
5757
'to search history': '搜索历史',
5858
'to paste images': '粘贴图片',
5959
'for external editor': '外部编辑器',
60+
'to toggle compact mode': '切换紧凑模式',
6061
'Jump through words in the input': '在输入中按单词跳转',
6162
'Close dialogs, cancel requests, or quit application':
6263
'关闭对话框、取消请求或退出应用程序',
@@ -1480,6 +1481,8 @@ export default {
14801481
'按 Tab 或输入 /approval-mode 可快速切换权限模式。',
14811482
'Try /insight to generate personalized insights from your chat history.':
14821483
'试试 /insight,从聊天记录中生成个性化洞察。',
1484+
'Press Ctrl+O to toggle compact mode — hide tool output and thinking for a cleaner view.':
1485+
'按 Ctrl+O 切换紧凑模式 ── 隐藏工具输出和思考过程,界面更简洁。',
14831486
'Add a QWEN.md file to give Qwen Code persistent project context.':
14841487
'添加 QWEN.md 文件,为 Qwen Code 提供持久的项目上下文。',
14851488
'Use /btw to ask a quick side question without disrupting the conversation.':
@@ -1839,6 +1842,7 @@ export default {
18391842
'(Use ↑ ↓ arrows to navigate, Enter to select, Ctrl+C to exit)\n':
18401843
'(使用 ↑ ↓ 箭头导航,Enter 选择,Ctrl+C 退出)\n',
18411844
compact: '紧凑',
1845+
'compact mode: on (Ctrl+O off)': '紧凑模式:开(Ctrl+O 关闭)',
18421846
'Hide tool output and thinking for a cleaner view (toggle with Ctrl+O).':
18431847
'紧凑模式下隐藏工具输出和思考过程,界面更简洁(Ctrl+O 切换)。',
18441848
'Press Ctrl+O to show full tool output': '按 Ctrl+O 查看详细工具调用结果',

packages/cli/src/services/tips/tipRegistry.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,4 +175,13 @@ export const tipRegistry: ContextualTip[] = [
175175
cooldownPrompts: 0,
176176
priority: 50,
177177
},
178+
{
179+
id: 'compact-mode',
180+
content:
181+
'Press Ctrl+O to toggle compact mode — hide tool output and thinking for a cleaner view.',
182+
trigger: 'startup',
183+
isRelevant: () => true,
184+
cooldownPrompts: 0,
185+
priority: 50,
186+
},
178187
];

packages/cli/src/ui/AppContainer.tsx

Lines changed: 2 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1313,10 +1313,6 @@ export const AppContainer = (props: AppContainerProps) => {
13131313
const [compactMode, setCompactMode] = useState<boolean>(
13141314
settings.merged.ui?.compactMode ?? false,
13151315
);
1316-
const [frozenSnapshot, setFrozenSnapshot] = useState<
1317-
HistoryItemWithoutId[] | null
1318-
>(null);
1319-
13201316
const [ctrlCPressedOnce, setCtrlCPressedOnce] = useState(false);
13211317
const ctrlCTimerRef = useRef<NodeJS.Timeout | null>(null);
13221318
const [ctrlDPressedOnce, setCtrlDPressedOnce] = useState(false);
@@ -1331,18 +1327,6 @@ export const AppContainer = (props: AppContainerProps) => {
13311327
const [showEscapePrompt, setShowEscapePrompt] = useState(false);
13321328
const [showIdeRestartPrompt, setShowIdeRestartPrompt] = useState(false);
13331329

1334-
useEffect(() => {
1335-
// Clear frozen snapshot when streaming ends OR when entering confirmation
1336-
// state. During WaitingForConfirmation, the user needs to see the latest
1337-
// pending items (including the confirmation message) rather than a stale snapshot.
1338-
if (
1339-
streamingState === StreamingState.Idle ||
1340-
streamingState === StreamingState.WaitingForConfirmation
1341-
) {
1342-
setFrozenSnapshot(null);
1343-
}
1344-
}, [streamingState]);
1345-
13461330
const { isFolderTrustDialogOpen, handleFolderTrustSelect, isRestarting } =
13471331
useFolderTrust(settings, setIsTrustedFolder);
13481332
const {
@@ -1734,13 +1718,6 @@ export const AppContainer = (props: AppContainerProps) => {
17341718
setCompactMode(newValue);
17351719
void settings.setValue(SettingScope.User, 'ui.compactMode', newValue);
17361720
refreshStatic();
1737-
// Only freeze during the actual responding phase. WaitingForConfirmation
1738-
// must keep focus so the user can approve/cancel tool confirmation UI.
1739-
if (streamingState === StreamingState.Responding) {
1740-
setFrozenSnapshot([...pendingHistoryItems]);
1741-
} else {
1742-
setFrozenSnapshot(null);
1743-
}
17441721
}
17451722
},
17461723
[
@@ -1776,8 +1753,6 @@ export const AppContainer = (props: AppContainerProps) => {
17761753
isAuthenticating,
17771754
compactMode,
17781755
setCompactMode,
1779-
setFrozenSnapshot,
1780-
pendingHistoryItems,
17811756
refreshStatic,
17821757
],
17831758
);
@@ -2207,8 +2182,8 @@ export const AppContainer = (props: AppContainerProps) => {
22072182
);
22082183

22092184
const compactModeValue = useMemo(
2210-
() => ({ compactMode, frozenSnapshot }),
2211-
[compactMode, frozenSnapshot],
2185+
() => ({ compactMode, setCompactMode }),
2186+
[compactMode, setCompactMode],
22122187
);
22132188

22142189
return (

0 commit comments

Comments
 (0)