From ad6e924b73d6cb5eee407695c8003a431fdffd77 Mon Sep 17 00:00:00 2001 From: Keith Guerin Date: Sun, 1 Mar 2026 23:39:57 -0800 Subject: [PATCH] feat(cli): full drawer collapse during tool approval and compact context summary --- docs/cli/settings.md | 2 +- docs/reference/configuration.md | 5 ++-- packages/cli/src/config/settingsSchema.ts | 6 ++--- packages/cli/src/test-utils/AppRig.tsx | 3 +++ .../cli/src/ui/components/Composer.test.tsx | 20 ++++++-------- packages/cli/src/ui/components/Composer.tsx | 10 +++++-- .../components/ContextSummaryDisplay.test.tsx | 26 ------------------- .../ui/components/ContextSummaryDisplay.tsx | 25 +++++------------- .../ContextSummaryDisplay.test.tsx.snap | 9 +++---- schemas/settings.schema.json | 8 +++--- 10 files changed, 40 insertions(+), 74 deletions(-) diff --git a/docs/cli/settings.md b/docs/cli/settings.md index 8a5c888db6..2cd0c5aa3a 100644 --- a/docs/cli/settings.md +++ b/docs/cli/settings.md @@ -62,7 +62,7 @@ they appear in the UI. | Hide Model Info | `ui.footer.hideModelInfo` | Hide the model name and context usage in the footer. | `false` | | Hide Context Window Percentage | `ui.footer.hideContextPercentage` | Hides the context window remaining percentage. | `true` | | Hide Footer | `ui.hideFooter` | Hide the footer from the UI | `false` | -| Hide Footer During Approval | `ui.hideFooterDuringApproval` | Hide the footer when a tool approval request is displayed. | `true` | +| Collapse Drawer During Approval | `ui.collapseDrawerDuringApproval` | Collapse the entire drawer (status, context, input, footer) when a tool approval request is displayed. | `true` | | New Footer Layout | `ui.newFooterLayout` | Use the new 2-row layout with inline tips. | `"legacy"` | | Show Tips | `ui.showTips` | Show informative tips on the right side of the status line. | `true` | | Show Witty Phrases | `ui.showWit` | Show witty phrases while waiting. | `true` | diff --git a/docs/reference/configuration.md b/docs/reference/configuration.md index c523e1dbda..19bd7da0d0 100644 --- a/docs/reference/configuration.md +++ b/docs/reference/configuration.md @@ -275,8 +275,9 @@ their corresponding top-level category object in your `settings.json` file. - **Description:** Hide the footer from the UI - **Default:** `false` -- **`ui.hideFooterDuringApproval`** (boolean): - - **Description:** Hide the footer when a tool approval request is displayed. +- **`ui.collapseDrawerDuringApproval`** (boolean): + - **Description:** Collapse the entire drawer (status, context, input, footer) + when a tool approval request is displayed. - **Default:** `true` - **`ui.newFooterLayout`** (enum): diff --git a/packages/cli/src/config/settingsSchema.ts b/packages/cli/src/config/settingsSchema.ts index 98387a561e..989da8d9b1 100644 --- a/packages/cli/src/config/settingsSchema.ts +++ b/packages/cli/src/config/settingsSchema.ts @@ -619,14 +619,14 @@ const SETTINGS_SCHEMA = { description: 'Hide the footer from the UI', showInDialog: true, }, - hideFooterDuringApproval: { + collapseDrawerDuringApproval: { type: 'boolean', - label: 'Hide Footer During Approval', + label: 'Collapse Drawer During Approval', category: 'UI', requiresRestart: false, default: true, description: - 'Hide the footer when a tool approval request is displayed.', + 'Collapse the entire drawer (status, context, input, footer) when a tool approval request is displayed.', showInDialog: true, }, newFooterLayout: { diff --git a/packages/cli/src/test-utils/AppRig.tsx b/packages/cli/src/test-utils/AppRig.tsx index 3ff65c4067..55df39e1c7 100644 --- a/packages/cli/src/test-utils/AppRig.tsx +++ b/packages/cli/src/test-utils/AppRig.tsx @@ -264,6 +264,9 @@ export class AppRig { enabled: false, hasSeenNudge: true, }, + ui: { + collapseDrawerDuringApproval: false, + }, }, }); } diff --git a/packages/cli/src/ui/components/Composer.test.tsx b/packages/cli/src/ui/components/Composer.test.tsx index ced4d3497f..21701191e7 100644 --- a/packages/cli/src/ui/components/Composer.test.tsx +++ b/packages/cli/src/ui/components/Composer.test.tsx @@ -457,9 +457,8 @@ describe('Composer', () => { const { lastFrame } = await renderComposer(uiState); - const output = lastFrame(); - expect(output).not.toContain('LoadingIndicator'); - expect(output).not.toContain('esc to cancel'); + const output = lastFrame({ allowEmpty: true }); + expect(output).toBe(''); }); it('renders LoadingIndicator when embedded shell is focused but background shell is visible', async () => { @@ -712,9 +711,7 @@ describe('Composer', () => { }); const { lastFrame } = await renderComposer(uiState); - const output = lastFrame(); - expect(output).not.toContain('plan'); - expect(output).not.toContain('ShortcutsHint'); + expect(lastFrame({ allowEmpty: true })).toBe(''); }); it('shows Esc rewind prompt in minimal mode without showing full UI', async () => { @@ -867,9 +864,10 @@ describe('Composer', () => { ), }); - const { lastFrame } = await renderComposer(uiState); + const { lastFrame, unmount } = await renderComposer(uiState); - expect(lastFrame()).not.toContain('ShortcutsHint'); + expect(lastFrame({ allowEmpty: true })).toBe(''); + unmount(); }); it('keeps shortcuts hint visible when no action is required', async () => { @@ -1003,24 +1001,22 @@ describe('Composer', () => { expect(lastFrame()).not.toContain('ShortcutsHelp'); unmount(); }); - it('hides shortcuts help when action is required', async () => { const uiState = createMockUIState({ shortcutsHelpVisible: true, customDialog: ( - Dialog content + Test Dialog ), }); const { lastFrame, unmount } = await renderComposer(uiState); - expect(lastFrame()).not.toContain('ShortcutsHelp'); + expect(lastFrame({ allowEmpty: true })).toBe(''); unmount(); }); }); - describe('Snapshots', () => { it('matches snapshot in idle state', async () => { const uiState = createMockUIState(); diff --git a/packages/cli/src/ui/components/Composer.tsx b/packages/cli/src/ui/components/Composer.tsx index b46e994cf9..91c4d808db 100644 --- a/packages/cli/src/ui/components/Composer.tsx +++ b/packages/cli/src/ui/components/Composer.tsx @@ -91,6 +91,7 @@ export const Composer = ({ isFocused = true }: { isFocused?: boolean }) => { Boolean(uiState.quota.proQuotaRequest) || Boolean(uiState.quota.validationRequest) || Boolean(uiState.customDialog); + const isPassiveShortcutsHelpState = uiState.isInputActive && uiState.streamingState === StreamingState.Idle && @@ -180,6 +181,13 @@ export const Composer = ({ isFocused = true }: { isFocused?: boolean }) => { return () => clearTimeout(timeout); }, [canShowShortcutsHint]); + if ( + hasPendingActionRequired && + settings.merged.ui.collapseDrawerDuringApproval + ) { + return null; + } + const showShortcutsHint = settings.merged.ui.showShortcutsHint && !hideShortcutsHintForSuggestions && @@ -751,8 +759,6 @@ export const Composer = ({ isFocused = true }: { isFocused?: boolean }) => { {showUiDetails && !settings.merged.ui.hideFooter && - (!hasPendingActionRequired || - !settings.merged.ui.hideFooterDuringApproval) && !isScreenReaderEnabled &&