/** * Host adapter — pure answer assembly (spec §10; no PI runtime, no fs, no network). * * The single typed core both render paths feed. A renderer captures a {@link RawSelection} per * question (widget-shaped); {@link assembleAnswers} turns the batch into the structured answers * object keyed by `question.key` (dotted for nested sections), which the engine then maps back onto * the target schema via `answersToOutput`/`validateAnswers`. * * The only PI reference here is a *type* — the run mode for the capability gate — a type-only import, * fully erased at runtime, so this module stays offline-testable. */ import type { ExtensionContext } from "@earendil-works/pi-coding-agent"; import type { Question, Questionnaire, QuestionOption } from "../flow/questionnaire.ts"; /** PI run mode (`"tui" | "rpc" | "json" | "print"`), derived from the exported context type. */ export type ExtensionMode = ExtensionContext["mode"]; /** Sentinel option value meaning "the user took the implicit Other choice and typed free text". */ export declare const OTHER_VALUE = "__other__"; /** Display label for the implicit "Other" choice appended to a single-choice question. */ export declare const OTHER_LABEL = "Other\u2026"; /** Display label for the "finish selecting" entry of the rich multi-select loop. */ export declare const DONE_LABEL = "Done"; /** * A renderer's raw capture for one question, before typing. Both render paths (the rich `ctx.ui.custom` * form and the native-dialog fallback) produce this shape; {@link assembleAnswers} types it. */ export interface RawSelection { /** single: the picked option value, or {@link OTHER_VALUE} when the implicit "Other" choice was taken. */ readonly option?: string; /** multi: the picked option values. */ readonly options?: readonly string[]; /** text/chat: the entered string; also the free text when `option === OTHER_VALUE`. */ readonly text?: string; } /** * Assemble structured answers keyed by `question.key` from a renderer's raw per-question selections * (pure). single → the chosen value, or the "Other" free text; multi → an array; text/chat → a string. * A question with no capture collapses to the empty value of its shape (`""` / `[]`). */ export declare function assembleAnswers(questionnaire: Questionnaire, raw: Readonly>): Record; /** A question's options ordered for display: recommended first (stable), original order otherwise. */ export declare function orderedOptions(question: Question): QuestionOption[]; /** A question's prompt title: `"
"` when the question belongs to a section. */ export declare function questionTitle(question: Question): string; /** A single option's display label: `label` + `(recommended)` marker + ` — description` when present. */ export declare function optionLabel(option: QuestionOption): string; /** * Capability gate (pure): render the rich `ctx.ui.custom` form only when a real terminal TUI is present. * Everything else (RPC / JSON / print) falls back to native per-question dialogs — which also work over * RPC, where `custom` cannot render. */ export declare function useRichForm(mode: ExtensionMode, hasUI: boolean): boolean; /** * The two UI primitives single/text collection needs — a selection list and a free-text input. Both * render paths implement this seam over their own widgets (native dialogs vs `ctx.ui.custom`), so the * "Other"-handling business logic below lives in exactly one place. `undefined` means the user dismissed. */ export interface Picker { pick(title: string, labels: string[]): Promise; text(title: string, placeholder?: string): Promise; } /** * Single-choice collection (spec §10): present ordered options (recommended first) plus an implicit * "Other → free text" entry, then map the pick back to its option value. Pure over the {@link Picker} * seam; returns a {@link RawSelection}, or `undefined` when the user dismisses. */ export declare function collectSingle(picker: Picker, question: Question): Promise; /** * Text/chat collection (spec §10): a single free-text input. Pure over the {@link Picker} seam; returns * a {@link RawSelection}, or `undefined` when the user dismisses. */ export declare function collectText(picker: Picker, question: Question): Promise; /** * Drive a whole questionnaire over the {@link Picker} seam and assemble the structured answers keyed by * `question.key` — the one collection loop BOTH render paths run (native dialogs and the rich TUI form), * so "ask every question in order, stop on dismissal, assemble once" is defined exactly once rather than * re-implemented per widget set. Returns `undefined` as soon as the user dismisses any question: dismiss * ≠ cancel, so the caller keeps the run blocked (spec §10.2). * * Multi-choice is the one genuinely widget-shaped question kind (a confirm per option vs a check/uncheck * selector loop), so it stays with the render path and arrives here as `collectMulti`. */ export declare function collectQuestionnaire(questionnaire: Questionnaire, picker: Picker, collectMulti: (question: Question) => Promise): Promise | undefined>; //# sourceMappingURL=answer-assembly.d.ts.map