diff --git a/packages/cli/src/ui/components/Composer.test.tsx b/packages/cli/src/ui/components/Composer.test.tsx
index af53d39c50..b12f4b62bf 100644
--- a/packages/cli/src/ui/components/Composer.test.tsx
+++ b/packages/cli/src/ui/components/Composer.test.tsx
@@ -89,10 +89,6 @@ vi.mock('./ShellModeIndicator.js', () => ({
ShellModeIndicator: () => ShellModeIndicator,
}));
-vi.mock('./ShortcutsHint.js', () => ({
- ShortcutsHint: () => ShortcutsHint,
-}));
-
vi.mock('./ShortcutsHelp.js', () => ({
ShortcutsHelp: () => ShortcutsHelp,
}));
@@ -847,7 +843,9 @@ describe('Composer', () => {
await vi.advanceTimersByTimeAsync(250);
});
- expect(lastFrame({ allowEmpty: true })).toContain('ShortcutsHint');
+ expect(lastFrame({ allowEmpty: true })).toContain(
+ 'press tab twice for more',
+ );
});
it('hides shortcuts hint when text is typed in buffer', async () => {
@@ -901,7 +899,7 @@ describe('Composer', () => {
await vi.advanceTimersByTimeAsync(250);
});
- expect(lastFrame()).toContain('ShortcutsHint');
+ expect(lastFrame()).toContain('press tab twice for more');
});
it('shows shortcuts hint when full UI details are visible', async () => {
@@ -916,7 +914,7 @@ describe('Composer', () => {
});
// In Refreshed UX, shortcuts hint is in the top multipurpose status row
- expect(lastFrame()).toContain('ShortcutsHint');
+ expect(lastFrame()).toContain('? for shortcuts');
});
it('hides shortcuts hint while loading when full UI details are visible', async () => {
@@ -1009,7 +1007,7 @@ describe('Composer', () => {
});
// In Refreshed UX, shortcuts hint is in the top status row and doesn't collide with suggestions below
- expect(lastFrame()).toContain('ShortcutsHint');
+ expect(lastFrame()).toContain('press tab twice for more');
});
});
diff --git a/packages/cli/src/ui/components/Composer.tsx b/packages/cli/src/ui/components/Composer.tsx
index 2e25c94575..ba537ee970 100644
--- a/packages/cli/src/ui/components/Composer.tsx
+++ b/packages/cli/src/ui/components/Composer.tsx
@@ -31,7 +31,6 @@ import { ApprovalModeIndicator } from './ApprovalModeIndicator.js';
import { ShellModeIndicator } from './ShellModeIndicator.js';
import { DetailedMessagesDisplay } from './DetailedMessagesDisplay.js';
import { RawMarkdownIndicator } from './RawMarkdownIndicator.js';
-import { ShortcutsHint } from './ShortcutsHint.js';
import { ShortcutsHelp } from './ShortcutsHelp.js';
import { InputPrompt } from './InputPrompt.js';
import { Footer } from './Footer.js';
@@ -112,27 +111,6 @@ export const Composer = ({ isFocused = true }: { isFocused?: boolean }) => {
uiState.streamingState === StreamingState.Idle &&
!hasPendingActionRequired;
- const [showShortcutsHintDebounced, setShowShortcutsHintDebounced] =
- useState(false);
- const canShowShortcutsHint =
- uiState.isInputActive &&
- uiState.streamingState === StreamingState.Idle &&
- !hasPendingActionRequired &&
- uiState.buffer.text.length === 0;
-
- useEffect(() => {
- if (!canShowShortcutsHint) {
- setShowShortcutsHintDebounced(false);
- return;
- }
-
- const timeout = setTimeout(() => {
- setShowShortcutsHintDebounced(true);
- }, 200);
-
- return () => clearTimeout(timeout);
- }, [canShowShortcutsHint]);
-
/**
* Use the setting if provided, otherwise default to true for the new UX.
* This allows tests to override the collapse behavior.
@@ -194,9 +172,6 @@ export const Composer = ({ isFocused = true }: { isFocused?: boolean }) => {
const shouldReserveSpaceForShortcutsHint =
settings.merged.ui.showShortcutsHint && !hideUiDetailsForSuggestions;
- const showShortcutsHint =
- shouldReserveSpaceForShortcutsHint && showShortcutsHintDebounced;
-
const showMinimalContextBleedThrough =
!settings.merged.ui.footer.hideContextPercentage &&
isContextUsageHigh(
@@ -239,7 +214,7 @@ export const Composer = ({ isFocused = true }: { isFocused?: boolean }) => {
* Determine the ambient text (tip) to display.
*/
const ambientContentStr = (() => {
- // Only show Tips on the right
+ // 1. Proactive Tip (Priority)
if (showTips && uiState.currentTip) {
if (
estimatedStatusLength + uiState.currentTip.length + 10 <=
@@ -249,6 +224,15 @@ export const Composer = ({ isFocused = true }: { isFocused?: boolean }) => {
}
}
+ // 2. Shortcut Hint (Fallback)
+ if (
+ settings.merged.ui.showShortcutsHint &&
+ !hideUiDetailsForSuggestions &&
+ !hasPendingActionRequired
+ ) {
+ return showUiDetails ? '? for shortcuts' : 'press tab twice for more';
+ }
+
return undefined;
})();
@@ -257,9 +241,7 @@ export const Composer = ({ isFocused = true }: { isFocused?: boolean }) => {
estimatedStatusLength + estimatedAmbientLength + 5 > terminalWidth;
const showAmbientLine =
- uiState.streamingState !== StreamingState.Idle &&
!hasPendingActionRequired &&
- (showTips || showWit) &&
ambientContentStr &&
!willCollideAmbient &&
!isNarrow;
@@ -296,17 +278,22 @@ export const Composer = ({ isFocused = true }: { isFocused?: boolean }) => {
const renderAmbientNode = () => {
if (!ambientContentStr) return null;
+ const isShortcutHint =
+ ambientContentStr === '? for shortcuts' ||
+ ambientContentStr === 'press tab twice for more';
+ const color =
+ isShortcutHint && uiState.shortcutsHelpVisible
+ ? theme.text.accent
+ : theme.text.secondary;
+
return (
-
+
{ambientContentStr === uiState.currentTip
? `Tip: ${ambientContentStr}`
@@ -352,7 +339,6 @@ export const Composer = ({ isFocused = true }: { isFocused?: boolean }) => {
thought={uiState.thought}
elapsedTime={uiState.elapsedTime}
forceRealStatusOnly={false}
- showCancelAndTimer={false}
wittyPhrase={uiState.currentWittyPhrase}
/>
);
@@ -374,7 +360,6 @@ export const Composer = ({ isFocused = true }: { isFocused?: boolean }) => {
errorVerbosity={settings.merged.ui.errorVerbosity}
elapsedTime={uiState.elapsedTime}
forceRealStatusOnly={true}
- showCancelAndTimer={false}
/>
)}
{hasUserHooks && (
@@ -450,12 +435,7 @@ export const Composer = ({ isFocused = true }: { isFocused?: boolean }) => {
- {!isNarrow && (
- <>
- {showShortcutsHint && }
- {!showShortcutsHint && showAmbientLine && renderAmbientNode()}
- >
- )}
+ {!isNarrow && showAmbientLine && renderAmbientNode()}
)}
@@ -464,7 +444,7 @@ export const Composer = ({ isFocused = true }: { isFocused?: boolean }) => {
{showRow1 &&
showRow2 &&
(showUiDetails || (showRow1_MiniMode && showRow2_MiniMode)) && (
-
+
{
- const { cleanUiDetailsVisible, shortcutsHelpVisible } = useUIState();
-
- if (!cleanUiDetailsVisible) {
- return press tab twice for more ;
- }
-
- const highlightColor = shortcutsHelpVisible
- ? theme.text.accent
- : theme.text.secondary;
-
- return ? for shortcuts;
-};
diff --git a/packages/cli/src/ui/components/__snapshots__/Composer.test.tsx.snap b/packages/cli/src/ui/components/__snapshots__/Composer.test.tsx.snap
index fa12e847ae..745347bc95 100644
--- a/packages/cli/src/ui/components/__snapshots__/Composer.test.tsx.snap
+++ b/packages/cli/src/ui/components/__snapshots__/Composer.test.tsx.snap
@@ -2,8 +2,8 @@
exports[`Composer > Snapshots > matches snapshot in idle state 1`] = `
"
-
- ───────────────────────────────────────────────────────────────────────────────────────────────────
+ ? for shortcuts
+────────────────────────────────────────────────────────────────────────────────────────────────────
ApprovalModeIndicator: default StatusDisplay
InputPrompt: Type your message or @path/to/file
Footer
@@ -11,21 +11,21 @@ Footer
`;
exports[`Composer > Snapshots > matches snapshot in minimal UI mode 1`] = `
-"
+" press tab twice for more
InputPrompt: Type your message or @path/to/file
"
`;
exports[`Composer > Snapshots > matches snapshot in minimal UI mode while loading 1`] = `
-"LoadingIndicator
+"LoadingIndicator press tab twice for more
InputPrompt: Type your message or @path/to/file
"
`;
exports[`Composer > Snapshots > matches snapshot in narrow view 1`] = `
"
-
- ────────────────────────────────────────
+ ? for shortcuts
+────────────────────────────────────────
ApprovalModeIndicator: StatusDispl
default ay
InputPrompt: Type your message or
@@ -36,8 +36,8 @@ Footer
exports[`Composer > Snapshots > matches snapshot while streaming 1`] = `
"
- LoadingIndicator: Thinking
- ───────────────────────────────────────────────────────────────────────────────────────────────────
+ LoadingIndicator: Thinking ? for shortcuts
+────────────────────────────────────────────────────────────────────────────────────────────────────
ApprovalModeIndicator: default StatusDisplay
InputPrompt: Type your message or @path/to/file
Footer