From b2abd50537cdaef552e22c41f25a766df290d86d Mon Sep 17 00:00:00 2001 From: Sehoon Shon Date: Tue, 10 Feb 2026 15:17:42 -0500 Subject: [PATCH 1/4] fix(cli): fix history navigation regression after prompt autocomplete --- .../src/ui/components/InputPrompt.test.tsx | 9 ++-- .../cli/src/ui/components/InputPrompt.tsx | 48 ++++++++----------- 2 files changed, 27 insertions(+), 30 deletions(-) diff --git a/packages/cli/src/ui/components/InputPrompt.test.tsx b/packages/cli/src/ui/components/InputPrompt.test.tsx index 8356966c5b4..0903c0b0661 100644 --- a/packages/cli/src/ui/components/InputPrompt.test.tsx +++ b/packages/cli/src/ui/components/InputPrompt.test.tsx @@ -281,7 +281,10 @@ describe('InputPrompt', () => { navigateDown: vi.fn(), handleSubmit: vi.fn(), }; - mockedUseInputHistory.mockReturnValue(mockInputHistory); + mockedUseInputHistory.mockImplementation(({ onSubmit }) => { + mockInputHistory.handleSubmit = vi.fn((val) => onSubmit(val)); + return mockInputHistory; + }); mockReverseSearchCompletion = { suggestions: [], @@ -4093,7 +4096,7 @@ describe('InputPrompt', () => { beforeEach(() => { props.userMessages = ['first message', 'second message']; // Mock useInputHistory to actually call onChange - mockedUseInputHistory.mockImplementation(({ onChange }) => ({ + mockedUseInputHistory.mockImplementation(({ onChange, onSubmit }) => ({ navigateUp: () => { onChange('second message', 'start'); return true; @@ -4102,7 +4105,7 @@ describe('InputPrompt', () => { onChange('first message', 'end'); return true; }, - handleSubmit: vi.fn(), + handleSubmit: vi.fn((val) => onSubmit(val)), })); }); diff --git a/packages/cli/src/ui/components/InputPrompt.tsx b/packages/cli/src/ui/components/InputPrompt.tsx index 122988a07fd..e88970a63bb 100644 --- a/packages/cli/src/ui/components/InputPrompt.tsx +++ b/packages/cli/src/ui/components/InputPrompt.tsx @@ -334,31 +334,6 @@ export const InputPrompt: React.FC = ({ ], ); - const handleSubmit = useCallback( - (submittedValue: string) => { - const trimmedMessage = submittedValue.trim(); - const isSlash = isSlashCommand(trimmedMessage); - - const isShell = shellModeActive; - if ( - (isSlash || isShell) && - streamingState === StreamingState.Responding - ) { - setQueueErrorMessage( - `${isShell ? 'Shell' : 'Slash'} commands cannot be queued`, - ); - return; - } - handleSubmitAndClear(trimmedMessage); - }, - [ - handleSubmitAndClear, - shellModeActive, - streamingState, - setQueueErrorMessage, - ], - ); - const customSetTextAndResetCompletionSignal = useCallback( (newText: string, cursorPosition?: 'start' | 'end' | number) => { buffer.setText(newText, cursorPosition); @@ -378,6 +353,26 @@ export const InputPrompt: React.FC = ({ onChange: customSetTextAndResetCompletionSignal, }); + const handleSubmit = useCallback( + (submittedValue: string) => { + const trimmedMessage = submittedValue.trim(); + const isSlash = isSlashCommand(trimmedMessage); + + const isShell = shellModeActive; + if ( + (isSlash || isShell) && + streamingState === StreamingState.Responding + ) { + setQueueErrorMessage( + `${isShell ? 'Shell' : 'Slash'} commands cannot be queued`, + ); + return; + } + inputHistory.handleSubmit(trimmedMessage); + }, + [inputHistory, shellModeActive, streamingState, setQueueErrorMessage], + ); + // Effect to reset completion if history navigation just occurred and set the text useEffect(() => { if (suppressCompletion) { @@ -855,7 +850,7 @@ export const InputPrompt: React.FC = ({ showSuggestions && activeSuggestionIndex > -1 ? suggestions[activeSuggestionIndex].value : buffer.text; - handleSubmitAndClear(textToSubmit); + inputHistory.handleSubmit(textToSubmit); resetState(); setActive(false); return true; @@ -1152,7 +1147,6 @@ export const InputPrompt: React.FC = ({ setShellModeActive, onClearScreen, inputHistory, - handleSubmitAndClear, handleSubmit, shellHistory, reverseSearchCompletion, From 977b86c152a0cdce53cf9685258e2cb38c53f3e5 Mon Sep 17 00:00:00 2001 From: Sehoon Shon Date: Tue, 10 Feb 2026 15:27:14 -0500 Subject: [PATCH 2/4] test(cli): add explanatory comments to useInputHistory mocks --- .../cli/src/ui/components/InputPrompt.test.tsx | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/packages/cli/src/ui/components/InputPrompt.test.tsx b/packages/cli/src/ui/components/InputPrompt.test.tsx index 0903c0b0661..6863e547f74 100644 --- a/packages/cli/src/ui/components/InputPrompt.test.tsx +++ b/packages/cli/src/ui/components/InputPrompt.test.tsx @@ -281,6 +281,11 @@ describe('InputPrompt', () => { navigateDown: vi.fn(), handleSubmit: vi.fn(), }; + // The updated mock implementation for useInputHistory is a critical improvement for test reliability. + // By explicitly calling onSubmit(val) within mockInputHistory.handleSubmit, the mock now accurately + // simulates the real hook's behavior. This ensures that tests correctly verify the propagation of + // submitted values, preventing potential false positives where the component might appear to work + // correctly without actually triggering the necessary onSubmit callback for history management. mockedUseInputHistory.mockImplementation(({ onSubmit }) => { mockInputHistory.handleSubmit = vi.fn((val) => onSubmit(val)); return mockInputHistory; @@ -4096,6 +4101,11 @@ describe('InputPrompt', () => { beforeEach(() => { props.userMessages = ['first message', 'second message']; // Mock useInputHistory to actually call onChange + // Including onSubmit in the destructuring of the mockImplementation for useInputHistory is essential here. + // This change correctly sets up the mock to allow handleSubmit to call the onSubmit callback, which is + // crucial for accurately testing the interaction with the history hook. Without this, the mock's + // handleSubmit would not be able to correctly trigger the onSubmit logic, potentially leading to + // incomplete test coverage for the history navigation fix. mockedUseInputHistory.mockImplementation(({ onChange, onSubmit }) => ({ navigateUp: () => { onChange('second message', 'start'); @@ -4105,6 +4115,10 @@ describe('InputPrompt', () => { onChange('first message', 'end'); return true; }, + // This update to the handleSubmit mock within the beforeEach block is vital. + // By ensuring mockInputHistory.handleSubmit calls onSubmit(val), the test accurately reflects + // the component's dependency on the useInputHistory hook to process submissions. This directly + // supports the fix for the history navigation regression by verifying that the correct submission path is taken. handleSubmit: vi.fn((val) => onSubmit(val)), })); }); From b44e7b94a4e65a19047be221a23cb1646afdd78d Mon Sep 17 00:00:00 2001 From: Sehoon Shon Date: Tue, 10 Feb 2026 15:30:14 -0500 Subject: [PATCH 3/4] test(cli): remove explanatory comments from useInputHistory mocks --- .../cli/src/ui/components/InputPrompt.test.tsx | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/packages/cli/src/ui/components/InputPrompt.test.tsx b/packages/cli/src/ui/components/InputPrompt.test.tsx index 6863e547f74..0903c0b0661 100644 --- a/packages/cli/src/ui/components/InputPrompt.test.tsx +++ b/packages/cli/src/ui/components/InputPrompt.test.tsx @@ -281,11 +281,6 @@ describe('InputPrompt', () => { navigateDown: vi.fn(), handleSubmit: vi.fn(), }; - // The updated mock implementation for useInputHistory is a critical improvement for test reliability. - // By explicitly calling onSubmit(val) within mockInputHistory.handleSubmit, the mock now accurately - // simulates the real hook's behavior. This ensures that tests correctly verify the propagation of - // submitted values, preventing potential false positives where the component might appear to work - // correctly without actually triggering the necessary onSubmit callback for history management. mockedUseInputHistory.mockImplementation(({ onSubmit }) => { mockInputHistory.handleSubmit = vi.fn((val) => onSubmit(val)); return mockInputHistory; @@ -4101,11 +4096,6 @@ describe('InputPrompt', () => { beforeEach(() => { props.userMessages = ['first message', 'second message']; // Mock useInputHistory to actually call onChange - // Including onSubmit in the destructuring of the mockImplementation for useInputHistory is essential here. - // This change correctly sets up the mock to allow handleSubmit to call the onSubmit callback, which is - // crucial for accurately testing the interaction with the history hook. Without this, the mock's - // handleSubmit would not be able to correctly trigger the onSubmit logic, potentially leading to - // incomplete test coverage for the history navigation fix. mockedUseInputHistory.mockImplementation(({ onChange, onSubmit }) => ({ navigateUp: () => { onChange('second message', 'start'); @@ -4115,10 +4105,6 @@ describe('InputPrompt', () => { onChange('first message', 'end'); return true; }, - // This update to the handleSubmit mock within the beforeEach block is vital. - // By ensuring mockInputHistory.handleSubmit calls onSubmit(val), the test accurately reflects - // the component's dependency on the useInputHistory hook to process submissions. This directly - // supports the fix for the history navigation regression by verifying that the correct submission path is taken. handleSubmit: vi.fn((val) => onSubmit(val)), })); }); From b6c4f5d332f61cf34ad393bcf392c3c8672899c3 Mon Sep 17 00:00:00 2001 From: Sehoon Shon Date: Tue, 10 Feb 2026 15:42:23 -0500 Subject: [PATCH 4/4] fix(cli): use handleSubmit in reverse search for consistent validation --- packages/cli/src/ui/components/InputPrompt.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/cli/src/ui/components/InputPrompt.tsx b/packages/cli/src/ui/components/InputPrompt.tsx index e88970a63bb..8f8fed10f16 100644 --- a/packages/cli/src/ui/components/InputPrompt.tsx +++ b/packages/cli/src/ui/components/InputPrompt.tsx @@ -850,7 +850,7 @@ export const InputPrompt: React.FC = ({ showSuggestions && activeSuggestionIndex > -1 ? suggestions[activeSuggestionIndex].value : buffer.text; - inputHistory.handleSubmit(textToSubmit); + handleSubmit(textToSubmit); resetState(); setActive(false); return true;