コンパクトモード設計:競合分析と最適化
Ctrl+O コンパクト/詳細モード切り替え — Claude Code との競合分析、現在の実装レビュー、最適化提案。
ユーザードキュメント: 設定 — ui.compactMode。
1. エグゼクティブサマリー
Qwen Code と Claude Code はどちらも Ctrl+O ショートカットでコンパクト表示と詳細表示を切り替えられるが、設計思想、デフォルト状態、インタラクションモデルは根本的に異なる。本書ではソースレベルの詳細な比較を行い、UX のギャップを特定し、Qwen Code の最適化を提案する。
| 次元 | Claude Code | Qwen Code |
|---|---|---|
| デフォルトモード | コンパクト (verbose=false) | 詳細 (compactMode=false) |
| 切り替えの意味論 | 一時的な詳細表示(ピーク) | 永続的な設定切り替え |
| 永続性 | セッション限定、再起動でリセット | settings.json に永続化 |
| スコープ | 画面全体の切り替え(prompt ↔ transcript) | コンポーネントごとのレンダリング切り替え |
| フローズンスナップショット | なし(概念なし) | なし(削除済み) |
| ツールごとの展開ヒント | あり (“ctrl+o to expand”) | あり (“Press Ctrl+O to show full tool output”) |
2. Claude Code 実装分析
2.1 アーキテクチャ
Claude Code は画面ベースのアプローチを採用しており、コンポーネントレベルのレンダリング切り替えではない:
┌──────────────────────────────────┐
│ AppState (Zustand) │
│ verbose: boolean (default: false)│
│ screen: 'prompt' | 'transcript' │
└──────────┬───────────────────────┘
│
┌─────┴──────┐
│ Ctrl+O │ スクリーンモードを切り替え
│ Handler │ レンダリングフラグではない
└─────┬──────┘
│
┌─────▼──────────────┐
│ REPL.tsx │
│ screen='prompt' → コンパクト表示(デフォルト)
│ screen='transcript'→ 詳細表示
└────────────────────┘2.2 主要ソースファイル
| コンポーネント | ファイル | 主要ロジック |
|---|---|---|
| トグルハンドラ | src/hooks/useGlobalKeybindings.tsx:90-132 | screen を 'prompt' と 'transcript' で切り替え |
| キーバインディング | src/keybindings/defaultBindings.ts:44 | app:toggleTranscript |
| 状態定義 | src/state/AppStateStore.ts:472 | verbose: false(セッション限定) |
| 展開ヒント | src/components/CtrlOToExpand.tsx:29-46 | ツールごとの “(ctrl+o to expand)” テキスト |
| メッセージフィルタ | src/components/Messages.tsx:93-151 | コンパクト表示用 filterForBriefTool() |
| 権限 | src/components/permissions/PermissionRequest.tsx | オーバーレイレイヤーでレンダリング、常に表示 |
2.3 設計上の判断
- コンパクトがデフォルト。 ユーザーは初期状態でクリーンなインターフェースを目にし、詳細はオプトインとなる。
- セッションスコープ。
verboseは新しいセッションごとにfalseにリセットされる。Claude Code はユーザーが基本的にコンパクト表示を好み、一時的にしか詳細を必要としないと想定している。 - 画面レベルの切り替え。 Ctrl+O はコンポーネントのレンダリング方法を変えるのではなく、画面全体を「プロンプト」(コンパクト)と「トランスクリプト」(詳細)の間で切り替える。
- フローズンスナップショットはなし。 スナップショットの固定概念はない。切り替えると、現在の状態で即座に表示が更新される。
- 権限ダイアログは分離。 ツール承認は専用のオーバーレイレイヤーにレンダリングされ、詳細/コンパクトの切り替えの影響を受けない。
- ツールごとのヒント。
CtrlOToExpandコンポーネントは、個々のツールが大きな出力を生成した場合にコンテキストヒントを表示する。サブエージェントでは非表示。
2.4 ユーザーフロー
セッション開始 → コンパクトモード(デフォルト)
│
├─ ツール出力は1行に要約
├─ 大きなツール出力には "(ctrl+o to expand)" ヒントを表示
│
├─ ユーザーが Ctrl+O を押下
│ └─→ 画面がトランスクリプト(詳細表示)に切り替わる
│ └─ すべてのツール出力、思考過程などを表示
│
├─ ユーザーが再度 Ctrl+O を押下
│ └─→ 画面がプロンプト(コンパクト表示)に戻る
│
└─ セッション終了 → verbose は false にリセット3. Qwen Code 実装分析
3.1 アーキテクチャ
Qwen Code はコンポーネントレベルのレンダリングフラグを使用し、各 UI コンポーネントがコンテキストからフラグを読み取る:
┌─────────────────────────────────────┐
│ CompactModeContext │
│ compactMode: boolean (default: false)│
│ setCompactMode: (v) => void │
└──────────┬──────────────────────────┘
│
┌─────┴──────┐
│ Ctrl+O │ compactMode を切り替え
│ Handler │ settings に永続化
└─────┬──────┘
│
┌─────▼──────────────────┐
│ 各コンポーネントが │
│ compactMode を読み取り │
│ レンダリング方法を決定│
└────────────────────────┘
│
┌─────▼──────────────────────────────┐
│ ToolGroupMessage │
│ showCompact = compactMode │
│ && !hasConfirmingTool │
│ && !hasErrorTool │
│ && !isEmbeddedShellFocused │
│ && !isUserInitiated │
└────────────────────────────────────┘3.2 主要ソースファイル
| コンポーネント | ファイル | 主要ロジック |
|---|---|---|
| トグルハンドラ | AppContainer.tsx:1684-1690 | compactMode を切り替え、settings に永続化 |
| コンテキスト | CompactModeContext.tsx | compactMode, setCompactMode |
| ツールグループ | ToolGroupMessage.tsx:105-110 | 4つの強制展開条件を持つ showCompact |
| ツールメッセージ | ToolMessage.tsx:346-350 | コンパクトモードで displayRenderer を非表示 |
| コンパクト表示 | CompactToolGroupDisplay.tsx:49-108 | ステータスとヒントを含む1行要約 |
| 確認 | ToolConfirmationMessage.tsx:113-147 | コンパクト時の3択簡略承認 |
| ヒント | Tips.tsx:14-29 | 起動時のヒントローテーションにコンパクトモードヒントを含む |
| 設定同期 | SettingsDialog.tsx:189-193 | CompactModeContext との同期 + refreshStatic |
| MainContent | MainContent.tsx:60-76 | ライブ pendingHistoryItems のレンダリング |
| 思考過程 | HistoryItemDisplay.tsx:123-133 | コンパクトモードで gemini_thought を非表示 |
3.3 設計上の判断
- 詳細がデフォルト。 ユーザーはデフォルトですべてのツール出力と思考過程を目にする。
- 永続的な設定。
compactModeはsettings.jsonに保存され、セッションをまたいで維持される。 - コンポーネントレベルのレンダリング。 各コンポーネントが
compactModeをコンテキストから読み取り、自身のレンダリングを調整する。 - 強制展開の保護。 4つの条件がコンパクトモードをオーバーライドし、重要な UI 要素(確認、エラー、シェル、ユーザー起因)を常に表示する。
- スナップショット固定なし。 切り替えは常にライブ出力を表示 — 固定スナップショットはなし。
- 設定ダイアログとの同期。 Settings からコンパクトモードを切り替えると、
setCompactModeを介して即座に React 状態が更新される。 - 発見可能性は控えめ。 コンパクトモードは、永続的なフッターインジケーターではなく、起動時の Tips ローテーションで紹介され、UI の乱雑さを避ける。
3.4 ユーザーフロー
セッション開始 → 詳細モード(デフォルト)
│
├─ すべてのツール出力、思考過程、詳細が表示される
│
├─ ユーザーが Ctrl+O を押下(または Settings で切り替え)
│ └─→ compactMode = true、永続化
│ ├─ ツールグループが1行要約で表示
│ ├─ 思考過程/思考内容は非表示
│ └─ 確認、エラー、シェルは展開されたまま
│
├─ ユーザーが再度 Ctrl+O を押下
│ └─→ compactMode = false、永続化
│ └─ すべての詳細が再表示
│
└─ 次回セッション → 前回と同じモード4. 主要な違いの詳細分析
4.1 デフォルトモードの哲学
| 側面 | Claude Code(コンパクトデフォルト) | Qwen Code(詳細デフォルト) |
|---|---|---|
| 第一印象 | クリーンでミニマル — プロフェッショナル感 | 情報豊富 — 完全な透明性 |
| 学習曲線 | ユーザーは詳細を見るために Ctrl+O を学ぶ必要あり | ユーザーはすぐにすべてを確認できる |
| ターゲットユーザー | ツールを信頼する経験豊富なユーザー | 何が起こっているかを理解したいユーザー |
| 情報過多 | デフォルトで回避 | 新規ユーザーには可能性あり |
| 発見可能性 | ツールごとの “(ctrl+o to expand)” ヒント | 起動時 Tips ローテーション + ? ショートカット + /help |
分析: Claude Code のコンパクトデフォルトは、ユーザーベースが一般的に経験豊富な開発者であり、ツールを信頼して毎回のツール呼び出しを確認する必要がないため機能している。Qwen Code の詳細デフォルトは、透明性を通じてユーザーの信頼を構築することが重要な現在の段階では適切である。
4.2 永続性モデル
| 側面 | Claude Code | Qwen Code |
|---|---|---|
| 永続化? | いいえ — セッション限定 | はい — settings.json に保存 |
| 根拠 | 詳細表示は一時的なピーク | モードはユーザーの好み |
| 再起動時 | 常にコンパクトで開始 | 最後に使用したモードで開始 |
分析: Claude Code は詳細表示を瞬間的なニーズとして扱う — 見て、戻る。Qwen Code は安定した設定として扱う — 常に詳細を望むユーザーもいれば、常にコンパクトを望むユーザーもいる。どちらも有効だが、Qwen Code のアプローチはより柔軟である。
4.3 確認保護
| 側面 | Claude Code | Qwen Code |
|---|---|---|
| メカニズム | オーバーレイ/モーダルレイヤー(構造的に分離) | showCompact 内の強制展開条件 |
| カバレッジ | 完全 — 承認が非表示になることは絶対にない | 完全 — 4条件で対話状態すべてをカバー |
| コンパクト確認 UI | なし(オーバーレイは常にフル表示) | 簡略化した3択 RadioButtonSelect |
分析: Claude Code のアーキテクチャ上の分離(オーバーレイレイヤー)はより堅牢である。Qwen Code の強制展開アプローチは有効だが、新しい対話状態を追加するたびに明示的に条件リストに追加する必要がある。
4.4 レンダリングアプローチ
| 側面 | Claude Code | Qwen Code |
|---|---|---|
| 切り替え範囲 | 画面レベル(prompt ↔ transcript) | コンポーネントレベル(各コンポーネントが判断) |
| 粒度 | オール・オア・ナッシング | コンポーネントごとの細かい制御 |
| 柔軟性 | 低 — グローバルスイッチ | 高 — コンポーネントがオーバーライド可能 |
| 一貫性 | 保証される | 各コンポーネントの実装に依存 |
分析: Qwen Code のコンポーネントレベルアプローチはより柔軟だが(特定条件での強制展開など)、一貫性を維持するにはより多くの規律が必要。Claude Code の画面レベルアプローチはよりシンプルで、動作の一貫性が保証される。
5. 最適化の提案
5.1 [P0] 詳細デフォルトを維持 — 変更不要
Qwen Code の詳細デフォルトは、現在の段階では正しい選択である。ツールに不慣れなユーザーは透明性を通じて信頼を構築する必要がある。プロダクトが成熟するにつれて、コンパクトデフォルト(Claude Code のように)への変更を検討すべきである。
5.2 [P1] 大きな出力に対するツールごとの展開
Claude Code では、大きな出力を生成した個々のツールに “(ctrl+o to expand)” と表示される。Qwen Code は現在グローバルな切り替えしかない。以下を検討:
- 単一のツール出力が N 行を超えた場合、コンパクトモードでツールごとに「展開」ヒントを表示する。
- スコープ: 将来の機能拡張、現時点では優先度低。
5.3 [P2] セッションスコープの一時オーバーライドの検討
コンパクトモードをデフォルトとしたいが、特定のセッションだけ詳細を必要とするユーザーもいる。両方のサポートを検討:
settings.json→ 永続的なデフォルト(現在の動作)- セッション中の Ctrl+O → 現在のセッションのみの一時オーバーライド(Claude Code の動作)
- セッション再起動時 → settings.json の値に戻す
これにより、ユーザーは両方の利点を得られる。実装には「設定のデフォルト」と「セッションのオーバーライド」の状態を分離する必要がある。
5.4 [P2] 確認画面の構造的分離
現在、確認保護は ToolGroupMessage の showCompact 条件に依存している。より堅牢なアプローチを検討:
- 確認画面を別レイヤーにレンダリングする(Claude Code のオーバーレイアプローチのように)。
- これにより、アーキテクチャ上、コンパクトモードが確認画面に影響を与えることが不可能になる。
- 現在の強制展開アプローチが正しく機能しているため、優先度は低い。
6. 現在の実装状況
feat/compact-mode-optimization ブランチの変更後:
| 機能 | 状態 | 備考 |
|---|---|---|
| 起動時 Tips ヒント | 完了 | Tips ローテーションにコンパクトモードヒント(控えめ) |
| キーボードショートカット (?) の Ctrl+O | 完了 | KeyboardShortcuts コンポーネントに追加 |
| /help の Ctrl+O | 完了 | Help コンポーネントに追加 |
| 設定ダイアログの同期 | 完了 | compactMode を CompactModeContext と同期 |
| スナップショット固定なし | 完了 | 切り替えは常にライブ出力を表示 |
| 確認保護 | 完了 | 強制展開 + WaitingForConfirmation ガード |
| シェル保護 | 完了 | !isEmbeddedShellFocused による強制展開 |
| エラー保護 | 完了 | !hasErrorTool による強制展開 |
| ユーザードキュメント更新 | 完了 | settings.md, keyboard-shortcuts.md |
7. ファイル参照
Qwen Code
| ファイル | 目的 |
|---|---|
packages/cli/src/ui/AppContainer.tsx | トグルハンドラ、状態初期化、コンテキストプロバイダ |
packages/cli/src/ui/contexts/CompactModeContext.tsx | コンテキスト定義 |
packages/cli/src/ui/components/messages/ToolGroupMessage.tsx | 強制展開ロジック |
packages/cli/src/ui/components/messages/ToolMessage.tsx | ツールごとの出力非表示 |
packages/cli/src/ui/components/messages/CompactToolGroupDisplay.tsx | コンパクト表示レンダリング |
packages/cli/src/ui/components/messages/ToolConfirmationMessage.tsx | コンパクト確認 UI |
packages/cli/src/ui/components/MainContent.tsx | 保留中の履歴アイテムのレンダリング |
packages/cli/src/ui/components/Tips.tsx | コンパクトモードヒントを含む起動時 Tips |
packages/cli/src/ui/components/Help.tsx | /help ショートカットエントリ |
packages/cli/src/ui/components/KeyboardShortcuts.tsx | ? ショートカットエントリ |
packages/cli/src/ui/components/SettingsDialog.tsx | 設定同期 |
packages/cli/src/ui/components/HistoryItemDisplay.tsx | 思考内容の非表示 |
packages/cli/src/config/settingsSchema.ts | 設定定義 |
packages/cli/src/config/keyBindings.ts | Ctrl+O バインディング |
Claude Code(参考)
| ファイル | 目的 |
|---|---|
src/hooks/useGlobalKeybindings.tsx | トグルハンドラ |
src/state/AppStateStore.ts | 状態定義 (verbose: false) |
src/components/CtrlOToExpand.tsx | ツールごとの展開ヒント |
src/components/Messages.tsx | 簡略メッセージフィルタ |
src/screens/REPL.tsx | 画面レベルのモード切り替え |
src/components/permissions/PermissionRequest.tsx | オーバーレイベースの確認 |