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.

104
Hooks
19k
Lines
REPL
State
TS
TypeScript

🔵 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:

  1. useInputBuffer — Captures keystrokes into a reactive text buffer with debounced updates.
  2. useArrowKeyHistory — On Up arrow, replaces buffer with previous entry (dedup-aware).
  3. useCommandQueue — On Ctrl+Enter, enqueues the buffer text and clears input.
  4. useMainLoopModel — Resolves the active model ID before sending the request.
  5. API Client — Sends the queued command to the backend with the selected model.
  6. useCancelRequest — Listens for Escape; wires an AbortController to the in-flight request.
  7. useLogMessages — Streams response tokens into the transcript message array.
  8. useDiffData — Parses any file-diff blocks in the response into structured hunks.
  9. useVirtualScroll — Computes visible window of messages for the transcript list.
  10. Terminal Render — Ink components consume hook outputs and paint the terminal.

Key Hooks & Functions

Hook / FunctionFilePurpose
useLogMessagesuseLogMessages.tsAppends streaming tokens to transcript, manages message lifecycle
useCommandQueueuseCommandQueue.tsFIFO queue for Ctrl+Enter submissions with flush control
useArrowKeyHistoryuseArrowKeyHistory.tsUp/down arrow prompt history with dedup and cursor tracking
useInputBufferuseInputBuffer.tsControlled text state for the prompt input area
useDiffDatauseDiffData.tsParses unified diff blocks into structured hunk objects
useVirtualScrolluseVirtualScroll.tsWindowed rendering for large message lists (overscan-aware)
useMainLoopModeluseMainLoopModel.tsModel selection state with fallback resolution
useCancelRequestuseCancelRequest.tsEscape-key listener wiring AbortController to active requests
useClipboarduseClipboard.tsSystem clipboard read/write with fallback for non-TTY
useAutoScrolluseAutoScroll.tsScroll-to-bottom on new content with user-pause detection
useThrottledRenderuseThrottledRender.tsRate-limits re-renders during high-frequency token streams
usePermissionStateusePermissionState.tsTracks 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

OptionDefaultDescription
VIRTUAL_SCROLL_OVERSCAN5Number of off-screen items rendered above/below viewport
THROTTLE_RENDER_MS16Minimum interval between forced re-renders (≈60 fps)
HISTORY_MAX_ENTRIES500Maximum stored prompt history entries
AUTO_SCROLL_THRESHOLD50Pixel distance from bottom before auto-scroll pauses