82 KiB
Claude Code — React Hooks
This document covers every hook in src/hooks/, src/hooks/toolPermission/, and src/hooks/notifs/. For each hook the entry covers: purpose, parameters/props, return value, key logic and side effects, and dependencies.
Table of Contents
- Core / Utility Hooks
- Input & Text Editing Hooks
- Permission & Tool-Use Hooks
- Swarm / Teammate Hooks
- IDE Integration Hooks
- Remote & Session Hooks
- Plugin & Suggestion Hooks
- Notification Hooks (
notifs/) - Tool Permission Subsystem (
toolPermission/) - Non-Hook Utilities in
hooks/
Core / Utility Hooks
useAfterFirstRender
File: hooks/useAfterFirstRender.ts
Purpose: ANT-internal startup-time measurement hook. After the first render it writes startup time to stderr and calls process.exit(0) if the CLAUDE_CODE_EXIT_AFTER_FIRST_RENDER environment variable is set.
Parameters: none
Return Value: void
Key Logic:
- Reads env var
CLAUDE_CODE_EXIT_AFTER_FIRST_RENDER. - Uses a
useEffecton[]to fire after first commit. - Computes elapsed ms from
MACRO.STARTUP_TIMESTAMP, writes toprocess.stderr, then exits.
Dependencies: useEffect (React)
useApiKeyVerification
File: hooks/useApiKeyVerification.ts
Purpose: Manages the full lifecycle of API key verification — loading, valid, invalid, missing, or error — and exposes a reverify callback. Guards against running apiKeyHelper scripts before the trust dialog is dismissed to prevent RCE.
Parameters: none
Return Value: ApiKeyVerificationResult — { status: 'loading'|'valid'|'invalid'|'missing'|'error', reverify: () => void, errorMessage?: string }
Key Logic:
- Subscribes to
AppStatefortrustDialogAcceptedandapiKeyVerificationStatus. - Uses
useEffectto run the verification on mount and wheneverreverifyis called. - Skips the
apiKeyHelperprocess before the trust dialog is shown. - Returns a stable
reverifycallback viauseCallback.
Dependencies: useAppState, useSetAppState, useCallback, useEffect
useBlink
File: hooks/useBlink.ts
Purpose: Returns a blinking boolean flag synchronized with an animation-frame clock. Pauses when the terminal is blurred or the component is offscreen (OffscreenFreeze).
Parameters:
enabled: boolean— when false, always returnstrue(cursor always visible).intervalMs?: number— blink period in milliseconds (default: 530).
Return Value: [ref: RefObject<unknown>, isVisible: boolean]
Key Logic:
- Uses
useAnimationFrame(Ink hook) to read the shared clock counter. - Divides counter by
intervalMs / frameMsand toggles on even/odd. - Returns same ref from Ink's
useOffscreenFreezeto pause when not in viewport.
Dependencies: useAnimationFrame (ink), useTerminalFocus (ink), useRef, useMemo
useCommandQueue
File: hooks/useCommandQueue.ts
Purpose: Exposes the current unified command queue as a reactive array. Any component can subscribe to observe queued commands without managing external store subscriptions manually.
Parameters: none
Return Value: readonly QueuedCommand[]
Key Logic:
- Wraps
useSyncExternalStoreovermessageQueueManager's subscribe/getSnapshot pair. - Re-renders only when the queue reference changes (not on every push that doesn't change length).
Dependencies: useSyncExternalStore (React), messageQueueManager
useCopyOnSelect
File: hooks/useCopyOnSelect.ts
Purpose: Automatically copies selected text to the clipboard when the user releases the mouse (mouseup) or double/triple-clicks. Also exports useSelectionBgColor for theming selected text.
Parameters:
selection: SelectionState— current ink selection state.isActive: boolean— only active when true.onCopied?: () => void— callback fired after clipboard write.
Return Value: void
Key Logic:
- Subscribes to ink mouse events via
useEffect. - On mouseup: if selection is non-empty and
isActive, callsnavigator.clipboard.writeText. useSelectionBgColor()reads AppState theme to return the correct highlight color.
Dependencies: useEffect, useAppState, useCallback
useDoublePress
File: hooks/useDoublePress.ts
Purpose: Returns a callback that implements double-press detection within an 800 ms window. Used for Ctrl+C/D to exit and double-Escape to clear input.
Parameters:
setPending: (show: boolean) => void— called withtrueafter first press,falseafter timeout.onDoublePress: () => void— called when the second press occurs within the window.onFirstPress?: () => void— optional side effect on first press.
Return Value: () => void — the wrapped press handler
Key Logic:
- Tracks
lastPressTimein a ref. - On call: if elapsed < 800 ms, calls
onDoublePressand resets; otherwise callssetPending(true), sets a 800 ms timer to callsetPending(false), and optionally callsonFirstPress.
Dependencies: useRef, useCallback
useElapsedTime
File: hooks/useElapsedTime.ts
Purpose: Computes a human-readable elapsed time string (e.g. "1m 23s") that updates while a task is running and freezes once it ends.
Parameters:
startTime: number— Unix timestamp (ms) when timing started.isRunning: boolean— when false, elapsed is frozen.ms?: number— update interval in ms (default: 1000).pausedMs?: number— accumulated paused time to subtract.endTime?: number— if provided, freezes at this timestamp.
Return Value: string — formatted elapsed time like "5s", "1m 23s", "2h 5m".
Key Logic:
- Uses
useSyncExternalStoreover a timer-based external clock. - Clock updates every
msviasetInterval; each subscriber gets a stable snapshot until it ticks. - Formats the delta using
formatDuration.
Dependencies: useSyncExternalStore, useRef
useExitOnCtrlCD
File: hooks/useExitOnCtrlCD.ts
Purpose: Implements double-press Ctrl+C / Ctrl+D to exit. Returns pending state so callers can show a "Press again to exit" hint.
Parameters:
useKeybindingsHook: (bindings: ...) => void— injectable hook for binding.onInterrupt?: () => void— called on first Ctrl+C press.onExit?: () => void— called on second press.isActive?: boolean— enables/disables the handler.
Return Value: ExitState — { pending: boolean, keyName: string | null }
Key Logic:
- Uses
useDoublePressinternally for both Ctrl+C and Ctrl+D. - Sets
pending = trueafter first press; false after timeout or second press. keyNametracks which key was pressed ('Ctrl-C' or 'Ctrl-D').
Dependencies: useDoublePress, useState, useCallback
useExitOnCtrlCDWithKeybindings
File: hooks/useExitOnCtrlCDWithKeybindings.ts
Purpose: Convenience wrapper that wires useExitOnCtrlCD to the keybinding system.
Parameters:
onExit?: () => voidonInterrupt?: () => voidisActive?: boolean
Return Value: ExitState
Key Logic: Passes useKeybindings as the hook parameter to useExitOnCtrlCD.
Dependencies: useExitOnCtrlCD, useKeybindings
useMemoryUsage
File: hooks/useMemoryUsage.ts
Purpose: Polls Node.js process.memoryUsage().heapUsed every 10 seconds and returns a status when memory usage is high or critical.
Parameters: none
Return Value: MemoryUsageInfo | null — null for normal; { heapUsed: number, status: 'high' | 'critical' } when heap > 1.5 GB (high) or > 2.5 GB (critical).
Key Logic:
- Uses
useInterval(usehooks-ts) with 10 000 ms period. - Thresholds:
HIGH_HEAP_MB = 1536,CRITICAL_HEAP_MB = 2560. - Returns
nullwhen below thresholds.
Dependencies: useInterval, useState, useEffect
useMinDisplayTime
File: hooks/useMinDisplayTime.ts
Purpose: Prevents UI flicker by guaranteeing each distinct value stays visible for at least minMs milliseconds before switching.
Parameters:
value: T— the value to display.minMs: number— minimum display duration.
Return Value: T — the "stable" displayed value, may lag behind value.
Key Logic:
- Uses
useRefto track the current stable value and the timestamp it was set. - On
valuechange: ifDate.now() - lastChanged >= minMs, updates immediately; otherwise schedules asetTimeoutto update after the remainder.
Dependencies: useState, useRef, useEffect
useNotifyAfterTimeout
File: hooks/useNotifyAfterTimeout.ts
Purpose: Sends a desktop (OS-level) notification after 6 seconds of user inactivity — used to alert the user when Claude has been working unattended.
Parameters:
message: string— the notification body text.notificationType: string— identifies the event type for analytics.
Return Value: void
Key Logic:
- Waits 6 000 ms after mount using
setTimeout. - Checks terminal focus state; only fires if the terminal is not focused.
- Calls
sendDesktopNotificationfrom a native module.
Dependencies: useEffect, useRef
useTimeout
File: hooks/useTimeout.ts
Purpose: Returns a boolean that becomes true after delay ms. Resets when resetTrigger changes.
Parameters:
delay: number— ms to wait.resetTrigger?: number— changing this value resets the timer.
Return Value: boolean — false until the delay elapses, then true.
Key Logic: Simple useState + useEffect with setTimeout. Cleanup clears the timeout on re-run or unmount.
Dependencies: useState, useEffect
useSettings
File: hooks/useSettings.ts
Purpose: Reads the current settings from global AppState. Reactive — re-renders when settings change (e.g. file-watcher triggers).
Parameters: none
Return Value: ReadonlySettings
Key Logic: Returns useAppState(s => s.settings).
Dependencies: useAppState
useSettingsChange
File: hooks/useSettingsChange.ts
Purpose: Subscribes to the settings change detector and calls onChange with the new settings and the change source whenever the settings file is modified on disk.
Parameters:
onChange: (source: string, settings: Settings) => void
Return Value: void
Key Logic:
- Uses
useEffectto subscribe tosettingsChangeDetector.subscribe(onChange). - Returns the unsubscribe function as the cleanup.
Dependencies: useEffect, settingsChangeDetector
useDeferredHookMessages
File: hooks/useDeferredHookMessages.ts
Purpose: Injects SessionStart hook messages into the message list asynchronously on mount, avoiding blocking the first render.
Parameters:
pendingHookMessages: Message[]— messages generated by session-start hooks.setMessages: SetMessages— the message list updater.
Return Value: () => Promise<void> — a stable async callback to trigger injection.
Key Logic:
- Defers via
setTimeout(0)to let the first render complete before injecting hook messages. - Uses
useRefto avoid stale closure issues.
Dependencies: useRef, useCallback
useDiffData
File: hooks/useDiffData.ts
Purpose: Fetches current git diff statistics and hunks on mount (used by the /diff command view).
Parameters: none
Return Value: DiffData — { stats: DiffStats, files: string[], hunks: DiffHunk[], loading: boolean }
Key Logic:
- On mount, calls
getGitDiff()which runsgit diffin the cwd. - Sets
loading: trueuntil the async fetch completes.
Dependencies: useState, useEffect
useFileHistorySnapshotInit
File: hooks/useFileHistorySnapshotInit.ts
Purpose: One-time initialization of the file history state from snapshot data stored in the conversation log, restoring file timestamps across /resume.
Parameters:
initialFileHistorySnapshots: FileHistorySnapshot[]fileHistoryState: FileHistoryStateonUpdateState: (state: FileHistoryState) => void
Return Value: void
Key Logic:
- Uses
useEffectwith[]dep to run only once. - Merges
initialFileHistorySnapshotsintofileHistoryStatewithout overwriting newer entries.
Dependencies: useEffect
useInputBuffer
File: hooks/useInputBuffer.ts
Purpose: Provides a debounced undo buffer for text input, enabling "undo last paste" or "undo last edit" functionality.
Parameters:
maxBufferSize: number— maximum number of entries to keep.debounceMs: number— how long to wait before committing current value.
Return Value: UseInputBufferResult — { pushToBuffer, undo, canUndo, clearBuffer }
Key Logic:
- Maintains a
string[]undo stack in a ref. pushToBufferis debounced: multiple rapid changes collapse into one buffer entry.undopops the stack and callsonChangewith the previous value.
Dependencies: useRef, useCallback, useEffect
useLogMessages
File: hooks/useLogMessages.ts
Purpose: Incrementally records messages to the conversation transcript file (.jsonl) after each render. Avoids re-writing the full transcript on every update.
Parameters:
messages: readonly Message[]— the current message list.ignore?: boolean— when true, skips recording.
Return Value: void
Key Logic:
- Tracks
lastProcessedIndexin a ref to process only new messages. - Handles edge cases: compaction (transcript size shrinks), first render, head-pointer rewind.
- Calls
recordTranscript(messages, from, to)for new messages only. - Deduplicates compact-summary boundaries.
Dependencies: useEffect, useRef
useMainLoopModel
File: hooks/useMainLoopModel.ts
Purpose: Returns the resolved model name for the current session. Re-evaluates when GrowthBook flags are refreshed so model alias resolution stays current mid-session.
Parameters: none
Return Value: ModelName
Key Logic:
- Reads
settings.modelfrom AppState. - Subscribes to
onGrowthBookRefreshviauseEffect; on each refresh, forces a re-render by incrementing a counter state. - Calls
resolveModelAlias(model)to translate user-facing aliases (e.g.opus) to concrete model IDs.
Dependencies: useAppState, useEffect, useState
useManagePlugins
File: hooks/useManagePlugins.ts
Purpose: Loads the plugin list on mount and wires up plugin lifecycle management: delisting enforcement, MCP/LSP plugin counting, and refresh-needed notifications.
Parameters:
{ enabled?: boolean }
Return Value: void
Key Logic:
- On mount (if enabled): calls
loadPlugins()and writes results to AppState. - Enforces delisted plugin removal by reading
delistedPluginsfrom settings. - Counts active MCP and LSP plugins and writes totals to AppState for /doctor diagnostics.
- Does NOT auto-refresh; refresh is triggered explicitly via
/reload-plugins.
Dependencies: useEffect, useSetAppState, useAppState
useMergedClients
File: hooks/useMergedClients.ts
Purpose: Deduplicates two MCP client lists (initial from settings + dynamically loaded) by server name.
Parameters:
initialClients: MCPServerConnection[]mcpClients: MCPServerConnection[]
Return Value: MCPServerConnection[]
Key Logic: Uses lodash.uniqBy([...initialClients, ...mcpClients], 'name'). The useMemo dependency is the combined list length and name set.
Dependencies: useMemo, lodash.uniqBy
useMergedCommands
File: hooks/useMergedCommands.ts
Purpose: Deduplicates command lists from initial load and MCP-sourced commands by command name.
Parameters:
initialCommands: Command[]mcpCommands: Command[]
Return Value: Command[]
Key Logic: useMemo over uniqBy([...initialCommands, ...mcpCommands], getCommandName).
Dependencies: useMemo
useMergedTools
File: hooks/useMergedTools.ts
Purpose: Assembles the full tool pool for a session by combining built-in tools, MCP tools, and applying permission-context filtering.
Parameters:
initialTools: Tool[]mcpTools: Tool[]toolPermissionContext: ToolPermissionContext
Return Value: Tools (the assembled tool set)
Key Logic:
- Calls
assembleToolPool(initialTools, mcpTools)to build the combined list. - Then calls
mergeAndFilterTools(pool, toolPermissionContext)to remove disabled tools.
Dependencies: useMemo
useSkillsChange
File: hooks/useSkillsChange.ts
Purpose: Keeps the command list fresh when skill files change on disk or when GrowthBook flags are refreshed.
Parameters:
cwd: string | undefined— the current working directory for scanning skills.onCommandsChange: (commands: Command[]) => void— callback to update the command list.
Return Value: void
Key Logic:
- Subscribes to
skillChangeDetector.subscribe(handleChange)— fires on skill file writes. - On file change: calls
clearCommandsCache()+getCommands(cwd)and callsonCommandsChange. - Subscribes to
onGrowthBookRefresh(handleGrowthBookRefresh)— on GB flag refresh, callsclearCommandMemoizationCaches()+getCommands(cwd)to re-evaluate feature-gated commands.
Dependencies: useEffect, useCallback
useUpdateNotification
File: hooks/useUpdateNotification.ts
Purpose: Returns the new semantic version string when an auto-update has been downloaded, for display in the status bar. Returns null if no new version or the version hasn't changed since last notification.
Parameters:
updatedVersion: string | null | undefined— the downloaded version (from auto-updater).initialVersion?: string— baseline version (default:MACRO.VERSION).
Return Value: string | null
Key Logic:
- Parses both versions with
semverto extractmajor.minor.patch. - Uses
useStateto track the last-notified semver. - If the new semver differs from
lastNotifiedSemver, sets state and returns the new value (triggers notification display). Otherwise returnsnull.
Dependencies: useState, semver
Input & Text Editing Hooks
useTextInput
File: hooks/useTextInput.ts
Purpose: Full readline-style text input handler. Manages cursor position, multiline editing, kill ring (Ctrl+K/U/W), yank (Ctrl+Y / Meta+Y), history navigation (Up/Down arrows), and ghost text rendering.
Parameters: UseTextInputProps including:
value: string— current text value (controlled).onChange: (value: string) => voidonSubmit?: (value: string) => voidonExit?: () => voidonHistoryUp / onHistoryDown / onHistoryReset / onClearInputfocus?: booleanmask?: string— masks all chars with this string.multiline?: booleancursorChar: stringcolumns: number— terminal width for wrapping.externalOffset: number— cursor offset controlled externally.onOffsetChange: (offset: number) => voidinputFilter?: (input: string, key: Key) => stringinlineGhostText?: InlineGhostTextdisableCursorMovementForUpDownKeys?: booleandisableEscapeDoublePress?: booleanmaxVisibleLines?: number
Return Value: TextInputState — { onInput, renderedValue, offset, setOffset, cursorLine, cursorColumn, viewportCharOffset, viewportCharEnd }
Key Logic:
Cursorclass fromutils/Cursor.jsmanages the text buffer and position arithmetic.- Maps keypresses to cursor mutations: Ctrl+A (home), Ctrl+E (end), Ctrl+F/B (forward/back), Ctrl+N/P (next/prev line), Meta+F/B (word navigation).
- Kill ring: Ctrl+K (kill to end), Ctrl+U (kill to start), Ctrl+W (kill word). Successive kills append to ring.
- Yank: Ctrl+Y inserts last kill; Meta+Y cycles through the ring.
- Double-press Ctrl+C clears or exits (via
useDoublePress). - Double-press Escape clears input with "Esc again to clear" hint.
- SSH-coalesced Enter detection:
text\rform triggers submit. - Handles raw
\x7fDEL characters for SSH/tmux compatibility. - Inline ghost text rendered at cursor position when
inlineGhostText.insertPosition === offset.
Dependencies: useDoublePress, useNotifications, Cursor class, useCallback
useVimInput
File: hooks/useVimInput.ts
Purpose: Extends useTextInput with a full Vim normal/insert mode state machine, including operators (d, c, y), motions, dot-repeat, find (f/F/t/T), text objects (iw, aw, etc.), and yank register.
Parameters: UseVimInputProps — same as UseTextInputProps plus:
onModeChange?: (mode: VimMode) => voidonUndo?: () => void
Return Value: VimInputState — extends TextInputState with { mode: VimMode, setMode }
Key Logic:
- Delegates INSERT mode keypresses to
useTextInputafter runninginputFilter. - In NORMAL mode, dispatches keypresses through
transition(state.command, input, ctx)fromvim/transitions.ts. - Manages
vimStateRef(current mode + pending command accumulator) andpersistentRef(register, lastFind, lastChange for dot-repeat). - Escape in INSERT:
switchToNormalMode()moves cursor left by one. - Arrow keys in NORMAL: mapped to h/j/k/l motions.
?in NORMAL idle: enters/search by writing?to the input.setModeExternalallows callers to programmatically switch modes (used by/vimcommand).
Dependencies: useTextInput, useState, useRef, useCallback, vim operators/transitions
useSearchInput
File: hooks/useSearchInput.ts
Purpose: Full readline-style text input for search boxes (history search, global search). Includes kill ring, yank, and word navigation.
Parameters: UseSearchInputOptions — { initialValue?, onKeyDown?, placeholder? }
Return Value: { query: string, setQuery, cursorOffset: number, handleKeyDown: (key: Key, input: string) => void }
Key Logic:
- Implements the same Ctrl key mapping as
useTextInputbut as a standalone reducer without React state for the cursor offset. - Used in
HistorySearchInputandGlobalSearchDialog.
Dependencies: useState, useCallback, useRef, kill ring utilities
useArrowKeyHistory
File: hooks/useArrowKeyHistory.tsx
Purpose: Arrow-key navigation through input history with lazy chunked loading, mode-based filtering, and draft preservation.
Parameters:
onSetInput: (value: string) => voidcurrentInput: stringpastedContents: string[]— paste-detected content to exclude from history matching.setCursorOffset?: (offset: number) => voidcurrentMode?: PromptInputMode
Return Value: { handleHistoryUp, handleHistoryDown, handleHistoryReset }
Key Logic:
- Loads history lazily in chunks of 50 from
getHistory(). - Navigates using an index pointer; on first Up saves the current draft.
- Filters entries by mode (e.g., bash mode only returns bash history).
- Shows a "Search history: Ctrl+R" hint notification on first use.
- Resets index when
currentInputchanges externally.
Dependencies: useState, useRef, useCallback, useNotifications
useHistorySearch
File: hooks/useHistorySearch.ts
Purpose: Implements Ctrl+R backward incremental history search with query matching and keyboard navigation.
Parameters:
onSetInput: (value: string) => voidcurrentInput: string- plus keybinding options.
Return Value: { historyQuery, setHistoryQuery, historyMatch, historyFailedMatch, handleKeyDown }
Key Logic:
- Registers
history:searchkeybinding (Ctrl+R) to activate search mode. - In search mode, registers
historySearch:*bindings (Enter to confirm, Escape to cancel, up/down to cycle matches). - Filters history entries by substring match against
historyQuery. historyFailedMatch: boolean— true when query has text but no match.
Dependencies: useKeybinding, useKeybindings, useState, useCallback, useEffect
useTypeahead
File: hooks/useTypeahead.tsx
Purpose: The primary typeahead/autocomplete engine for the prompt input. Handles @file, /command, #channel, and directory suggestions using debounced fuzzy matching, shell completion, and MCP resources.
Parameters: Large props object including:
inputValue: string,cursorOffset: numbercommands: Command[],agents: AgentDefinition[]mcpResources: MCPResource[]isLoading: booleanonSelect: (value: string) => voidonToggleVisible: (show: boolean) => void
Return Value: { suggestions, selectedIndex, handleKeyDown, isSuggesting, suggestionType, ... }
Key Logic:
- Detects suggestion context from input:
@tokentriggers file/resource/agent suggestions;/triggers command suggestions;#channeltriggers Slack channel suggestions (if Slack MCP present). - File suggestions use
generateUnifiedSuggestions(nucleo + Fuse.js ranked). - Command suggestions use
generateCommandSuggestionswith argument hint generation. - Shell completions use
getShellCompletionsfor bash/zsh completions. - Path completions use
getPathCompletions/getDirectoryCompletions. - Registers as an overlay via
useRegisterOverlayso escape/enter/arrow keys are captured. - Uses
useDebounceCallback(usehooks-ts) to rate-limit file lookups. - Tracks keyboard navigation state (
selectedIndex) internally. - Session resume suggestions for
/resumequeries viasearchSessionsByCustomTitle.
Dependencies: useInput (ink, backward-compat bridge), useRegisterOverlay, useKeybindings, useDebounceCallback, useState, useRef, useMemo, useCallback, useEffect, generateUnifiedSuggestions, generateCommandSuggestions, getShellCompletions
usePasteHandler
File: hooks/usePasteHandler.ts
Purpose: Handles bracketed paste mode detection, large paste chunking, image file path detection, and macOS clipboard image fallback.
Parameters:
{ onPaste: (text: string) => void, onInput: (text: string, key: Key) => void, onImagePaste?: (base64: string, ...) => void }
Return Value: { wrappedOnInput, pasteState, isPasting }
Key Logic:
- Detects bracketed paste via
\x1b[?2004h/\x1b[200~/\x1b[201~escape sequences. - Splits large pastes (>1000 chars) into multiple
onPastecalls to avoid blocking the event loop. - Detects image file paths in paste content (extensions
.png,.jpg,.gif, etc.) and triggersonImagePaste. - On macOS: falls back to
pbpastefor image clipboard content.
Dependencies: useState, useRef, useCallback, useEffect
useVoice
File: hooks/useVoice.ts
Purpose: Hold-to-talk voice recording using the voice_stream STT endpoint. Auto-repeat key events extend the recording; releasing the key after RELEASE_TIMEOUT_MS stops it.
Parameters: { onTranscript: (text: string) => void, enabled: boolean }
Return Value: { state: 'idle'|'recording'|'processing', handleKeyEvent: (fallbackMs?: number) => void }
Key Logic:
- Calls
connectVoiceStream()to open a WebSocket tovoice_streamSTT. - Maps user locale to BCP-47 language codes for Deepgram (20+ languages mapped).
- Auto-repeat detection: key events arriving within 120 ms are considered "held".
- Modifier combos (Ctrl+Space etc.) use 2 000 ms
FIRST_PRESS_FALLBACK_MS. - Requires 5 rapid keydowns (HOLD_THRESHOLD) for bare-char bindings to activate, 2 for warmup feedback.
- Uses
useTerminalFocusto pause recording when terminal loses focus. - Fetches voice keyterms for improved domain recognition.
Dependencies: useState, useRef, useCallback, useEffect, useTerminalFocus, connectVoiceStream, getVoiceKeyterms
useVoiceEnabled
File: hooks/useVoiceEnabled.ts
Purpose: Combines user intent (settings.voiceEnabled), OAuth auth check, and GrowthBook kill-switch into a single boolean indicating whether voice mode is available.
Parameters: none
Return Value: boolean
Key Logic:
userIntentfromuseAppState(s => s.settings.voiceEnabled === true).authedmemoized onauthVersion— avoids expensivehasVoiceAuth()call on every render.isVoiceGrowthBookEnabled()not memoized (cheap cached lookup, so mid-session kill-switch takes effect).
Dependencies: useAppState, useMemo
useVoiceIntegration
File: hooks/useVoiceIntegration.tsx
Purpose: Orchestrates the full voice-mode integration: reading keybindings, detecting held keys, activating useVoice, suppressing full-width space input during recording, and showing status notifications.
Parameters:
{ onTranscript: (text: string) => void, isModalOverlayActive: boolean }
Return Value: { voiceState: VoiceState, handleVoiceKeyEvent }
Key Logic:
- Reads
voice:activatekeybinding from keybinding context (default: spacebar). - Detects held key by counting rapid key events (HOLD_THRESHOLD=5 for bare chars, 1 for modifier combos).
- Shows warmup notification after WARMUP_THRESHOLD=2 events.
- Uses
useInput(ink) as a backward-compat bridge until REPL wireshandleKeyDownto<Box onKeyDown>. - Guards on
useIsModalOverlayActive()— does not activate voice while a modal is open. - Dead-code elimination: conditionally requires
useVoiceonly iffeature('VOICE_MODE')is set; otherwise uses a no-op stub. - Calls
normalizeFullWidthSpaceto handle full-width space (Japanese IME) by passing it to the transcript instead of activating voice.
Dependencies: useVoice, useVoiceEnabled, useInput (ink), useOptionalKeybindingContext, useIsModalOverlayActive, useNotifications, useState, useRef, useMemo, useCallback, useEffect
useVirtualScroll
File: hooks/useVirtualScroll.ts
Purpose: React-level virtualization for MessageRow items inside a ScrollBox. Mounts only items in the viewport plus overscan, using spacer boxes to maintain scroll height.
Parameters:
scrollRef: RefObject<ScrollBoxHandle | null>— reference to the ScrollBox.itemKeys: readonly string[]— stable keys for each item.columns: number— terminal width; triggers height cache rescaling on change.
Return Value: VirtualScrollResult:
range: [startIndex, endIndex)— half-open slice to render.topSpacer: number— rows before the first rendered item.bottomSpacer: number— rows after last rendered item.measureRef: (key) => ref— attach to each item rootBoxfor height measurement.spacerRef: RefObject<DOMElement>— attach to top spacer for drift-free origin tracking.offsets: ArrayLike<number>— cumulative y-offsets per item.getItemTop: (index) => number— reads live YogacomputedTop.getItemElement: (index) => DOMElement | nullgetItemHeight: (index) => number | undefinedscrollToIndex: (i) => void
Key Logic:
DEFAULT_ESTIMATE = 3rows for unmeasured items;OVERSCAN_ROWS = 80;COLD_START_COUNT = 30.SCROLL_QUANTUM = 40rows — scrollTop is quantized so React re-renders only when the mounted range needs to shift, not on every wheel tick.SLIDE_STEP = 25— caps new mounts per commit to bound reconcile time.PESSIMISTIC_HEIGHT = 1for coverage back-walk (guarantees viewport coverage).MAX_MOUNTED_ITEMS = 300cap.- On column change: scales all cached heights by
oldCols/newColsinstead of clearing. - Uses
useSyncExternalStoreover the ScrollBox's scroll-top external store. - Uses
useLayoutEffectto measure Yoga heights after each commit. - Sticky-scroll: when pinned to the bottom, always renders the last N items.
Dependencies: useRef, useMemo, useDeferredValue, useLayoutEffect, useSyncExternalStore, ScrollBox handle
Permission & Tool-Use Hooks
useCanUseTool
File: hooks/useCanUseTool.tsx
Purpose: Core permission gate for tool execution. Called for every tool use attempt; routes through the appropriate handler (coordinator, interactive, swarm-worker) and resolves to a PermissionDecision.
Parameters:
setToolUseConfirmQueue: SetState<ToolUseConfirm[]>setToolPermissionContext: (ctx: ToolPermissionContext) => void
Return Value: CanUseToolFn — async (tool, input, toolUseContext, assistantMessage, toolUseID) => PermissionDecision
Key Logic:
- Calls
hasPermissionsToUseToolto get the initial decision (allow,deny, orask). - If
allowordeny: logs and returns immediately. - If
ask: a. If swarm worker: delegates tohandleSwarmWorkerPermission(forwards to leader via mailbox). b. If coordinator worker: delegates tohandleCoordinatorPermission(awaits hooks + classifier, then falls through). c. Otherwise: delegates tohandleInteractivePermission(shows dialog, races hooks/classifier/bridge/channel). - Creates a
PermissionContextobject with the full set of callbacks (logDecision, persistPermissions, tryClassifier, runHooks, etc.).
Dependencies: useCallback, useAppState, useSetAppState, createPermissionContext, createPermissionQueueOps, handleCoordinatorPermission, handleInteractivePermission, handleSwarmWorkerPermission
CancelRequestHandler (exported as useCancelRequest module)
File: hooks/useCancelRequest.ts
Purpose: React component (renders null) that registers three keybinding handlers for cancellation:
chat:cancel(Escape) — cancels running task or pops queued command.app:interrupt(Ctrl+C) — cancels running task; in teammate view, also kills all agents and exits.chat:killAgents(Ctrl+X Ctrl+K) — two-press pattern to stop all background agents.
Parameters: CancelRequestHandlerProps:
setToolUseConfirmQueue,onCancel,onAgentsKilledisMessageSelectorVisible,screenabortSignal?: AbortSignalpopCommandFromQueue?,vimMode,isLocalJSXCommand,isSearchingHistory,isHelpOpeninputMode?, inputValue?, streamMode?
Return Value: null
Key Logic:
handleCancel: Priority 1 — abort signal if task running. Priority 2 — pop command if queue non-empty. Fallback — callonCancel.handleInterrupt: if in teammate view, kills all agents + exits. Then callshandleCancel.handleKillAgents: first press shows "Press again" hint; second press within 3 000 ms (KILL_AGENTS_CONFIRM_WINDOW_MS) kills alllocal_agenttasks, emits SDK events, enqueues aggregate notification.isEscapeActive/isCtrlCActiveguards: skip if overlay, vim INSERT, transcript, history-search, help, etc.chat:killAgentsalways registered to prevent Ctrl+K (chord prefix) passing to readline.
Dependencies: useKeybinding, useAppState, useSetAppState, useCommandQueue, useNotifications, useIsOverlayActive, useCallback, useRef, killAllRunningAgentTasks, emitTaskTerminatedSdk
useSwarmPermissionPoller
File: hooks/useSwarmPermissionPoller.ts
Purpose: Polls every 500 ms for permission responses from the swarm leader when running as a worker agent. When a response arrives, it invokes the registered callback (onAllow or onReject).
Parameters: none
Return Value: void
Key Logic:
- Only active when
isSwarmWorker()returnstrue. - Uses
useInterval(usehooks-ts) withPOLL_INTERVAL_MS = 500. - For each
requestIdinpendingCallbacks, callspollForResponse(requestId, agentName, teamName). - On response: calls
processResponse(response)which invokes the callback, then callsremoveWorkerResponse. - Module-level
pendingCallbacks: Map<string, PermissionResponseCallback>andpendingSandboxCallbacks: Map<...>. - Exported helper functions:
registerPermissionCallback,unregisterPermissionCallback,hasPermissionCallback,clearAllPendingCallbacks,processMailboxPermissionResponse,registerSandboxPermissionCallback,hasSandboxPermissionCallback,processSandboxPermissionResponse.
Dependencies: useCallback, useEffect, useRef, useInterval, permissionSync
Swarm / Teammate Hooks
useSwarmInitialization
File: hooks/useSwarmInitialization.ts
Purpose: Initializes swarm features (teammate context and hooks) on mount. Handles both resumed sessions (teamName/agentName in transcript) and fresh spawns (environment variables).
Parameters:
setAppState: SetAppStateinitialMessages: Message[] | undefined{ enabled?: boolean }
Return Value: void
Key Logic:
- Checks
isAgentSwarmsEnabled()before doing anything. - Resumed session path: reads
teamName/agentNamefrominitialMessages[0], callsinitializeTeammateContextFromSession, reads team file to getagentId, callsinitializeTeammateHooks. - Fresh spawn path: calls
getDynamicTeamContext()to read env vars, then callsinitializeTeammateHooks.
Dependencies: useEffect
useTeammateViewAutoExit
File: hooks/useTeammateViewAutoExit.ts
Purpose: Auto-exits teammate viewing mode when the viewed teammate is killed, fails, encounters an error, or is evicted from the task map.
Parameters: none
Return Value: void
Key Logic:
- Selects only
viewingAgentTaskIdand the viewed task from AppState (avoids re-rendering on unrelated streaming updates). - Narrows the task to
InProcessTeammateTasktype. - Exits if task evicted, status is
killed,failed, or error is present. - Does NOT exit if status is
running,completed, orpending.
Dependencies: useEffect, useAppState, useSetAppState, exitTeammateView
useBackgroundTaskNavigation
File: hooks/useBackgroundTaskNavigation.ts
Purpose: Manages keyboard navigation of the background task list. Shift+Up/Down moves selection; Enter enters the view; f opens the full transcript; k kills the task; Escape exits.
Parameters: options?: { isActive?: boolean }
Return Value: { handleKeyDown: (key: Key, input: string) => void }
Key Logic:
- Reads the list of background tasks from AppState.
selectedIndexis clamped to[0, tasks.length - 1]whenever the list changes.- Enter: sets
viewingAgentTaskIdin AppState to the selected task's ID. f: setsshowFullTranscript = truein AppState.k: callskillTask(task.id).- Escape: calls
exitTeammateView(setAppState).
Dependencies: useAppState, useSetAppState, useState, useEffect, useCallback
useInboxPoller
File: hooks/useInboxPoller.ts
Purpose: Polls the team lead's inbox every 1 second (or on demand when idle) and routes messages. Handles permission requests/responses, sandbox permissions, plan approvals, shutdown handling, team permission updates, mode-set requests, and regular messages.
Parameters:
{ enabled: boolean, isLoading: boolean, focusedInputDialog: string | null, onSubmitMessage: (msg) => void }
Return Value: void
Key Logic:
- Uses
useIntervalwith 1 000 ms period; no-ops if!enabled. - Reads messages from the team lead's mailbox directory.
- Dispatches by message type:
permission_request→ adds totoolUseConfirmQueue.permission_response→ callsprocessMailboxPermissionResponse.sandbox_permission_request→ calls sandbox permission handler.sandbox_permission_response→ callsprocessSandboxPermissionResponse.plan_approval→ routes to plan approval handler.shutdown→ gracefully exits.team_permission_update→ updates AppState permission context.mode_set→ changes permission mode.- Regular messages → calls
onSubmitMessagewhen idle.
- Delivers pending messages only when
!isLoadingand no focused input dialog.
Dependencies: useInterval, useEffect, useRef, useAppState, useSetAppState, processMailboxPermissionResponse, processSandboxPermissionResponse
useTaskListWatcher
File: hooks/useTaskListWatcher.ts
Purpose: Watches a task list directory and automatically picks up open, unowned tasks to work on (tasks mode). Claims tasks atomically to prevent race conditions.
Parameters:
{ taskListId?: string, isLoading: boolean, onSubmitTask: (prompt: string) => boolean }
Return Value: void
Key Logic:
- Calls
ensureTasksDiron mount, thenwatch(tasksDir, debouncedCheck)with DEBOUNCE_MS=1000. - Uses stable refs for
isLoadingandonSubmitTaskto avoid Bun PathWatcherManager deadlock (oven-sh/bun#27469) by not recreating the watcher on every turn. checkForTasks: lists tasks, findsstatus=pending,owner=undefined, allblockedBycompleted; callsclaimTask(taskListId, task.id, agentId).- Formats task as
"Complete all open tasks. Start with task #N: ...\n\nDescription". - Additional
useEffectonisLoadingto trigger check when going idle.
Dependencies: fs.watch, useEffect, useRef
useTasksV2
File: hooks/useTasksV2.ts
Purpose: Exposes the current task list for the persistent TodoV2 UI. All consumers share a single TasksV2Store (singleton file-watcher) to avoid watcher churn.
Parameters: none
Return Value: Task[] | undefined — undefined when hidden (all completed for >5 s, or empty).
Key Logic:
TasksV2Storeclass: managesfs.watch,onTasksUpdatedsubscription, debounced fetch (DEBOUNCE_MS=50), hide timer (HIDE_DELAY_MS=5000), fallback poll (FALLBACK_POLL_MS=5000).getSnapshotreturnsundefinedwhen#hidden = true.useSyncExternalStoresubscription; store starts on first subscriber, stops on last unsubscribe.- Only active when
isTodoV2Enabled()and (no team context, or is team lead). useTasksV2WithCollapseEffect: same asuseTasksV2plus collapses the expanded task view in AppState when the list becomes hidden.
Dependencies: useSyncExternalStore, useEffect, useAppState, useSetAppState, fs.watch
useSessionBackgrounding
File: hooks/useSessionBackgrounding.ts
Purpose: Manages Ctrl+B backgrounding and foregrounding of the current session. When a task is foregrounded, it syncs that task's messages to the main message list.
Parameters: (large props including setMessages, setIsLoading, tools, etc.)
Return Value: { handleBackgroundSession: () => void }
Key Logic:
- On
handleBackgroundSession: if a task is running, backgrounds it (writes to AppState background tasks); otherwise foregrounds the first background task. - Foreground: injects the backgrounded task's messages into the main list via
setMessages, resumes the task's streams.
Dependencies: useCallback, useAppState, useSetAppState
useScheduledTasks
File: hooks/useScheduledTasks.ts
Purpose: Mounts the cron scheduler in the REPL. Fired tasks are enqueued via enqueuePendingNotification at later priority; teammate-scoped crons are injected directly into that teammate's message stream.
Parameters:
{ isLoading: boolean, assistantMode?: boolean, setMessages: Dispatch<SetStateAction<Message[]>> }
Return Value: void
Key Logic:
- Gated on
isKairosCronEnabled()at effect time. - Uses
isLoadingRefto avoid stale closures onisLoading. onFireTaskcallback: if task hasagentId, finds the teammate and callsinjectUserMessageToTeammate; otherwise creates aScheduledTaskFireMessageand enqueues the prompt.createCronScheduleris the shared scheduler core (used also byprint.tsfor headless mode).isKilledcallback pollsisKairosCronEnabled()each tick as a mid-session killswitch.
Dependencies: useEffect, useRef, useAppStateStore, useSetAppState, createCronScheduler
IDE Integration Hooks
useIDEIntegration
File: hooks/useIDEIntegration.tsx
Purpose: Manages IDE auto-connection on startup. Detects running IDEs, sets up dynamic MCP config for the found IDE server, and shows the IDE onboarding dialog if needed.
Parameters:
{ autoConnectIdeFlag, ideToInstallExtension, setDynamicMcpConfig, setShowIdeOnboarding, setIDEInstallationState }
Return Value: void
Key Logic:
- Calls
detectIDEs()on mount to find running IDE extension servers. - If found: calls
setDynamicMcpConfigto add the IDE's MCP server config. - Checks
settings.ideHintShownCountto decide whether to show onboarding. - Handles the
ideToInstallExtensionCLI flag for direct IDE extension install flows.
Dependencies: useEffect, useRef, useAppState
useIdeAtMentioned
File: hooks/useIdeAtMentioned.ts
Purpose: Listens for at_mentioned MCP notifications from the IDE extension and calls a callback with file/line context so Claude can reference the file.
Parameters:
mcpClients: MCPServerConnection[]onAtMentioned: (filePath: string, lineNumber?: number) => void
Return Value: void
Key Logic:
- Uses
getConnectedIdeClient(mcpClients)to find the IDE client. - Registers a notification handler for the
at_mentionedmethod viaideClient.client.setNotificationHandler. - Passes parsed
filePathandlineNumbertoonAtMentioned.
Dependencies: useEffect
useIdeConnectionStatus
File: hooks/useIdeConnectionStatus.ts
Purpose: Returns the current IDE connection status (connected, disconnected, pending, or null) and the IDE name.
Parameters:
mcpClients?: MCPServerConnection[]
Return Value: { status: IDEConnectionStatus | null, ideName: string | null }
Key Logic:
- Uses
useMemoovermcpClientsto find the IDE client by checkingisIdeClient(client). - Maps client connection state to the status enum.
Dependencies: useMemo
useIdeLogging
File: hooks/useIdeLogging.ts
Purpose: Registers a log_event MCP notification handler on the IDE client to forward IDE telemetry events to the analytics system.
Parameters:
mcpClients: MCPServerConnection[]
Return Value: void
Key Logic:
- Calls
getConnectedIdeClientto find the IDE client. - Registers a Zod-validated handler:
{ method: 'log_event', params: { eventName, eventData } }. - Calls
logEvent('tengu_ide_${eventName}', eventData).
Dependencies: useEffect, zod
useIdeSelection
File: hooks/useIdeSelection.ts
Purpose: Listens for selection_changed MCP notifications from the IDE and delivers them as IDESelection objects to the REPL.
Parameters:
mcpClients: MCPServerConnection[]onSelect: (selection: IDESelection) => void
Return Value: void
Key Logic:
- Finds IDE client, registers notification handler for
selection_changed. - Converts the raw notification payload to
IDESelectionformat{ filePath, text, lineStart, lineEnd, lineCount }.
Dependencies: useEffect
useDiffInIDE
File: hooks/useDiffInIDE.ts
Purpose: Opens a file diff in the connected IDE via MCP RPC. Handles user save/close/reject responses to finalize or revert the edit.
Parameters:
{ onChange, toolUseContext, filePath, edits, editMode }
Return Value: { closeTabInIDE, showingDiffInIDE, ideName, hasError }
Key Logic:
- Calls
ideClient.client.request('show_diff', { filePath, edits, ... })to open the diff in the IDE. - Waits for the IDE to respond with
saved,closed, orrejected. - On
saved: callsonChangeto apply the edit. - On
rejected: calls the abort controller. - Returns
closeTabInIDE()so the permission dialog can close the tab programmatically.
Dependencies: useState, useRef, useCallback, useEffect
Remote & Session Hooks
useDirectConnect
File: hooks/useDirectConnect.ts
Purpose: Manages a WebSocket connection to a DirectConnect server (local server mode). Routes inbound messages and permission requests between the server and the REPL.
Parameters:
{ config, setMessages, setIsLoading, setToolUseConfirmQueue, tools }
Return Value: UseDirectConnectResult — { isConnected, send }
Key Logic:
- Uses
directConnectManagerto manage the WebSocket lifecycle. - Translates inbound SDK messages to
Message[]format. - Handles tool permission requests by pushing to
setToolUseConfirmQueue. - Reconnects on disconnect with exponential backoff.
Dependencies: useEffect, useRef, useState
useSSHSession
File: hooks/useSSHSession.ts
Purpose: Wires an SSH session manager to the REPL. Handles reconnection, graceful shutdown on disconnect, and transcript message injection.
Parameters:
{ session, setMessages, setIsLoading, setToolUseConfirmQueue, tools }
Return Value: UseSSHSessionResult — { isConnected, disconnect }
Key Logic:
- Subscribes to SSH session events:
message,connect,disconnect,error. - On disconnect: injects a system message explaining the disconnect and showing reconnect options.
- On reconnect: injects a system message confirming reconnection.
- Handles graceful shutdown: drains pending messages before closing.
Dependencies: useEffect, useRef, useState
useRemoteSession
File: hooks/useRemoteSession.ts
Purpose: Full CCR (Claude Code Remote) WebSocket session management. Handles bidirectional message conversion, streaming tool uses, permission request/response flow, response timeout detection, session title updates, and subagent task counting.
Parameters: Large props object including:
config: AppConfigsetMessages: SetMessagessetIsLoading,setToolUseConfirmQueuetools: Tool[]onSessionTitleUpdate?: (title: string) => void
Return Value: UseRemoteSessionResult — { isConnected, sendMessage, sessionId, ... }
Key Logic:
- Connects to CCR WebSocket on mount, reconnects on disconnect.
- Converts
SDKMessagetypes to internalMessageformat on inbound. - Converts outbound messages to SDK format for CCR consumption.
- Manages streaming tool uses: accumulates
input_json_deltachunks, fires permission dialog ontool_usecompletion. - Response timeout: sets a flag after 30 s of no response from the model.
- Session title: subscribes to
session_title_updateevents and callsonSessionTitleUpdate. - Subagent task counting: tracks
subagent_start/subagent_endevents to count running agents.
Dependencies: useEffect, useState, useRef, useCallback, SessionsWebSocket
useAssistantHistory
File: hooks/useAssistantHistory.ts
Purpose: Lazy-loads older messages from a remote session's history as the user scrolls up in viewer-only mode.
Parameters:
{ config, setMessages, scrollRef, onPrepend }
Return Value: { maybeLoadOlder: () => Promise<void> }
Key Logic:
- On scroll-up event, calls
loadSessionHistory(sessionId, pageToken). - Prepends loaded messages to the message list.
- Chains viewport fill: if the loaded messages don't fill the viewport, immediately loads another page.
- Scroll anchoring: saves the current scroll position before prepending and restores it after.
- Shows a sentinel message at the top ("Beginning of conversation") once all pages are exhausted.
Dependencies: useCallback, useRef, useEffect
useMailboxBridge
File: hooks/useMailboxBridge.ts
Purpose: Bridges the mailbox message context to the REPL's submit function. Polls the mailbox on revision change when idle.
Parameters:
{ isLoading: boolean, onSubmitMessage: (msg) => void }
Return Value: void
Key Logic:
- Subscribes to
mailboxRevisionchanges in AppState. - When revision bumps and
!isLoading: callspollMailbox()and submits any pending messages viaonSubmitMessage.
Dependencies: useEffect, useRef, useAppState
useReplBridge
File: hooks/useReplBridge.tsx
Purpose: Full REPL bridge session management — the main hook wiring the REPL to the Claude API. Manages the full query execution loop, permission flow, streaming message assembly, compact operations, and bridge connectivity.
Parameters: Large props including tools, messages, setMessages, config, and many callbacks.
Return Value: Large result including { onQuery, isLoading, abortController, toolUseConfirmQueue, ... }
Key Logic: (file is >75k tokens; key points from reading the first 80 lines and the summary)
- Manages
abortControllerlifecycle — creates a new one per query, aborts on cancel. - Calls the streaming Claude API via
query.ts. - Assembles streaming
AssistantMessagefrom delta events. - Routes
tool_usetocanUseToolfor permission gating. - Handles compact boundary detection and auto-compact triggers.
- Integrates bridge callbacks for CCR permission relaying.
- Manages local session history recording.
Dependencies: useState, useRef, useCallback, useEffect, useMemo, useCanUseTool, useLogMessages, query, compact
useTeleportResume
File: hooks/useTeleportResume.tsx
Purpose: Manages the async lifecycle of teleporting into a remote Code Session: loading state, error state, selected session tracking, and the resumeSession callback.
Parameters:
source: TeleportSource—'cliArg' | 'localCommand'(for analytics).
Return Value: { resumeSession, isResuming, error, selectedSession, clearError }
Key Logic:
resumeSession(session): setsisResuming = true, logstengu_teleport_resume_session, callsteleportResumeCodeSession(session.id), setsteleportedSessionInfofor reliability logging.- On error: wraps in
TeleportResumeErrorwithisOperationErrorflag for UI differentiation. - Uses React Compiler (
_c) memoization.
Dependencies: useState, useCallback, teleportResumeCodeSession, setTeleportedSessionInfo
Plugin & Suggestion Hooks
usePromptSuggestion
File: hooks/usePromptSuggestion.ts
Purpose: Manages AI prompt completion suggestions: fetches a suggestion for the current input, tracks accept/ignore/submit outcomes, and logs telemetry.
Parameters:
{ inputValue: string, isAssistantResponding: boolean }
Return Value: { suggestion: string | null, markAccepted, markShown, logOutcomeAtSubmission }
Key Logic:
- Calls
generatePromptSuggestion(inputValue)debounced after 300 ms of no typing. markAccepted(): records that the user pressed Tab to accept.markShown(): records when the ghost-text suggestion becomes visible.logOutcomeAtSubmission(): called on submit; logsaccept(Tab was pressed),ignore(shown but not accepted), orno_suggestionoutcome.
Dependencies: useState, useRef, useCallback, useEffect, generatePromptSuggestion
usePromptsFromClaudeInChrome
File: hooks/usePromptsFromClaudeInChrome.tsx
Purpose: Listens for prompts sent from the Claude in Chrome extension via MCP notifications. Also syncs the current permission mode to the extension.
Parameters:
mcpClients: MCPServerConnection[]toolPermissionMode: PermissionMode
Return Value: void
Key Logic:
- Finds the Chrome extension MCP client.
- Registers a notification handler for
prompt_from_chrome. - Submits received prompts to the command queue.
- On
toolPermissionModechange: sends amode_changednotification back to the extension.
Dependencies: useEffect, useRef
usePrStatus
File: hooks/usePrStatus.ts
Purpose: Polls gh pr status every 60 seconds to detect review state changes on the current branch's PR.
Parameters:
isLoading: booleanenabled?: boolean
Return Value: PrStatusState — { reviewStatus: 'approved'|'changes_requested'|'pending'|null, prUrl: string | null }
Key Logic:
- Uses
useIntervalwith 60 000 ms period; skips poll whenisLoading. - Stops polling after 60 minutes of idle time (no new turns).
- Permanently disables if a fetch takes >4 seconds (likely no
ghbinary or no PR). - Runs
gh pr status --json reviewDecision,urlin a subprocess.
Dependencies: useInterval, useState, useRef
useClaudeCodeHintRecommendation
File: hooks/useClaudeCodeHintRecommendation.tsx
Purpose: Surfaces plugin install prompts from <claude-code-hint /> tags parsed from Claude's responses. Show-once semantics per plugin per session.
Parameters: none
Return Value: { recommendation: PluginRecommendation | null, handleResponse: (accepted: boolean) => void }
Key Logic:
- Monitors
messagesfor assistant messages containing<claude-code-hint plugin="name" />XML. - Uses
usePluginRecommendationBasestate machine to gate display. handleResponse(true): installs the plugin;false: dismisses.
Dependencies: usePluginRecommendationBase, useAppState, useEffect
useLspPluginRecommendation
File: hooks/useLspPluginRecommendation.tsx
Purpose: Recommends an LSP plugin when the user edits a file whose extension matches a supported language and the LSP binary is present.
Parameters: none
Return Value: { recommendation: PluginRecommendation | null, handleResponse: (accepted: boolean) => void }
Key Logic:
- Watches
messagesforFileEdit/FileWritetool result messages. - Extracts the file extension, checks if there's a matching LSP plugin.
- Uses
usePluginRecommendationBaseto avoid showing while another recommendation is active. - Show-once per session (tracked in AppState).
Dependencies: usePluginRecommendationBase, useAppState, useEffect
usePluginRecommendationBase
File: hooks/usePluginRecommendationBase.tsx
Purpose: Shared state machine for plugin recommendations. Guards against showing a recommendation while in remote mode, while another is already showing, or while a check is in-flight.
Parameters: generic T
Return Value: { recommendation: T | null, clearRecommendation, tryResolve: (candidate: T | null) => void }
Key Logic:
tryResolve(candidate): if remote mode or already showing, no-op; otherwise setsrecommendation.clearRecommendation(): clears the current recommendation.- Guards
inFlightref to prevent concurrent checks.
Dependencies: useState, useRef, useCallback
useOfficialMarketplaceNotification
File: hooks/useOfficialMarketplaceNotification.tsx
Purpose: Handles official marketplace auto-install on first launch and shows success/failure startup notifications.
Parameters: none
Return Value: void
Key Logic:
- On mount: checks
settings.autoInstallOfficialMarketplaceflag. - If set and not yet installed: calls
installOfficialMarketplace(). - Shows a
startuppriority notification on success or failure.
Dependencies: useEffect, useRef, useNotifications
useChromeExtensionNotification
File: hooks/useChromeExtensionNotification.tsx
Purpose: Shows startup notifications about the Chrome extension status: requires subscription, not installed, or default-enabled.
Parameters: none
Return Value: void
Key Logic:
- Uses
useStartupNotification(notifs/) internally. - Checks
chrome_extension_statusfrom settings/config. - Returns appropriate notification text for each status.
Dependencies: useStartupNotification
useClipboardImageHint
File: hooks/useClipboardImageHint.ts
Purpose: Shows a notification when the terminal gains focus and the clipboard contains an image. Debounced with 1 000 ms delay and a 30-second cooldown.
Parameters:
isFocused: booleanenabled: boolean
Return Value: void
Key Logic:
- Watches
isFocusedchanges. - On focus gain: checks clipboard via
navigator.clipboard.read()forimage/*MIME. - If image found: calls
addNotification({ key: 'clipboard-image', text: 'Image in clipboard · Ctrl+V to attach' }). - Cooldown: stores last-shown timestamp to avoid notification spam.
Dependencies: useEffect, useRef, useNotifications
useManagePlugins
File: hooks/useManagePlugins.ts — (same as above; see Core section for full details)
useIssueFlagBanner
File: hooks/useIssueFlagBanner.ts
Purpose: ANT-internal: shows an issue-flag banner after a session has friction signals (e.g. repeated tool retries) and has been active for at least 30 minutes with 3+ submits.
Parameters:
messages: readonly Message[]submitCount: number
Return Value: boolean — whether to show the banner.
Key Logic:
- Counts tool errors, retries, and refusals in recent messages.
- Only enabled for ANT internal users (checks
isAntInternal()). - 30-minute cooldown stored in localStorage.
Dependencies: useMemo, useRef
useQueueProcessor
File: hooks/useQueueProcessor.ts
Purpose: Processes queued commands from the unified command queue when no active query is running and no blocking UI is shown.
Parameters:
{ executeQueuedInput: (cmd: QueuedCommand) => void, hasActiveLocalJsxUI: boolean, queryGuard: () => boolean }
Return Value: void
Key Logic:
- Uses two
useSyncExternalStoresubscriptions: one for the command queue, one for the "is loading" state. - When the queue is non-empty,
!isLoading,!hasActiveLocalJsxUI, andqueryGuard()returns true: dequeues and executes the next command. - Uses
useEffectto trigger processing on state changes.
Dependencies: useSyncExternalStore, useEffect, messageQueueManager
useTurnDiffs
File: hooks/useTurnDiffs.ts
Purpose: Extracts per-turn file diffs from the message list for display in the /diff view. Uses incremental processing — only new messages are scanned on each render.
Parameters:
messages: Message[]
Return Value: TurnDiff[] — reverse-chronological list of turns that modified files.
Key Logic:
TurnDiff:{ turnIndex, userPromptPreview, timestamp, files: Map<string, TurnFileDiff>, stats }.- Detects turn boundaries from user messages that are not tool results and not
isMeta. - Collects
FileEdit/FileWritetool results within each turn. - New-file hunks: generates synthetic
+linehunks fromcontent. - Accumulated across edits to the same file in a turn.
- Cache ref holds
completedTurns+currentTurn+lastProcessedIndexfor O(n_new) processing.
Dependencies: useMemo, useRef
useSkillImprovementSurvey
File: hooks/useSkillImprovementSurvey.ts
Purpose: Manages the skill improvement survey dialog. Triggered by AppState.skillImprovementSurvey, applies improvements to the skills file on accept.
Parameters:
setMessages: SetMessages
Return Value: { isOpen: boolean, suggestion: SkillSuggestion | null, handleSelect: (selection) => void }
Key Logic:
- Reads
AppState.skillImprovementSurveyto get the pending survey. handleSelect('apply'): callsapplySkillImprovement(suggestion)and injects a system message.handleSelect('dismiss'): clears the survey from AppState.- On any selection: clears
AppState.skillImprovementSurvey.
Dependencies: useAppState, useSetAppState, useCallback
useGlobalKeybindings
File: hooks/useGlobalKeybindings.tsx
Purpose: React component (renders null) that registers global keybinding handlers for Ctrl+T (toggle todos), Ctrl+O (toggle transcript/messages), Ctrl+E (toggle show-all), and Escape/Ctrl+C (exit transcript).
Parameters: Props including screen, isLoading, isSearchingHistory, isHelpOpen, etc.
Return Value: null
Key Logic:
- Registers
view:toggleTasks,view:toggleTranscript,view:toggleShowAllbindings. - KAIROS feature flag gates:
view:toggleTasksonly active whenisTodoV2Enabled(). view:toggleTranscriptsetsexpandedView = 'messages'or'none'in AppState.view:toggleShowAllsetsshowAllMessagesin AppState.
Dependencies: useKeybinding, useAppState, useSetAppState
CommandKeybindingHandlers
File: hooks/useCommandKeybindings.tsx
Purpose: Registers all command:* keybinding actions as slash command submitters — e.g., command:compact, command:memory, command:config, etc.
Parameters: { onSubmit: (cmd: string) => void, isActive?: boolean }
Return Value: null
Key Logic:
- Calls
useKeybindingswith a map ofcommand:X→() => onSubmit('/X')entries. - Derives the slash command name from the keybinding action name.
Dependencies: useKeybindings
useAwaySummary
File: hooks/useAwaySummary.ts
Purpose: Appends a "while you were away" summary message after the terminal has been blurred for 5 minutes, when no turn is in progress.
Parameters:
messages: readonly Message[]setMessages: SetMessagesisLoading: boolean
Return Value: void
Key Logic:
- Gated on
feature('AWAY_SUMMARY')bundle flag andtengu_sedge_lanternGrowthBook flag. - Subscribes to
subscribeTerminalFocusfor blur/focus events. - On blur: starts a
BLUR_DELAY_MS = 5 * 60_000timer. - Timer fire: if still loading, sets
pendingRef = true(deferred); otherwise callsgenerate(). generate(): callsgenerateAwaySummary(messages, signal)→ appendscreateAwaySummaryMessage(text).- On focus: clears timer, aborts in-flight generation, clears
pendingRef. - Second
useEffectonisLoading: if!isLoadingandpendingRefand still blurred, firesgenerate(). hasSummarySinceLastUserTurn(): walks backward to prevent duplicate summaries.
Dependencies: useEffect, useRef, useCallback, subscribeTerminalFocus, generateAwaySummary
useAfterFirstRender / renderPlaceholder
See entry under "Core / Utility Hooks" for useAfterFirstRender.
Notification Hooks (notifs/)
All hooks in notifs/ use useNotifications() from context/notifications.js to push entries to the status bar notification queue. Most are gated on !getIsRemoteMode().
useStartupNotification
File: hooks/notifs/useStartupNotification.ts
Purpose: Base primitive for fire-once-on-mount notifications. Encapsulates the remote-mode gate and once-per-session ref guard used by most other notifs/ hooks.
Parameters:
compute: () => Result | Promise<Result>— returnsnullto skip,Notificationfor one,Notification[]for many.
Return Value: void
Key Logic:
hasRunRefprevents re-firing on re-render.- Runs
computeinsidePromise.resolve().then(...)to allow async. - Catches errors via
logError. - Skips entirely in remote mode.
Dependencies: useEffect, useRef, useNotifications
useAutoModeUnavailableNotification
File: hooks/notifs/useAutoModeUnavailableNotification.ts
Purpose: Shows a one-shot warning when the Shift+Tab mode carousel wraps past where "auto mode" would have been, explaining why auto mode is unavailable.
Parameters: none
Key Logic:
- Detects the wrap:
mode === 'default' && prevMode !== 'default' && prevMode !== 'auto' && !isAutoModeAvailable && hasAutoModeOptIn(). - Calls
getAutoModeUnavailableReason()to get the specific reason (circuit-breaker, org-allowlist, settings). shownRefprevents showing more than once per session.- Gated on
feature('TRANSCRIPT_CLASSIFIER').
useCanSwitchToExistingSubscription
File: hooks/notifs/useCanSwitchToExistingSubscription.tsx
Purpose: Shows up to 3 times (MAX_SHOW_COUNT=3) across sessions a notification prompting users who have a Claude Pro/Max subscription but are logged in via API key to run /login.
Key Logic:
- Reads
globalConfig.subscriptionNoticeCount; returns null if >= 3. - Calls
getOauthProfileFromApiKey()to check for Pro/Max subscription. - Increments
subscriptionNoticeCountin global config on each show. - Renders a JSX notification with
color="suggestion".
useDeprecationWarningNotification
File: hooks/notifs/useDeprecationWarningNotification.tsx
Purpose: Shows a color="warning" notification when the active model is deprecated.
Parameters: model: string
Key Logic:
- Calls
getModelDeprecationWarning(model)on eachmodelchange. - Uses
lastWarningRefto avoid re-adding the same notification on re-render. - Resets tracking if model changes to non-deprecated.
useFastModeNotification
File: hooks/notifs/useFastModeNotification.tsx
Purpose: Shows real-time notifications for fast mode state changes: cooldown started/expired, org-level enable/disable, and overage rejection.
Key Logic:
- Subscribes to
onCooldownTriggered,onCooldownExpired,onFastModeOverageRejection,onOrgFastModeChangedevent emitters. - On org-disabled while fast mode is active: disables fast mode in AppState.
- Shows immediate-priority notifications with
color="fastMode"orcolor="warning".
useIDEStatusIndicator
File: hooks/notifs/useIDEStatusIndicator.tsx
Purpose: Shows IDE connection status in the notification area: hint to install extension, JetBrains info, install error, or current selection preview.
Parameters: { ideInstallationStatus, ideSelection, mcpClients }
Key Logic:
- Uses
useIdeConnectionStatus(mcpClients)to get current status. - Shows "install extension" hint up to MAX_IDE_HINT_SHOW_COUNT=5 times (tracked in globalConfig).
- Shows JetBrains info notification (different flow than VS Code).
- Shows selection preview as a persistent notification when file/text is selected.
useInstallMessages
File: hooks/notifs/useInstallMessages.tsx
Purpose: Shows startup notifications for native installer issues (PATH not configured, alias not set, install errors).
Key Logic:
- Calls
checkInstall()to get installation messages. - Maps message types to priorities:
error/userActionRequired→high;path/alias→medium; others →low. - Colors:
error→color="error"; others →color="warning".
useLspInitializationNotification
File: hooks/notifs/useLspInitializationNotification.tsx
Purpose: Polls LSP server status every 5 000 ms and shows notifications when the LSP manager or individual servers fail to initialize.
Key Logic:
- Gated on
ENABLE_LSP_TOOLenv var. - Polls
getInitializationStatus()andgetLspServerManager(). - De-duplicates errors using
notifiedErrorsRefset. - Adds errors to
appState.plugins.errorsfor/doctordisplay.
useMcpConnectivityStatus
File: hooks/notifs/useMcpConnectivityStatus.tsx
Purpose: Shows notifications when MCP servers fail to connect or need authentication.
Parameters: { mcpClients?: MCPServerConnection[] }
Key Logic:
- Filters
mcpClientsby connection state:failed,needs_auth. - Separately tracks
claudeaiclients (connector) vs local clients (server). - Shows JSX notifications with counts and
· /mcpnavigation hint.
useModelMigrationNotifications
File: hooks/notifs/useModelMigrationNotifications.tsx
Purpose: Shows one-time notifications immediately after automatic model migrations (e.g. Sonnet 4.5 → 4.6, Opus Pro → Opus 4.6).
Key Logic:
- Uses
useStartupNotificationwith aMIGRATIONSarray of check functions. - Each check reads a timestamp field from
globalConfigand returns a notification if the timestamp is within the last 3 seconds (i.e., this is the launch that triggered the migration).
useNpmDeprecationNotification
File: hooks/notifs/useNpmDeprecationNotification.tsx
Purpose: Shows a 15-second warning notification when Claude Code is running via an npm install (deprecated) rather than the native installer.
Key Logic:
- Skips if
isInBundledMode()orDISABLE_INSTALLATION_CHECKSenv var is set. - Calls
getCurrentInstallationType(); skips for'development'installs.
usePluginAutoupdateNotification
File: hooks/notifs/usePluginAutoupdateNotification.tsx
Purpose: Subscribes to onPluginsAutoUpdated and shows a notification prompting the user to run /reload-plugins when plugins have been auto-updated in the background.
Key Logic:
useState([])forupdatedPluginslist.onPluginsAutoUpdatedsubscription fires with updated plugin IDs.- Extracts plugin names (strips
@marketplacesuffix) and shows JSX notification withcolor="success". - 10 000 ms timeout.
usePluginInstallationStatus
File: hooks/notifs/usePluginInstallationStatus.tsx
Purpose: Shows a notification when one or more plugins fail to install (from AppState plugins.installationStatus).
Key Logic:
- Reads
installationStatus.marketplacesandinstallationStatus.pluginsfrom AppState. - Filters by
status === 'failed', memoizes counts. - Shows
"N plugins failed to install · /plugin for details"withpriority: 'medium'.
useRateLimitWarningNotification
File: hooks/notifs/useRateLimitWarningNotification.tsx
Purpose: Shows rate limit warnings: (1) immediate notification when entering overage mode; (2) warning notification when approaching usage limits.
Parameters: model: string
Key Logic:
useClaudeAiLimits()for reactive limit data.getRateLimitWarning(limits, model)— string describing approaching limit.getUsingOverageText(limits)— string for overage mode.- Overage notification shown once per overage entry (tracked via
hasShownOverageNotificationstate). - Team/enterprise: skips overage notification unless user has billing access.
- Warning notification shown only when text changes (deduped via
shownWarningRef).
useSettingsErrors
File: hooks/notifs/useSettingsErrors.tsx
Purpose: Watches for settings validation errors (from getSettingsWithAllErrors) and shows/removes a warning notification in the status bar.
Return Value: ValidationError[] — the current list of errors (also used for /doctor display).
Key Logic:
- Initial state populated synchronously from
getSettingsWithAllErrors(). useSettingsChangesubscription: re-reads errors on file change.- Shows
"Found N settings issues · /doctor for details"with 60 000 ms timeout. - Removes notification when errors clear.
useTeammateShutdownNotification / useTeammateLifecycleNotification
File: hooks/notifs/useTeammateShutdownNotification.ts
Purpose: Fires batched spawn/shutdown notifications when in-process teammates start or complete. Uses fold() to combine "1 agent spawned" + "1 agent spawned" into "2 agents spawned".
Key Logic:
- Reads
tasksfrom AppState. - Tracks seen running/completed IDs in
seenRunningRef/seenCompletedRef. makeSpawnNotif(count)/makeShutdownNotif(count)with 5 000 ms timeout and fold function.- Exported as
useTeammateLifecycleNotification.
Tool Permission Subsystem (toolPermission/)
PermissionContext.ts
File: hooks/toolPermission/PermissionContext.ts
Purpose: Factory for creating a PermissionContext object — the shared context passed to all three permission handlers. Contains all callbacks needed to approve, deny, log, queue, and persist permission decisions.
Exported Functions:
createPermissionContext(tool, input, toolUseContext, assistantMessage, toolUseID, setToolPermissionContext, queueOps?) → PermissionContextcreatePermissionQueueOps(setToolUseConfirmQueue) → PermissionQueueOps— bridges React state setter to the generic queue interface.createResolveOnce<T>(resolve) → ResolveOnce<T>— atomic check-and-mark-as-resolved guard for races.
PermissionContext methods:
logDecision(args, opts?)— delegates tologPermissionDecision.logCancelled()— logstengu_tool_use_cancelledevent.persistPermissions(updates)— callspersistPermissionUpdatesand updates AppState.resolveIfAborted(resolve)— short-circuits if abort signal is fired.cancelAndAbort(feedback?, isAbort?, contentBlocks?)— builds a deny decision and aborts the controller if appropriate.tryClassifier(pendingCheck, updatedInput)— awaits classifier auto-approval (bash only;BASH_CLASSIFIERfeature flag).runHooks(permissionMode, suggestions, updatedInput?, startTimeMs?)— executes PermissionRequest hooks sequentially.buildAllow(updatedInput, opts?)→PermissionAllowDecisionbuildDeny(message, reason)→PermissionDenyDecisionhandleUserAllow(updatedInput, permissionUpdates, feedback?, startTimeMs?, contentBlocks?, decisionReason?)— persists updates, logs, returns allow decision.handleHookAllow(finalInput, permissionUpdates, startTimeMs?)— same for hook-sourced allows.pushToQueue(item),removeFromQueue(),updateQueueItem(patch)— queue management viaqueueOps.
permissionLogging.ts
File: hooks/toolPermission/permissionLogging.ts
Purpose: Centralized analytics and telemetry logging for all tool permission decisions. Fans out to Statsig (logEvent), OTel telemetry, code-edit metrics, and the toolUseContext.toolDecisions map.
Exported Functions:
logPermissionDecision(ctx, args, startTimeMs?)— main entry point.isCodeEditingTool(toolName)— checks if tool is Edit/Write/NotebookEdit.buildCodeEditToolAttributes(tool, input, decision, source)— builds OTel attributes including language from file path.
Analytics Events:
tengu_tool_use_granted_in_config— auto-approved by settings allowlist.tengu_tool_use_granted_in_prompt_permanent/_temporary— user approved.tengu_tool_use_granted_by_permission_hook— hook approved.tengu_tool_use_granted_by_classifier— classifier approved.tengu_tool_use_rejected_in_prompt— any rejection.tengu_tool_use_denied_in_config— denied by settings denylist.
handlers/coordinatorHandler.ts
File: hooks/toolPermission/handlers/coordinatorHandler.ts
Purpose: Handles the coordinator-worker permission flow: runs hooks then classifier (both awaited sequentially) before falling through to the interactive dialog.
Exported: handleCoordinatorPermission(params) → Promise<PermissionDecision | null>
Parameters: CoordinatorPermissionParams — { ctx, pendingClassifierCheck?, updatedInput, suggestions, permissionMode }
Logic:
await ctx.runHooks(...)— if hooks return a decision, return it.- If
BASH_CLASSIFIERflag:await ctx.tryClassifier?.(...)— if classifier returns, return it. - Return
null→ caller falls through tohandleInteractivePermission. - On unexpected error: logs and returns null (graceful fallback to dialog).
handlers/interactiveHandler.ts
File: hooks/toolPermission/handlers/interactiveHandler.ts
Purpose: Handles the interactive (main-agent) permission flow. Sets up the ToolUseConfirm queue entry with all callbacks and races user interaction against background automated checks (hooks, classifier, bridge, channel).
Exported: handleInteractivePermission(params, resolve) → void (synchronous setup)
Key Logic:
- Creates a
PermissionConfirmqueue entry with callbacks:onAbort,onAllow,onReject,recheckPermission,onUserInteraction,onDismissCheckmark. createResolveOnceguard ensures only the first resolution wins.userInteractedflag: prevents classifier from auto-approving after user interaction (200 ms grace period).- Race 1 — User:
onAllow/onReject/onAbortcallbacks. - Race 2 — Hooks: async
ctx.runHooks(...)— if win, removes from queue, resolves. - Race 3 — Classifier:
executeAsyncClassifierCheck(...)— on allow, shows checkmark UI for 3 s (focused) or 1 s (blurred), then removes from queue. - Race 4 — Bridge (CCR): sends
permission_requestto CCR; subscribes to CCR response; on win, logs, resolves. - Race 5 — Channel: sends structured
permission_requestto all active channel MCP servers (Telegram, iMessage); subscribes to response; on win, resolves. - Checkmark dismissal:
onDismissCheckmarkallows user to press Escape during the checkmark window. - Abort: if abort signal fires mid-dialog,
claim()races to resolve with cancel.
handlers/swarmWorkerHandler.ts
File: hooks/toolPermission/handlers/swarmWorkerHandler.ts
Purpose: Handles the swarm-worker permission flow: tries classifier auto-approval, then forwards the request to the team leader via mailbox. Awaits the leader's response.
Exported: handleSwarmWorkerPermission(params) → Promise<PermissionDecision | null>
Logic:
- Returns
nullif notisAgentSwarmsEnabled()or notisSwarmWorker(). - If
BASH_CLASSIFIER: triesctx.tryClassifier?.(...). - Creates a
Promise<PermissionDecision>that resolves when the leader responds. - Registers
onAllow/onRejectcallbacks viaregisterPermissionCallback. - Calls
sendPermissionRequestViaMailbox(request)to notify the leader. - Sets
AppState.pendingWorkerRequestfor visual indicator. - On abort: resolves with
cancelAndAbort. - On error: returns
null(fallback to local UI handling).
Non-Hook Utilities in hooks/
These files live in hooks/ but are not React hooks.
fileSuggestions.ts
File: hooks/fileSuggestions.ts
Exports:
generateFileSuggestions(query, cwd, ...) → Promise<SuggestionItem[]>— main entry point. Manages aFileIndexsingleton (native Rust/nucleo), fetches tracked files viagit ls-files, falls back toripgrep. Returns up to 15 scored matches.startBackgroundCacheRefresh(cwd)— queues a background refresh of untracked files.clearFileSuggestionCaches()— called on/clearto reset the index.applyFileSuggestion(suggestion, inputValue, cursorOffset) → string— replaces the@tokenin the input with the chosen file path.findLongestCommonPrefix(suggestions) → string— used for Tab-autocomplete of common prefix.onIndexBuildComplete(callback)— notifies when background index is built.
Key Design:
- Path signature (mtime + size) invalidates cache without full rebuild.
.ignore/.rgignorefile support.- Directory name extraction for
@dir/completions.
unifiedSuggestions.ts
File: hooks/unifiedSuggestions.ts
Exports:
generateUnifiedSuggestions(query, mcpResources, agents, showOnEmpty) → Promise<SuggestionItem[]>— merges file suggestions (nucleo), MCP resource suggestions (Fuse.js), and agent suggestions into a ranked list of up to 15 items.
Key Design:
- File suggestions use nucleo score (0–1 float).
- MCP resource suggestions use Fuse.js score (lower = better, inverted for sorting).
- Agent suggestions always appended at lower priority.
renderPlaceholder.ts
File: hooks/renderPlaceholder.ts
Exports:
renderPlaceholder(placeholder, hidePlaceholderText?, cursorChar?) → string— pure function that renders placeholder text with a cursor character appended. WhenhidePlaceholderText = true(voice recording mode), returns only the cursor.