import type { WizardPrompter, SelectOption, MultiSelectOption, ProgressHandle, } from './interface.js'; export type AnswerValue = string | boolean | string[]; export class HeadlessPrompter implements WizardPrompter { private answers: Map; private logs: string[] = []; constructor(answers: Record = {}) { this.answers = new Map(Object.entries(answers)); } intro(message: string): void { this.logs.push(`[intro] ${message}`); } outro(message: string): void { this.logs.push(`[outro] ${message}`); } note(message: string, title?: string): void { this.logs.push(`[note] ${title ?? ''}: ${message}`); } log(message: string): void { this.logs.push(`[log] ${message}`); } warn(message: string): void { this.logs.push(`[warn] ${message}`); } async text(opts: { message: string; placeholder?: string; defaultValue?: string; validate?: (value: string) => string | void; }): Promise { const answer = this.answers.get(opts.message); const value = typeof answer === 'string' ? answer : opts.defaultValue !== undefined ? opts.defaultValue : undefined; if (value === undefined) { throw new Error(`HeadlessPrompter: no answer for "${opts.message}"`); } if (opts.validate) { const error = opts.validate(value); if (error) throw new Error(`HeadlessPrompter validation failed for "${opts.message}": ${error}`); } return value; } async confirm(opts: { message: string; initialValue?: boolean }): Promise { const answer = this.answers.get(opts.message); if (typeof answer === 'boolean') return answer; return opts.initialValue ?? true; } async select(opts: { message: string; options: SelectOption[]; initialValue?: T; }): Promise { const answer = this.answers.get(opts.message); if (answer !== undefined) { // Find matching option by value string comparison const match = opts.options.find((o) => String(o.value) === String(answer)); if (match) return match.value; } if (opts.initialValue !== undefined) return opts.initialValue; if (opts.options.length === 0) { throw new Error(`HeadlessPrompter: no options for "${opts.message}"`); } const first = opts.options[0]; if (first === undefined) { throw new Error(`HeadlessPrompter: no options for "${opts.message}"`); } return first.value; } async multiselect(opts: { message: string; options: MultiSelectOption[]; required?: boolean; }): Promise { const answer = this.answers.get(opts.message); if (Array.isArray(answer)) { return opts.options .filter((o) => (answer as string[]).includes(String(o.value))) .map((o) => o.value); } return opts.options.filter((o) => o.selected).map((o) => o.value); } async groupMultiselect(opts: { message: string; options: Record[]>; required?: boolean; }): Promise { const answer = this.answers.get(opts.message); if (Array.isArray(answer)) { const all = Object.values(opts.options).flat(); return all.filter((o) => (answer as string[]).includes(String(o.value))).map((o) => o.value); } return Object.values(opts.options) .flat() .filter((o) => o.selected) .map((o) => o.value); } spinner(): ProgressHandle { return { update(_message: string) {}, stop(_message?: string) {}, }; } separator(): void {} getLogs(): string[] { return [...this.logs]; } }