/**
 * Interactive fuzzy-filter picker built on @inquirer/core.
 *
 * Provides a searchable, paginated list UI with optional preview pane
 * for selecting items in the terminal. Used by session picker, command
 * picker, and other interactive selection flows.
 */
/**
 * Custom inquirer prompt for searchable, scrollable selection lists.
 *
 * Extends @inquirer/core to support type-ahead filtering, column-aligned
 * display, and keyboard navigation. Used by sessions, teams, and other
 * interactive pickers throughout the CLI.
 */
import { Separator } from '@inquirer/core';
/** Configuration for the interactive picker prompt. */
export interface PickerConfig<T> {
    message: string;
    /** Optional dim hint line rendered directly under the header (above the rows). */
    subtitle?: string;
    /**
     * The row pool. A {@link Separator} entry renders as a non-selectable divider
     * (used for group headers) — navigation skips it and it is never returned.
     */
    items: Array<T | Separator>;
    filter: (query: string) => Array<T | Separator>;
    labelFor: (item: T, query: string) => string;
    buildPreview?: (item: T) => string;
    /**
     * Called once with a repaint trigger for the open prompt. An async preview
     * source (e.g. a remote row's digest arriving over SSH) invokes the trigger
     * when data `buildPreview` reported as pending is now ready, so the pane
     * refreshes without a keypress. The trigger is inert after the prompt closes.
     */
    registerPreviewRepaint?: (repaint: () => void) => void;
    shortIdFor?: (item: T) => string;
    /**
     * Prefix each selectable row with its 1-based position in the current
     * filtered list (`  1.`, ` 12.`), right-aligned so the labels stay columnar
     * and a user scanning a long list can tell where they are. Separators are
     * never numbered.
     */
    numbered?: boolean;
    pageSize?: number;
    initialSearch?: string;
    emptyMessage?: string;
    enterHint?: string;
    /**
     * Lines the caller already printed above the Inquirer prompt (e.g. the
     * hidden-session footer). Subtracted from the row budget so the list page is
     * capped to keep the preview — and those notices — on screen together.
     */
    linesAbovePrompt?: number;
}
/** The result returned when the user selects an item. */
export interface PickedItem<T> {
    item: T;
}
/** Configuration for the multi-select picker prompt. */
export interface MultiPickerConfig<T> {
    message: string;
    items: T[];
    filter: (query: string) => T[];
    labelFor: (item: T, query: string) => string;
    /** Stable identity for an item — drives the selected set. */
    keyFor: (item: T) => string;
    buildPreview?: (item: T) => string;
    pageSize?: number;
    initialSearch?: string;
    emptyMessage?: string;
    enterHint?: string;
    /** See {@link PickerConfig.linesAbovePrompt}. */
    linesAbovePrompt?: number;
}
/**
 * Rows the detail preview is guaranteed when it is open and a row is selected.
 * The list page is capped so this floor always fits the viewport — without it a
 * long list (PICKER_RECENT_COUNT = 15) consumes the whole default 24-row
 * terminal, `availablePreviewRows` goes <= 0, and the preview silently collapses
 * to empty (RUSH-2198).
 */
export declare const PREVIEW_MIN_ROWS = 6;
/** Floor for the visible list page, so a short terminal still shows a few rows. */
export declare const PICKER_MIN_LIST_ROWS = 3;
/**
 * Cap the visible list page so an open preview keeps a guaranteed floor of rows.
 *
 * The picker renders header + list page + separator + preview + help. When the
 * requested page size (e.g. 15) is large enough to fill the terminal on its own,
 * the preview has no room left and collapses. This reserves
 * {@link PREVIEW_MIN_ROWS} (plus its separator) for the preview and hands the
 * list whatever remains, never below {@link PICKER_MIN_LIST_ROWS}.
 *
 * `chromeRows` counts the fixed non-list, non-preview lines (header, subtitle,
 * help, any flash). `linesAbovePrompt` counts lines the caller printed above the
 * Inquirer prompt that have scrolled the viewport but the picker cannot measure —
 * today the session picker passes the hidden-session footer; subtracting it keeps
 * that notice on screen alongside the preview. (The fleet browser folds its
 * unreachable-peer warning into the header instead, so it needs no reserve here.)
 */
export declare function pickerPageSize(opts: {
    requestedPageSize: number;
    terminalRows: number;
    chromeRows: number;
    previewOpen: boolean;
    linesAbovePrompt?: number;
    previewMinRows?: number;
    minListRows?: number;
}): number;
/** Clip a picker preview so the full prompt can fit in the terminal viewport. */
export declare function limitPreviewHeight(preview: string, maxRows: number, width: number): string;
/** Show an interactive fuzzy-filter picker and return the selected item, or null on cancel. */
export declare function itemPicker<T>(config: PickerConfig<T>): Promise<PickedItem<T> | null>;
/**
 * Multi-select variant of {@link itemPicker}. Same searchable, paginated list
 * and preview pane, but `space` toggles a checkbox on the active row instead of
 * the preview (preview moves to `tab`), and `enter` confirms every checked row.
 *
 * Returns the selected items (in the config's `items` order) or `null` on
 * cancel. Pressing `enter` with nothing checked confirms just the highlighted
 * row, so a quick single-pick still works.
 */
export declare function multiItemPicker<T>(config: MultiPickerConfig<T>): Promise<T[] | null>;
/** Configuration for the dynamic (async-refetch) picker prompt. */
export interface DynamicPickerConfig<T, F, A = never> {
    message: string;
    /** The initial filter state. Changing it (via a keybinding) re-runs {@link load}. */
    initialFilter: F;
    /** Async loader for the current filter state. Its result is the row pool. */
    load: (filter: F) => Promise<T[]>;
    labelFor: (item: T, query: string) => string;
    /** Stable identity for an item (used for the active-row cursor across reloads). */
    keyFor: (item: T) => string;
    /** Client-side text filter over the loaded pool (the `S` search). */
    matches?: (item: T, query: string) => boolean;
    buildPreview?: (item: T) => string;
    /** See {@link PickerConfig.registerPreviewRepaint}. */
    registerPreviewRepaint?: (repaint: () => void) => void;
    /** Dim summary of the current filter state, rendered in the header. */
    headerFor?: (filter: F) => string;
    /** The hotkey-legend help line; receives the mode so it can adapt. */
    helpFor?: (filter: F, mode: 'nav' | 'search') => string;
    /**
     * Single-key bindings (by key name) that transform the filter. Returning the
     * SAME reference is a no-op; a new object triggers a reload.
     */
    keyBindings?: Record<string, (filter: F) => F>;
    /** Keys that submit the highlighted row with an alternate typed action. */
    submitKeys?: Record<string, A>;
    /**
     * Side-effecting keys that don't change the filter (e.g. `y` copies a command).
     * Receives the live search `query` so the effect can be search-aware. Return a
     * short string to flash under the list, or `{ flash, reload }` when the effect
     * changed something the rows RENDER (a star, a mark) and the list has to be
     * rebuilt — the row labels are memoized, so a flash alone leaves them stale.
     */
    onKey?: (name: string, filter: F, active: T | undefined, query: string) => string | void | {
        flash?: string;
        reload?: boolean;
    };
    /** Key that enters search mode (default `s`). */
    searchKey?: string;
    /** Key that toggles the preview pane (default `tab`). */
    previewKey?: string;
    pageSize?: number;
    emptyMessage?: string;
    loadingMessage?: string;
    enterHint?: string;
    /** See {@link PickerConfig.linesAbovePrompt}. */
    linesAbovePrompt?: number;
}
/**
 * The lookup token for a hotkey: the literal character the key produced, else
 * readline's key name (`tab`, `escape`, arrows).
 *
 * readline reports both `f` and `F` as name `f` — only `sequence` tells them
 * apart — and gives a punctuation key like `*` no name at all. Keying on the
 * character makes shifted letters and punctuation bindable, and is a no-op for
 * every existing binding: for a plain lowercase letter, sequence === name.
 *
 * Callers receiving this in `onKey` see the literal character, so a handler that
 * wants to accept both cases of a letter must say so (`'y'` and `'Y'`); the
 * keyBindings lookup falls back to the key NAME, which keeps the shifted form of
 * an existing single-letter binding working without each caller restating it.
 */
export declare function hotkeyToken(key: {
    name?: string;
    sequence?: string;
    ctrl?: boolean;
    meta?: boolean;
}): string;
/** The result returned when the user selects a row: the item plus the live filter. */
export interface DynamicPicked<T, F, A = never> {
    item: T;
    filter: F;
    action?: A;
}
/**
 * Async-refetch variant of {@link itemPicker}. Holds a `filter` object in state and
 * re-runs `load(filter)` whenever a keybinding mutates it (with a loading placeholder
 * while the fetch — e.g. an SSH fleet fan-out — is in flight). A separate `S` search
 * mode filters the loaded pool client-side. `enter` returns the active row + the live
 * filter; `esc` cancels (from search mode, `esc` first exits search).
 *
 * Same render/pagination/preview machinery as the static pickers — only the data
 * source and keymap are dynamic.
 */
export declare function dynamicPicker<T, F, A = never>(config: DynamicPickerConfig<T, F, A>): Promise<DynamicPicked<T, F, A> | null>;
