π File detail
types/textInputTypes.ts
π― Use case
This file lives under βtypes/β, which covers shared TypeScript types and generated typings. On the API surface it exposes InlineGhostText, BaseTextInputProps, VimTextInputProps, VimMode, and BaseInputState (and more) β mainly types, interfaces, or factory objects. Dependencies touch @anthropic-ai, crypto, and React UI. It composes internal code from entrypoints, ink, utils, ids, and message (relative imports).
Generated from folder role, exports, dependency roots, and inline comments β not hand-reviewed for every path.
π§ Inline summary
import type { ContentBlockParam } from '@anthropic-ai/sdk/resources/messages.mjs' import type { UUID } from 'crypto' import type React from 'react' import type { PermissionResult } from '../entrypoints/agentSdkTypes.js' import type { Key } from '../ink.js'
π€ Exports (heuristic)
InlineGhostTextBaseTextInputPropsVimTextInputPropsVimModeBaseInputStateTextInputStateVimInputStatePromptInputModeEditablePromptInputModeQueuePriorityQueuedCommandisValidImagePastegetImagePasteIdsOrphanedPermission
π External import roots
Package roots from from "β¦" (relative paths omitted).
@anthropic-aicryptoreact
π₯οΈ Source preview
import type { ContentBlockParam } from '@anthropic-ai/sdk/resources/messages.mjs'
import type { UUID } from 'crypto'
import type React from 'react'
import type { PermissionResult } from '../entrypoints/agentSdkTypes.js'
import type { Key } from '../ink.js'
import type { PastedContent } from '../utils/config.js'
import type { ImageDimensions } from '../utils/imageResizer.js'
import type { TextHighlight } from '../utils/textHighlighting.js'
import type { AgentId } from './ids.js'
import type { AssistantMessage, MessageOrigin } from './message.js'
/**
* Inline ghost text for mid-input command autocomplete
*/
export type InlineGhostText = {
/** The ghost text to display (e.g., "mit" for /commit) */
readonly text: string
/** The full command name (e.g., "commit") */
readonly fullCommand: string
/** Position in the input where the ghost text should appear */
readonly insertPosition: number
}
/**
* Base props for text input components
*/
export type BaseTextInputProps = {
/**
* Optional callback for handling history navigation on up arrow at start of input
*/
readonly onHistoryUp?: () => void
/**
* Optional callback for handling history navigation on down arrow at end of input
*/
readonly onHistoryDown?: () => void
/**
* Text to display when `value` is empty.
*/
readonly placeholder?: string
/**
* Allow multi-line input via line ending with backslash (default: `true`)
*/
readonly multiline?: boolean
/**
* Listen to user's input. Useful in case there are multiple input components
* at the same time and input must be "routed" to a specific component.
*/
readonly focus?: boolean
/**
* Replace all chars and mask the value. Useful for password inputs.
*/
readonly mask?: string
/**
* Whether to show cursor and allow navigation inside text input with arrow keys.
*/
readonly showCursor?: boolean
/**
* Highlight pasted text
*/
readonly highlightPastedText?: boolean
/**
* Value to display in a text input.
*/
readonly value: string
/**
* Function to call when value updates.
*/
readonly onChange: (value: string) => void
/**
* Function to call when `Enter` is pressed, where first argument is a value of the input.
*/
readonly onSubmit?: (value: string) => void
/**
* Function to call when Ctrl+C is pressed to exit.
*/
readonly onExit?: () => void
/**
* Optional callback to show exit message
*/
readonly onExitMessage?: (show: boolean, key?: string) => void
/**
* Optional callback to show custom message
*/
// readonly onMessage?: (show: boolean, message?: string) => void
/**
* Optional callback to reset history position
*/
readonly onHistoryReset?: () => void
/**
* Optional callback when input is cleared (e.g., double-escape)
*/
readonly onClearInput?: () => void
/**
* Number of columns to wrap text at
*/
readonly columns: number
/**
* Maximum visible lines for the input viewport. When the wrapped input
* exceeds this many lines, only lines around the cursor are rendered.
*/
readonly maxVisibleLines?: number
/**
* Optional callback when an image is pasted
*/
readonly onImagePaste?: (
base64Image: string,
mediaType?: string,
filename?: string,
dimensions?: ImageDimensions,
sourcePath?: string,
) => void
/**
* Optional callback when a large text (over 800 chars) is pasted
*/
readonly onPaste?: (text: string) => void
/**
* Callback when the pasting state changes
*/
readonly onIsPastingChange?: (isPasting: boolean) => void
/**
* Whether to disable cursor movement for up/down arrow keys
*/
readonly disableCursorMovementForUpDownKeys?: boolean
/**
* Skip the text-level double-press escape handler. Set this when a
* keybinding context (e.g. Autocomplete) owns escape β the keybinding's
* stopImmediatePropagation can't shield the text input because child
* effects register useInput listeners before parent effects.
*/
readonly disableEscapeDoublePress?: boolean
/**
* The offset of the cursor within the text
*/
readonly cursorOffset: number
/**
* Callback to set the offset of the cursor
*/
onChangeCursorOffset: (offset: number) => void
/**
* Optional hint text to display after command input
* Used for showing available arguments for commands
*/
readonly argumentHint?: string
/**
* Optional callback for undo functionality
*/
readonly onUndo?: () => void
/**
* Whether to render the text with dim color
*/
readonly dimColor?: boolean
/**
* Optional text highlights for search results or other highlighting
*/
readonly highlights?: TextHighlight[]
/**
* Optional custom React element to render as placeholder.
* When provided, overrides the standard `placeholder` string rendering.
*/
readonly placeholderElement?: React.ReactNode
/**
* Optional inline ghost text for mid-input command autocomplete
*/
readonly inlineGhostText?: InlineGhostText
/**
* Optional filter applied to raw input before key routing. Return the
* (possibly transformed) input string; returning '' for a non-empty
* input drops the event.
*/
readonly inputFilter?: (input: string, key: Key) => string
}
/**
* Extended props for VimTextInput
*/
export type VimTextInputProps = BaseTextInputProps & {
/**
* Initial vim mode to use
*/
readonly initialMode?: VimMode
/**
* Optional callback for mode changes
*/
readonly onModeChange?: (mode: VimMode) => void
}
/**
* Vim editor modes
*/
export type VimMode = 'INSERT' | 'NORMAL'
/**
* Common properties for input hook results
*/
export type BaseInputState = {
onInput: (input: string, key: Key) => void
renderedValue: string
offset: number
setOffset: (offset: number) => void
/** Cursor line (0-indexed) within the rendered text, accounting for wrapping. */
cursorLine: number
/** Cursor column (display-width) within the current line. */
cursorColumn: number
/** Character offset in the full text where the viewport starts (0 when no windowing). */
viewportCharOffset: number
/** Character offset in the full text where the viewport ends (text.length when no windowing). */
viewportCharEnd: number
// For paste handling
isPasting?: boolean
pasteState?: {
chunks: string[]
timeoutId: ReturnType<typeof setTimeout> | null
}
}
/**
* State for text input
*/
export type TextInputState = BaseInputState
/**
* State for vim input with mode
*/
export type VimInputState = BaseInputState & {
mode: VimMode
setMode: (mode: VimMode) => void
}
/**
* Input modes for the prompt
*/
export type PromptInputMode =
| 'bash'
| 'prompt'
| 'orphaned-permission'
| 'task-notification'
export type EditablePromptInputMode = Exclude<
PromptInputMode,
`${string}-notification`
>
/**
* Queue priority levels. Same semantics in both normal and proactive mode.
*
* - `now` β Interrupt and send immediately. Aborts any in-flight tool
* call (equivalent to Esc + send). Consumers (print.ts,
* REPL.tsx) subscribe to queue changes and abort when they
* see a 'now' command.
* - `next` β Mid-turn drain. Let the current tool call finish, then
* send this message between the tool result and the next API
* round-trip. Wakes an in-progress SleepTool call.
* - `later` β End-of-turn drain. Wait for the current turn to finish,
* then process as a new query. Wakes an in-progress SleepTool
* call (query.ts upgrades the drain threshold after sleep so
* the message is attached to the same turn).
*
* The SleepTool is only available in proactive mode, so "wakes SleepTool"
* is a no-op in normal mode.
*/
export type QueuePriority = 'now' | 'next' | 'later'
/**
* Queued command type
*/
export type QueuedCommand = {
value: string | Array<ContentBlockParam>
mode: PromptInputMode
/** Defaults to the priority implied by `mode` when enqueued. */
priority?: QueuePriority
uuid?: UUID
orphanedPermission?: OrphanedPermission
/** Raw pasted contents including images. Images are resized at execution time. */
pastedContents?: Record<number, PastedContent>
/**
* The input string before [Pasted text #N] placeholders were expanded.
* Used for ultraplan keyword detection so pasted content containing the
* keyword does not trigger a CCR session. Falls back to `value` when
* unset (bridge/UDS/MCP sources have no paste expansion).
*/
preExpansionValue?: string
/**
* When true, the input is treated as plain text even if it starts with `/`.
* Used for remotely-received messages (e.g. bridge/CCR) that should not
* trigger local slash commands or skills.
*/
skipSlashCommands?: boolean
/**
* When true, slash commands are dispatched but filtered through
* isBridgeSafeCommand() β 'local-jsx' and terminal-only commands return
* a helpful error instead of executing. Set by the Remote Control bridge
* inbound path so mobile/web clients can run skills and benign commands
* without re-exposing the PR #19134 bug (/model popping the local picker).
*/
bridgeOrigin?: boolean
/**
* When true, the resulting UserMessage gets `isMeta: true` β hidden in the
* transcript UI but visible to the model. Used by system-generated prompts
* (proactive ticks, teammate messages, resource updates) that route through
* the queue instead of calling `onQuery` directly.
*/
isMeta?: boolean
/**
* Provenance of this command. Stamped onto the resulting UserMessage so the
* transcript records origin structurally (not just via XML tags in content).
* undefined = human (keyboard).
*/
origin?: MessageOrigin
/**
* Workload tag threaded through to cc_workload= in the billing-header
* attribution block. The queue is the async boundary between the cron
* scheduler firing and the turn actually running β a user prompt can slip
* in between β so the tag rides on the QueuedCommand itself and is only
* hoisted into bootstrap state when THIS command is dequeued.
*/
workload?: string
/**
* Agent that should receive this notification. Undefined = main thread.
* Subagents run in-process and share the module-level command queue; the
* drain gate in query.ts filters by this field so a subagent's background
* task notifications don't leak into the coordinator's context (PR #18453
* unified the queue but lost the isolation the dual-queue accidentally had).
*/
agentId?: AgentId
}
/**
* Type guard for image PastedContent with non-empty data. Empty-content
* images (e.g. from a 0-byte file drag) yield empty base64 strings that
* the API rejects with `image cannot be empty`. Use this at every site
* that converts PastedContent β ImageBlockParam so the filter and the
* ID list stay in sync.
*/
export function isValidImagePaste(c: PastedContent): boolean {
return c.type === 'image' && c.content.length > 0
}
/** Extract image paste IDs from a QueuedCommand's pastedContents. */
export function getImagePasteIds(
pastedContents: Record<number, PastedContent> | undefined,
): number[] | undefined {
if (!pastedContents) {
return undefined
}
const ids = Object.values(pastedContents)
.filter(isValidImagePaste)
.map(c => c.id)
return ids.length > 0 ? ids : undefined
}
export type OrphanedPermission = {
permissionResult: PermissionResult
assistantMessage: AssistantMessage
}