hooks — REPL State Hooks
REPL State Hooks
React hooks powering the interactive REPL experience. Manages transcript logging, command queuing, input history, prompt text buffering, diff display, large-list virtualization, model selection, and cancellation flows.
🔵 React Hooks 🟢 REPL State 🟡 Virtual Scrolling 🔴 Input Management
📚 What is this?
The hooks module is the reactive state backbone of the Claude Code REPL. Every piece of interactive behaviour—from typing a prompt to scrolling through thousands of output lines—is driven by a dedicated React hook that encapsulates its own state, effects, and cleanup logic.
💡 Analogy
Think of each hook as a specialised instrument in an orchestra. useLogMessages is the recording engineer, useCommandQueue is the conductor scheduling pieces, useArrowKeyHistory is the sheet-music librarian, and useVirtualScroll is the spotlight operator making sure only the visible musicians are lit up. Together they produce the REPL symphony.
Architecture
flowchart LR
subgraph AppState["AppState Store"]
S1["messages[]"]
S2["modelId"]
S3["inputBuffer"]
end
subgraph Hooks["React Hooks"]
H1["useLogMessages"]
H2["useCommandQueue"]
H3["useArrowKeyHistory"]
H4["useInputBuffer"]
H5["useDiffData"]
H6["useVirtualScroll"]
H7["useMainLoopModel"]
H8["useCancelRequest"]
end
subgraph Components["REPL Components"]
C1["PromptInput"]
C2["TranscriptView"]
C3["DiffViewer"]
C4["ModelSelector"]
end
subgraph Services["Backend Services"]
SV1["API Client"]
SV2["File Watcher"]
end
S1 --> H1
S2 --> H7
S3 --> H4
H1 --> C2
H2 --> C1
H3 --> C1
H4 --> C1
H5 --> C3
H6 --> C2
H7 --> C4
H8 --> C1
SV1 --> H1
SV2 --> H5
Data Flow
flowchart TD KE["Keyboard Event"] --> IB["useInputBuffer"] IB --> CQ["useCommandQueue"] CQ --> API["API Client send()"] API --> LM["useLogMessages"] LM --> VS["useVirtualScroll"] VS --> RENDER["Terminal Render"] KE --> AKH["useArrowKeyHistory"] AKH --> IB KE --> CR["useCancelRequest"] CR -->|abort signal| API API --> DD["useDiffData"] DD --> RENDER MLM["useMainLoopModel"] --> API
🚶 Step-by-Step Walkthrough: User submits a prompt
Trace a single prompt from keypress to rendered response:
- useInputBuffer — Captures keystrokes into a reactive text buffer with debounced updates.
- useArrowKeyHistory — On Up arrow, replaces buffer with previous entry (dedup-aware).
- useCommandQueue — On Ctrl+Enter, enqueues the buffer text and clears input.
- useMainLoopModel — Resolves the active model ID before sending the request.
- API Client — Sends the queued command to the backend with the selected model.
- useCancelRequest — Listens for Escape; wires an AbortController to the in-flight request.
- useLogMessages — Streams response tokens into the transcript message array.
- useDiffData — Parses any file-diff blocks in the response into structured hunks.
- useVirtualScroll — Computes visible window of messages for the transcript list.
- Terminal Render — Ink components consume hook outputs and paint the terminal.
Key Hooks & Functions
| Hook / Function | File | Purpose |
|---|---|---|
useLogMessages | useLogMessages.ts | Appends streaming tokens to transcript, manages message lifecycle |
useCommandQueue | useCommandQueue.ts | FIFO queue for Ctrl+Enter submissions with flush control |
useArrowKeyHistory | useArrowKeyHistory.ts | Up/down arrow prompt history with dedup and cursor tracking |
useInputBuffer | useInputBuffer.ts | Controlled text state for the prompt input area |
useDiffData | useDiffData.ts | Parses unified diff blocks into structured hunk objects |
useVirtualScroll | useVirtualScroll.ts | Windowed rendering for large message lists (overscan-aware) |
useMainLoopModel | useMainLoopModel.ts | Model selection state with fallback resolution |
useCancelRequest | useCancelRequest.ts | Escape-key listener wiring AbortController to active requests |
useClipboard | useClipboard.ts | System clipboard read/write with fallback for non-TTY |
useAutoScroll | useAutoScroll.ts | Scroll-to-bottom on new content with user-pause detection |
useThrottledRender | useThrottledRender.ts | Rate-limits re-renders during high-frequency token streams |
usePermissionState | usePermissionState.ts | Tracks pending permission prompts and user responses |
Directory Map
Source tree for hooks
hooks/
├── useLogMessages.ts ← Transcript streaming & lifecycle
├── useCommandQueue.ts ← Ctrl+Enter FIFO queue
├── useArrowKeyHistory.ts ← Up-arrow prompt recall (dedup)
├── useInputBuffer.ts ← Controlled prompt text state
├── useDiffData.ts ← Unified diff parser
├── useVirtualScroll.ts ← Windowed list virtualization
├── useMainLoopModel.ts ← Model selector state
├── useCancelRequest.ts ← Escape cancellation controller
├── useClipboard.ts ← Clipboard read/write
├── useAutoScroll.ts ← Smart auto-scroll on new output
├── useThrottledRender.ts ← Rate-limited re-render gate
├── usePermissionState.ts ← Permission prompt tracking
├── useAnimationFrame.ts ← rAF-based animation loop
├── useInterval.ts ← setInterval wrapper with cleanup
├── useFocusManager.ts ← Tab-key focus ring management
├── __tests__/ ← Hook unit tests
│ ├── useLogMessages.test.ts
│ ├── useCommandQueue.test.ts
│ └── ...
└── index.ts ← Barrel export
Configuration
| Option | Default | Description |
|---|---|---|
VIRTUAL_SCROLL_OVERSCAN | 5 | Number of off-screen items rendered above/below viewport |
THROTTLE_RENDER_MS | 16 | Minimum interval between forced re-renders (≈60 fps) |
HISTORY_MAX_ENTRIES | 500 | Maximum stored prompt history entries |
AUTO_SCROLL_THRESHOLD | 50 | Pixel distance from bottom before auto-scroll pauses |