import type { ChannelSetupChoice, ChannelSetupChoiceOptions } from "#setup/cli/index.js"; import type { SearchActionOption } from "#setup/cli/select-state.js"; import type { ProviderPickerChoice, ProviderPickerRequest } from "#setup/flows/provider.js"; import type { PlannerNavigation, SelectMetadata, SelectNotice } from "#setup/prompter.js"; import type { SetupPanelOption } from "./setup-panel.js"; export type SetupEditableSelectResult = { kind: "selected"; value: string; } | { kind: "edited"; value: string; text: string; }; interface SetupSelectRequestBase { message: string; helpText?: string; description?: string; metadata?: readonly SelectMetadata[]; options: readonly SetupPanelOption[]; notices?: readonly SelectNotice[]; navigation?: PlannerNavigation; } interface SetupSingleSelectRequest extends SetupSelectRequestBase { kind: "single" | "stacked" | "task-list"; initialValue?: string; } interface SetupSearchAction extends SearchActionOption { load?(query: string): Promise; } interface SetupSearchSelectRequest extends SetupSelectRequestBase { kind: "search"; layout?: "task-list"; initialValue?: string; placeholder?: string; searchAction?: SetupSearchAction; } interface SetupMultiSelectRequest extends SetupSelectRequestBase { kind: "multi"; initialValues?: readonly string[]; required: boolean; } interface SetupSearchableMultiSelectRequest extends SetupSelectRequestBase { kind: "searchable-multi"; layout?: "stacked"; initialValues?: readonly string[]; placeholder?: string; required: boolean; } /** * A setup select's complete interaction grammar. The discriminant prevents * callers from combining incompatible modes; searchable multi-select supports * the stable stacked checklist layout but not single-select task actions. */ export type SetupSelectRequest = SetupSingleSelectRequest | SetupSearchSelectRequest | SetupMultiSelectRequest | SetupSearchableMultiSelectRequest; export type SetupSelectResult = readonly string[] | { kind: "navigate"; direction: "back" | "forward"; values: readonly string[]; } | undefined; export type SetupFlowInterrupt = "escape" | "ctrl-c"; export interface SetupFlowRenderer { begin(title: string): void; /** Sets progress owned by an enclosing setup journey, independent of its active question. */ setNavigation?(navigation: PlannerNavigation | undefined): void; end(options?: { preserveDiagnostics?: boolean; }): void; readSelect(options: SetupSelectRequest): Promise; readEditableSelect(options: { message: string; options: readonly SetupPanelOption[]; initialValue?: string; editable: { value: string; defaultValue: string; formatHint: (value: string) => string; validate?: (value: string) => string | undefined; }; }): Promise; /** Provider-only picker with masked async validation. Not part of Prompter. */ readProviderPicker(options: ProviderPickerRequest): Promise; readText(options: { message: string; placeholder?: string; defaultValue?: string; mask?: boolean; validate?: (value: string) => string | undefined; notices?: readonly SelectNotice[]; }): Promise; readAcknowledge(options: { message: string; lines: readonly string[]; }): Promise; /** * Presents an inert context row and a separate action menu beside the live * flow indicator. Returns the choice plus a `close()` that dismisses the menu * when a concurrent wait resolves first. Used by the Slack install wait for * "Try again" / "Cancel": the poll keeps running while the prompt is up, and * whichever settles first wins. */ readChoice(options: ChannelSetupChoiceOptions): ChannelSetupChoice; setStatus(status: string | undefined): void; renderLine(text: string, tone: "info" | "success" | "warning" | "error"): void; replaceContent?(content?: { headline: string; facts: readonly { label: string; value: string; }[]; }): void; renderOutput(text: string): void; /** Temporarily restores the terminal while a child process inherits stdio. */ withInheritedStdio(task: () => Promise): Promise; /** Gives a setup subprocess exclusive terminal and development-host ownership. */ withExclusiveTerminal?(task: () => Promise): Promise; /** * Arms a key trap for the flow's working state — the status indicator between * questions, where no prompt is consuming keys. Ctrl-C or Esc resolves the * promise so the command can abandon an in-flight flow (e.g. a parked * `vercel connect create` browser OAuth). Open questions own their keys; the * trap covers only the gaps. `interruptible: false` still consumes and * discards input but does not cancel non-abortable work. `dispose` releases * the trap; the promise then never resolves. */ waitForInterrupt(options?: { interruptible?: boolean; }): { promise: Promise; dispose(): void; }; } export type SetupFlowPrompterRenderer = Pick; export {};