/**
* The question model the `Screen` runs.
*
* A view describes a question as data; the `Screen` adds it to the live scene,
* reads keys, repaints, and appends the answer when it settles. Nothing here
* paints or reads input, so a reducer and a view are ordinary pure functions
* that a table test can drive.
*
* `Confirm` answers with one lettered key, `Choose` with one option from a list
* that opens under the question, `Pick` with several from a list that filters
* as a person types, and `Input` with one typed line.
*/
import type { SuggestedAction } from "@agentxm/registry-protocol/unstable/suggested-action";
import type * as Result from "effect/Result";
import type * as Array from "effect/Array";
import { type AppError } from "../../app-error/index.js";
import type { Doc, PromptNode, Text } from "../doc.js";
import type { SceneFacts } from "../scene.js";
import { isQuitKey, isSubmitKey, type InteractionKey } from "../interaction.js";
export type AskKey = InteractionKey;
export { isQuitKey, isSubmitKey };
interface AskBase {
readonly question: Text;
readonly note?: Text;
readonly label?: string;
}
/** One lettered choice: the key that picks it, the word that says what it means. */
export interface ConfirmChoice {
readonly key: string;
readonly word: string;
readonly value: A;
/** Whether selecting this choice leaves an answer in the transcript. */
readonly transcript?: boolean;
}
export interface ConfirmAsk extends AskBase {
readonly _tag: "Confirm";
/** The choices, the first of which is the default `enter` takes. */
readonly choices: Array.NonEmptyReadonlyArray>;
}
/** One option of a `Choose`: what it is called, and the facts that tell it apart. */
export interface ChooseOption {
readonly title: string;
/** Facts shown beside the title, which the painter joins with its separator. */
readonly details?: ReadonlyArray;
readonly value: A;
/** The option the question opens on; the first option when none is. */
readonly selected?: true;
}
export interface ChooseAsk extends AskBase {
readonly _tag: "Choose";
readonly options: Array.NonEmptyReadonlyArray>;
}
/**
* One option of a `Pick` as the list shows it: what it is called, the facts
* that tell it apart, and the group it is listed under.
*/
export interface PickEntry {
readonly title: string;
/** Facts shown beside the title, which the painter joins with its separator. */
readonly details?: ReadonlyArray;
/**
* The group the option is listed under. Options that name a group sit one
* step in beneath its header, and groups keep the order they first appear in.
*/
readonly group?: string;
/** Whether the option is picked when the question opens. */
readonly selected?: true;
}
/** One option of a `Pick` and the value picking it contributes to the answer. */
export interface PickOption extends PickEntry {
readonly value: V;
}
/** What one picked option is called, and what several are. */
export interface PickNoun {
readonly one: string;
readonly other: string;
}
export interface PickAsk extends AskBase {
readonly _tag: "Pick";
readonly options: ReadonlyArray;
/** What the options are, for the count and for a bound that is not met. */
readonly noun: PickNoun;
/** The fewest options `enter` accepts; none by default. */
readonly min?: number;
/** The most options that may be picked; any number by default. */
readonly max?: number;
/** The answer the picked options make, given their positions in `options`. */
readonly answer: (picked: ReadonlyArray) => A;
}
/**
* A `Pick` whose answer is the values of the options picked, in the order the
* options are listed.
*/
export declare const pickAsk: (spec: Omit>, "_tag" | "options" | "answer"> & {
readonly options: ReadonlyArray>;
}) => PickAsk>;
export interface InputAsk extends AskBase {
readonly _tag: "Input";
/** An example answer, shown dim until something is typed. */
readonly placeholder?: string;
/**
* What the typed line answers, or in one line what is wrong with it. It is
* pure, so a line that fails stays open with the reason beneath it.
*/
readonly validate: (raw: string) => Result.Result;
}
/** A question a view describes as data and the `Screen` runs. */
export type Ask = ConfirmAsk | ChooseAsk | PickAsk | InputAsk;
/** The shared prompt head; each kind supplies only its kind-specific body. */
export declare const promptNode: (ask: AskBase, body: Omit) => PromptNode;
/** The common transcript line left by an answered question. */
export declare const answerDoc: (ask: AskBase, value: Text) => Doc;
/** The text a key typed, or `undefined` for a key that typed none. */
export declare const typedText: (key: AskKey) => string | undefined;
/**
* What one key did to a running question, whatever its kind: the state to
* show next, the value it settled on with the one transcript line it leaves,
* or a cancellation.
*/
export type AskAction = {
readonly _tag: "Next";
readonly state: S;
} | {
readonly _tag: "Submit";
readonly value: A;
readonly answer: Doc;
} | {
readonly _tag: "Cancel";
};
/** A kind reducer's common control flow before its submission becomes an answer. */
export type AskReducerAction = {
readonly _tag: "Next";
readonly state: S;
} | {
readonly _tag: "Submit";
readonly submission: Submission;
} | {
readonly _tag: "Cancel";
};
/**
* One kind of question as the `Screen` runs it: where it starts, what a key
* does to it, and what the live region shows in the space it is given. Each
* kind keeps its own state type behind this, so one loop runs them all.
*/
export interface AskKind {
readonly initial: S;
readonly reduce: (state: S, key: AskKey) => AskAction;
readonly view: (state: S, facts: SceneFacts) => Doc;
}
/** Why a prompt would open, and how to get past it where one may not. */
export interface InteractiveGuard {
readonly message?: string;
readonly guidance?: string;
readonly suggestions?: ReadonlyArray;
}
/**
* The failure a guarded prompt raises where it may not open: a usage error
* naming what was needed and how to supply it without answering a question.
*/
export declare const promptRequired: (message: string, guard?: InteractiveGuard) => AppError;
/** The ordinary yes/no choices with the safe default first. */
export declare const yesNo: (defaultsToYes: boolean) => Array.NonEmptyReadonlyArray>;
//# sourceMappingURL=ask.d.ts.map