From b2d148d771587dfe909c71d3c23829b5588208d5 Mon Sep 17 00:00:00 2001 From: qqqys Date: Wed, 26 Aug 2026 00:55:01 +0800 Subject: [PATCH] refactor(cli): remove unused useInputHistoryStore hook --- eslint.legacy-filenames.mjs | 1 - .../src/ui/hooks/useInputHistoryStore.test.ts | 293 ------------------ .../cli/src/ui/hooks/useInputHistoryStore.ts | 118 ------- 3 files changed, 412 deletions(-) delete mode 100644 packages/cli/src/ui/hooks/useInputHistoryStore.test.ts delete mode 100644 packages/cli/src/ui/hooks/useInputHistoryStore.ts diff --git a/eslint.legacy-filenames.mjs b/eslint.legacy-filenames.mjs index a2839e04beb..a53dc3c5f92 100644 --- a/eslint.legacy-filenames.mjs +++ b/eslint.legacy-filenames.mjs @@ -448,7 +448,6 @@ export const legacyFilenames = [ 'useIdeTrustListener', 'useInitializationAuthError', 'useInputHistory', - 'useInputHistoryStore', 'useKeypress', 'useKittyKeyboardProtocol', 'useLaunchEditor', diff --git a/packages/cli/src/ui/hooks/useInputHistoryStore.test.ts b/packages/cli/src/ui/hooks/useInputHistoryStore.test.ts deleted file mode 100644 index 49ccef42bc8..00000000000 --- a/packages/cli/src/ui/hooks/useInputHistoryStore.test.ts +++ /dev/null @@ -1,293 +0,0 @@ -/** - * @license - * Copyright 2025 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -import { act, renderHook } from '@testing-library/react'; -import { vi, describe, it, expect, beforeEach } from 'vitest'; -import { useInputHistoryStore } from './useInputHistoryStore.js'; - -describe('useInputHistoryStore', () => { - beforeEach(() => { - vi.clearAllMocks(); - }); - - it('should initialize with empty input history', () => { - const { result } = renderHook(() => useInputHistoryStore()); - - expect(result.current.inputHistory).toEqual([]); - }); - - it('should add input to history', () => { - const { result } = renderHook(() => useInputHistoryStore()); - - act(() => { - result.current.addInput('test message 1'); - }); - - expect(result.current.inputHistory).toEqual(['test message 1']); - - act(() => { - result.current.addInput('test message 2'); - }); - - expect(result.current.inputHistory).toEqual([ - 'test message 1', - 'test message 2', - ]); - }); - - it('should not add empty or whitespace-only inputs', () => { - const { result } = renderHook(() => useInputHistoryStore()); - - act(() => { - result.current.addInput(''); - }); - - expect(result.current.inputHistory).toEqual([]); - - act(() => { - result.current.addInput(' '); - }); - - expect(result.current.inputHistory).toEqual([]); - }); - - it('should deduplicate consecutive identical messages', () => { - const { result } = renderHook(() => useInputHistoryStore()); - - act(() => { - result.current.addInput('test message'); - }); - - act(() => { - result.current.addInput('test message'); // Same as previous - }); - - expect(result.current.inputHistory).toEqual(['test message']); - - act(() => { - result.current.addInput('different message'); - }); - - act(() => { - result.current.addInput('test message'); // Same as first, but not consecutive - }); - - expect(result.current.inputHistory).toEqual([ - 'test message', - 'different message', - 'test message', - ]); - }); - - it('should initialize from logger successfully', async () => { - const mockLogger = { - getPreviousUserMessages: vi - .fn() - .mockResolvedValue(['newest', 'middle', 'oldest']), - }; - - const { result } = renderHook(() => useInputHistoryStore()); - - await act(async () => { - await result.current.initializeFromLogger(mockLogger); - }); - - // Should reverse the order to oldest first - expect(result.current.inputHistory).toEqual(['oldest', 'middle', 'newest']); - expect(mockLogger.getPreviousUserMessages).toHaveBeenCalledTimes(1); - }); - - it('should handle logger initialization failure gracefully', async () => { - const mockLogger = { - getPreviousUserMessages: vi - .fn() - .mockRejectedValue(new Error('Logger error')), - }; - - const { result } = renderHook(() => useInputHistoryStore()); - - await act(async () => { - await result.current.initializeFromLogger(mockLogger); - }); - - expect(result.current.inputHistory).toEqual([]); - }); - - it('should initialize only once', async () => { - const mockLogger = { - getPreviousUserMessages: vi - .fn() - .mockResolvedValue(['message1', 'message2']), - }; - - const { result } = renderHook(() => useInputHistoryStore()); - - // Call initializeFromLogger twice - await act(async () => { - await result.current.initializeFromLogger(mockLogger); - }); - - await act(async () => { - await result.current.initializeFromLogger(mockLogger); - }); - - // Should be called only once - expect(mockLogger.getPreviousUserMessages).toHaveBeenCalledTimes(1); - expect(result.current.inputHistory).toEqual(['message2', 'message1']); - }); - - it('should handle null logger gracefully', async () => { - const { result } = renderHook(() => useInputHistoryStore()); - - await act(async () => { - await result.current.initializeFromLogger(null); - }); - - expect(result.current.inputHistory).toEqual([]); - }); - - it('should trim input before adding to history', () => { - const { result } = renderHook(() => useInputHistoryStore()); - - act(() => { - result.current.addInput(' test message '); - }); - - expect(result.current.inputHistory).toEqual(['test message']); - }); - - describe('deduplication logic from previous implementation', () => { - it('should deduplicate consecutive messages from past sessions during initialization', async () => { - const mockLogger = { - getPreviousUserMessages: vi - .fn() - .mockResolvedValue([ - 'message1', - 'message1', - 'message2', - 'message2', - 'message3', - ]), // newest first with duplicates - }; - - const { result } = renderHook(() => useInputHistoryStore()); - - await act(async () => { - await result.current.initializeFromLogger(mockLogger); - }); - - // Should deduplicate consecutive messages and reverse to oldest first - expect(result.current.inputHistory).toEqual([ - 'message3', - 'message2', - 'message1', - ]); - }); - - it('should deduplicate across session boundaries', async () => { - const mockLogger = { - getPreviousUserMessages: vi.fn().mockResolvedValue(['old2', 'old1']), // newest first - }; - - const { result } = renderHook(() => useInputHistoryStore()); - - // Initialize with past session - await act(async () => { - await result.current.initializeFromLogger(mockLogger); - }); - - // Add current session inputs - act(() => { - result.current.addInput('old2'); // Same as last past session message - }); - - // Should deduplicate across session boundary - expect(result.current.inputHistory).toEqual(['old1', 'old2']); - - act(() => { - result.current.addInput('new1'); - }); - - expect(result.current.inputHistory).toEqual(['old1', 'old2', 'new1']); - }); - - it('should preserve non-consecutive duplicates', async () => { - const mockLogger = { - getPreviousUserMessages: vi - .fn() - .mockResolvedValue(['message2', 'message1', 'message2']), // newest first with non-consecutive duplicate - }; - - const { result } = renderHook(() => useInputHistoryStore()); - - await act(async () => { - await result.current.initializeFromLogger(mockLogger); - }); - - // Non-consecutive duplicates should be preserved - expect(result.current.inputHistory).toEqual([ - 'message2', - 'message1', - 'message2', - ]); - }); - - it('should handle complex deduplication with current session', () => { - const { result } = renderHook(() => useInputHistoryStore()); - - // Add multiple messages with duplicates - act(() => { - result.current.addInput('hello'); - }); - act(() => { - result.current.addInput('hello'); // consecutive duplicate - }); - act(() => { - result.current.addInput('world'); - }); - act(() => { - result.current.addInput('world'); // consecutive duplicate - }); - act(() => { - result.current.addInput('hello'); // non-consecutive duplicate - }); - - // Should have deduplicated consecutive ones - expect(result.current.inputHistory).toEqual(['hello', 'world', 'hello']); - }); - - it('should maintain oldest-first order in final output', async () => { - const mockLogger = { - getPreviousUserMessages: vi - .fn() - .mockResolvedValue(['newest', 'middle', 'oldest']), // newest first - }; - - const { result } = renderHook(() => useInputHistoryStore()); - - await act(async () => { - await result.current.initializeFromLogger(mockLogger); - }); - - // Add current session messages - act(() => { - result.current.addInput('current1'); - }); - act(() => { - result.current.addInput('current2'); - }); - - // Should maintain oldest-first order - expect(result.current.inputHistory).toEqual([ - 'oldest', - 'middle', - 'newest', - 'current1', - 'current2', - ]); - }); - }); -}); diff --git a/packages/cli/src/ui/hooks/useInputHistoryStore.ts b/packages/cli/src/ui/hooks/useInputHistoryStore.ts deleted file mode 100644 index f879e31f0f1..00000000000 --- a/packages/cli/src/ui/hooks/useInputHistoryStore.ts +++ /dev/null @@ -1,118 +0,0 @@ -/** - * @license - * Copyright 2025 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -import { useState, useCallback } from 'react'; -import { createDebugLogger } from '@qwen-code/qwen-code-core'; - -interface Logger { - getPreviousUserMessages(): Promise; -} - -export interface UseInputHistoryStoreReturn { - inputHistory: string[]; - addInput: (input: string) => void; - initializeFromLogger: (logger: Logger | null) => Promise; -} - -const debugLogger = createDebugLogger('INPUT_HISTORY_STORE'); - -/** - * Hook for independently managing input history. - * Completely separated from chat history and unaffected by /clear commands. - */ -export function useInputHistoryStore(): UseInputHistoryStoreReturn { - const [inputHistory, setInputHistory] = useState([]); - const [_pastSessionMessages, setPastSessionMessages] = useState([]); - const [_currentSessionMessages, setCurrentSessionMessages] = useState< - string[] - >([]); - const [isInitialized, setIsInitialized] = useState(false); - - /** - * Recalculate the complete input history from past and current sessions. - * Applies the same deduplication logic as the previous implementation. - */ - const recalculateHistory = useCallback( - (currentSession: string[], pastSession: string[]) => { - // Combine current session (newest first) + past session (newest first) - const combinedMessages = [...currentSession, ...pastSession]; - - // Deduplicate consecutive identical messages (same algorithm as before) - const deduplicatedMessages: string[] = []; - if (combinedMessages.length > 0) { - deduplicatedMessages.push(combinedMessages[0]); // Add the newest one unconditionally - for (let i = 1; i < combinedMessages.length; i++) { - if (combinedMessages[i] !== combinedMessages[i - 1]) { - deduplicatedMessages.push(combinedMessages[i]); - } - } - } - - // Reverse to oldest first for useInputHistory - setInputHistory(deduplicatedMessages.reverse()); - }, - [], - ); - - /** - * Initialize input history from logger with past session data. - * Executed only once at app startup. - */ - const initializeFromLogger = useCallback( - async (logger: Logger | null) => { - if (isInitialized || !logger) return; - - try { - const pastMessages = (await logger.getPreviousUserMessages()) || []; - setPastSessionMessages(pastMessages); // Store as newest first - recalculateHistory([], pastMessages); - setIsInitialized(true); - } catch (error) { - // Start with empty history even if logger initialization fails - debugLogger.warn( - 'Failed to initialize input history from logger:', - error, - ); - setPastSessionMessages([]); - recalculateHistory([], []); - setIsInitialized(true); - } - }, - [isInitialized, recalculateHistory], - ); - - /** - * Add new input to history. - * Recalculates the entire history with deduplication. - */ - const addInput = useCallback( - (input: string) => { - const trimmedInput = input.trim(); - if (!trimmedInput) return; // Filter empty/whitespace-only inputs - - setCurrentSessionMessages((prevCurrent) => { - const newCurrentSession = [...prevCurrent, trimmedInput]; - - setPastSessionMessages((prevPast) => { - recalculateHistory( - newCurrentSession.slice().reverse(), // Convert to newest first - prevPast, - ); - return prevPast; // No change to past messages - }); - - return newCurrentSession; - }); - }, - [recalculateHistory], - ); - - return { - inputHistory, - addInput, - initializeFromLogger, - }; -}