Skip to content

Commit 435f711

Browse files
authored
feat(cli): warn users that rewind is disabled in IDE mode (#4122)
1 parent df32345 commit 435f711

2 files changed

Lines changed: 94 additions & 3 deletions

File tree

packages/cli/src/ui/AppContainer.test.tsx

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3077,6 +3077,85 @@ describe('AppContainer State Management', () => {
30773077
expect(trigger.activeCount()).toBe(0);
30783078
});
30793079
});
3080+
3081+
describe('IDE mode rewind guard', () => {
3082+
it('shows info message instead of opening rewind selector when IDE mode is enabled', () => {
3083+
const mockAddItem = vi.fn();
3084+
mockedUseHistory.mockReturnValue({
3085+
history: [{ id: 1, type: 'user', text: 'hello' }],
3086+
addItem: mockAddItem,
3087+
updateItem: vi.fn(),
3088+
clearItems: vi.fn(),
3089+
loadHistory: vi.fn(),
3090+
truncateToItem: vi.fn(),
3091+
});
3092+
mockedUseGeminiStream.mockReturnValue({
3093+
streamingState: 'idle',
3094+
submitQuery: vi.fn(),
3095+
initError: null,
3096+
pendingHistoryItems: [],
3097+
thought: null,
3098+
cancelOngoingRequest: vi.fn(),
3099+
retryLastPrompt: vi.fn(),
3100+
});
3101+
vi.spyOn(mockConfig, 'getIdeMode').mockReturnValue(true);
3102+
3103+
render(
3104+
<AppContainer
3105+
config={mockConfig}
3106+
settings={mockSettings}
3107+
version="1.0.0"
3108+
initializationResult={mockInitResult}
3109+
/>,
3110+
);
3111+
3112+
capturedUIActions.openRewindSelector();
3113+
3114+
expect(mockAddItem).toHaveBeenCalledWith(
3115+
expect.objectContaining({
3116+
type: 'info',
3117+
text: expect.stringMatching(/rewind.*disabled.*IDE/i),
3118+
}),
3119+
expect.any(Number),
3120+
);
3121+
expect(capturedUIState.isRewindSelectorOpen).toBeFalsy();
3122+
});
3123+
3124+
it('opens rewind selector normally when IDE mode is disabled', () => {
3125+
const mockAddItemDisabled = vi.fn();
3126+
mockedUseHistory.mockReturnValue({
3127+
history: [{ id: 1, type: 'user', text: 'hello' }],
3128+
addItem: mockAddItemDisabled,
3129+
updateItem: vi.fn(),
3130+
clearItems: vi.fn(),
3131+
loadHistory: vi.fn(),
3132+
truncateToItem: vi.fn(),
3133+
});
3134+
mockedUseGeminiStream.mockReturnValue({
3135+
streamingState: 'idle',
3136+
submitQuery: vi.fn(),
3137+
initError: null,
3138+
pendingHistoryItems: [],
3139+
thought: null,
3140+
cancelOngoingRequest: vi.fn(),
3141+
retryLastPrompt: vi.fn(),
3142+
});
3143+
vi.spyOn(mockConfig, 'getIdeMode').mockReturnValue(false);
3144+
3145+
render(
3146+
<AppContainer
3147+
config={mockConfig}
3148+
settings={mockSettings}
3149+
version="1.0.0"
3150+
initializationResult={mockInitResult}
3151+
/>,
3152+
);
3153+
3154+
capturedUIActions.openRewindSelector();
3155+
3156+
expect(mockAddItemDisabled).not.toHaveBeenCalled();
3157+
});
3158+
});
30803159
});
30813160

30823161
describe('dedupeNewestFirst', () => {

packages/cli/src/ui/AppContainer.tsx

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2160,14 +2160,25 @@ export const AppContainer = (props: AppContainerProps) => {
21602160
}, []);
21612161

21622162
// --- Rewind selector callbacks ---
2163+
// IDE guard here is NOT redundant with the keyboard handler guard (line ~2375):
2164+
// /rewind calls openRewindSelector directly, bypassing the keyboard handler.
21632165
const openRewindSelector = useCallback(() => {
21642166
if (streamingState !== StreamingState.Idle) return;
2165-
if (config.getIdeMode()) return;
21662167
if (dialogsVisibleRef.current) return;
2168+
if (config.getIdeMode()) {
2169+
historyManager.addItem(
2170+
{
2171+
type: 'info',
2172+
text: 'Rewind is disabled in IDE mode.',
2173+
},
2174+
Date.now(),
2175+
);
2176+
return;
2177+
}
21672178
const hasUserTurns = historyManager.history.some((h) => h.type === 'user');
21682179
if (!hasUserTurns) return;
21692180
setIsRewindSelectorOpen(true);
2170-
}, [streamingState, config, historyManager.history]);
2181+
}, [streamingState, config, historyManager]);
21712182
openRewindSelectorRef.current = openRewindSelector;
21722183

21732184
const closeRewindSelector = useCallback(() => {
@@ -2559,7 +2570,8 @@ export const AppContainer = (props: AppContainerProps) => {
25592570
// Input is empty and idle — double-ESC opens rewind selector
25602571
if (
25612572
streamingState === StreamingState.Idle &&
2562-
!dialogsVisibleRef.current
2573+
!dialogsVisibleRef.current &&
2574+
!config.getIdeMode()
25632575
) {
25642576
if (escapeTimerRef.current) {
25652577
clearTimeout(escapeTimerRef.current);

0 commit comments

Comments
 (0)